use super::bind::{
EverCrypt_Chacha20Poly1305_aead_decrypt, EverCrypt_Chacha20Poly1305_aead_encrypt,
};
const SIZE_KEY: usize = 32;
const SIZE_TAG: usize = 16;
const SIZE_NONCE: usize = 24;
#[must_use = "authentication failure must be handled"]
pub fn open(
key: &[u8; SIZE_KEY],
nonce: &[u8; SIZE_NONCE],
ad: &[u8],
pt: &mut [u8],
ct: &[u8],
tag: &[u8; SIZE_TAG],
) -> Result<(), ()> {
assert!(ct.len() <= pt.len());
assert!(ct.len() <= u32::max_value() as usize);
assert!(ad.len() <= u32::max_value() as usize);
let ok = unsafe {
EverCrypt_Chacha20Poly1305_aead_decrypt(
key.as_ptr(),
nonce.as_ptr(),
ad.len() as cty::uint32_t,
ad.as_ptr(),
ct.len() as cty::uint32_t,
pt.as_mut_ptr(),
ct.as_ptr(),
tag.as_ptr(),
)
};
if ok == 0 {
Ok(())
} else {
Err(())
}
}
#[must_use = "authentication failure must be handled"]
pub fn open_inplace(
key: &[u8; SIZE_KEY],
nonce: &[u8],
ad: &[u8],
msg: &mut [u8],
tag: &[u8; SIZE_TAG],
) -> Result<(), ()> {
assert!(ad.len() <= u32::max_value() as usize);
assert!(msg.len() <= u32::max_value() as usize);
assert_eq!(nonce.len(), 24, "nonce must be 24 bytes long");
assert_eq!(tag.len(), 16, "tag buffer must be 16 bytes");
let ok = unsafe {
EverCrypt_Chacha20Poly1305_aead_decrypt(
key.as_ptr(),
nonce.as_ptr(),
ad.len() as cty::uint32_t,
ad.as_ptr(),
msg.len() as cty::uint32_t,
msg.as_mut_ptr(),
msg.as_ptr(),
tag.as_ptr(),
)
};
if ok == 0 {
Ok(())
} else {
Err(())
}
}
pub fn seal(
key: &[u8; SIZE_KEY],
nonce: &[u8; SIZE_NONCE],
ad: &[u8],
pt: &[u8],
ct: &mut [u8],
tag: &mut [u8; SIZE_TAG],
) {
assert!(ct.len() >= pt.len());
assert!(pt.len() <= u32::max_value() as usize);
assert!(ad.len() <= u32::max_value() as usize);
unsafe {
EverCrypt_Chacha20Poly1305_aead_encrypt(
key.as_ptr(),
nonce.as_ptr(),
ad.len() as cty::uint32_t,
ad.as_ptr(),
pt.len() as cty::uint32_t,
pt.as_ptr(),
ct.as_mut_ptr(),
tag.as_mut_ptr(),
);
}
}
pub fn seal_inplace(
key: &[u8; SIZE_KEY],
nonce: &[u8; SIZE_NONCE],
ad: &[u8],
msg: &mut [u8],
tag: &mut [u8; SIZE_TAG],
) {
assert!(ad.len() <= u32::max_value() as usize);
assert!(msg.len() <= u32::max_value() as usize);
assert_eq!(nonce.len(), 24, "nonce must be 24 bytes long");
assert_eq!(tag.len(), 16, "tag buffer must be 16 bytes");
unsafe {
EverCrypt_Chacha20Poly1305_aead_encrypt(
key.as_ptr(),
nonce.as_ptr(),
ad.len() as cty::uint32_t,
ad.as_ptr(),
msg.len() as cty::uint32_t,
msg.as_ptr(),
msg.as_mut_ptr(),
tag.as_mut_ptr(),
);
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::convert::TryInto;
use proptest::prelude::*;
use std::vec::Vec;
#[cfg(feature = "nightly")]
use test::Bencher;
proptest! {
#[test]
fn seal_test(pt: Vec<u8>, ad: Vec<u8>, key: [u8; 32], nonce: [u8; 24]) {
let mut ct : Vec<u8> = vec![0; pt.len()];
let mut ptt : Vec<u8> = vec![0; pt.len()];
let mut tag : [u8; 16] = [0; 16];
seal(&key, &nonce, &ad[..], &pt, &mut ct, &mut tag);
open(&key, &nonce, &ad[..], &mut ptt, &ct, &tag).unwrap();
assert_eq!(&ptt[..], &pt[..], "open \\circ seal != id");
}
#[test]
fn seal_test_inplace(pt: Vec<u8>, ad: Vec<u8>, key: [u8; 32], nonce: [u8; 24]) {
let mut ptt : Vec<u8> = pt.clone();
ptt.extend(&[0u8; 16]);
let (pb, tb) = ptt.split_at_mut(pt.len());
seal_inplace(&key, &nonce, &ad[..], pb, tb.try_into().unwrap());
open_inplace(&key, &nonce, &ad[..], pb, (&*tb).try_into().unwrap()).unwrap();
assert_eq!(&pb[..], &pt[..], "open_inplace \\circ seal_inplace != id");
}
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_seal(b: &mut Bencher) {
let key: [u8; 32] = [1; 32];
let nonce: [u8; 24] = [0; 24];
let ad: [u8; 0] = [];
let mut tag: [u8; 16] = [0; 16];
let mut pt: Vec<u8> = vec![0; 1024 * 1024];
b.iter(|| {
seal_inplace(
&key,
&nonce,
&ad[..],
&mut pt[..],
(&mut tag[..]).try_into().unwrap(),
);
});
}
}