diff options
Diffstat (limited to 'aezref/src/lib.rs')
-rw-r--r-- | aezref/src/lib.rs | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/aezref/src/lib.rs b/aezref/src/lib.rs new file mode 100644 index 0000000..8fc902c --- /dev/null +++ b/aezref/src/lib.rs @@ -0,0 +1,155 @@ +//! Bindings to the reference (slow, unsafe) implementation of AEZ. +//! +//! **Warning**: +//! +//! > This version is slow and susceptible to side-channel attacks. +//! > Do not use for any purpose other than to understand AEZ. +//! +//! We only use it to compare outputs between `zears` and `aezref`. +use std::ffi::*; + +unsafe extern "C" { + fn Decrypt( + key: *const c_uchar, + keybytes: c_uint, + nonce: *const c_uchar, + noncebytes: c_uint, + ad: *const *const c_uchar, + adbytes: *const c_uint, + veclen: c_uint, + abytes: c_uint, + ciphertext: *const c_uchar, + cipherbytes: c_uint, + message: *mut c_uchar, + ) -> c_int; + + fn Encrypt( + key: *const c_uchar, + keybytes: c_uint, + nonce: *const c_uchar, + noncebytes: c_uint, + ad: *const *const c_uchar, + adbytes: *const c_uint, + veclen: c_uint, + abytes: c_uint, + message: *const c_uchar, + messagebytes: c_uint, + ciphertext: *mut c_uchar, + ); +} + +/// Encrypt the given `message` using the given `key`, `nonce` and associated data items `ad`. +/// +/// The ciphertext will be written to `ciphertext`. +/// +/// The number of authentication bytes will be inferred from the length difference between +/// `message` and `ciphertext` +/// +/// This function will panic if +/// +/// * any of the given byte strings is longer than [`c_uint::MAX`] (usually 2^32 - 1) +/// * the ciphertext buffer is smaller than the message buffer +pub fn encrypt(key: &[u8], nonce: &[u8], ad: &[&[u8]], message: &[u8], ciphertext: &mut [u8]) { + assert!(ciphertext.len() >= message.len()); + let adlens: Vec<c_uint> = ad + .into_iter() + .map(|x| x.len().try_into().expect("associated data item too long")) + .collect(); + let ad = ad.into_iter().map(|x| x.as_ptr()).collect::<Vec<_>>(); + let abytes = ciphertext.len() - message.len(); + unsafe { + Encrypt( + key.as_ptr(), + key.len().try_into().expect("key too long"), + nonce.as_ptr(), + nonce.len().try_into().expect("nonce too long"), + ad.as_ptr(), + adlens.as_ptr(), + ad.len().try_into().expect("too many associated data items"), + abytes.try_into().expect("too many authentication bytes"), + message.as_ptr(), + message.len().try_into().expect("message too long"), + ciphertext.as_mut_ptr(), + ) + } +} + +/// Decrypt the given `ciphertext` using the given `key`, `nonce` and associated data items `ad`. +/// +/// The plaintext message will be written to `message`. +/// +/// The number of authentication bytes will be inferred from the length difference between +/// `message` and `ciphertext`. +/// +/// If the authentication bytes do not match the expected bytes (i.e. the ciphertext has been +/// modified, or the wrong key/nonce/ad is provided), `Err(())` is returned. Otherwise, `Ok(())` is +/// returned. +/// +/// This function will panic if +/// +/// * any of the given byte strings is longer than [`c_uint::MAX`] (usually 2^32 - 1) +/// * the ciphertext buffer is smaller than the message buffer +pub fn decrypt( + key: &[u8], + nonce: &[u8], + ad: &[&[u8]], + ciphertext: &[u8], + message: &mut [u8], +) -> Result<(), ()> { + assert!(ciphertext.len() >= message.len()); + let adlens: Vec<c_uint> = ad + .into_iter() + .map(|x| x.len().try_into().expect("associated data item too long")) + .collect(); + let ad = ad.into_iter().map(|x| x.as_ptr()).collect::<Vec<_>>(); + let abytes = ciphertext.len() - message.len(); + let result = unsafe { + Decrypt( + key.as_ptr(), + key.len().try_into().expect("key too long"), + nonce.as_ptr(), + nonce.len().try_into().expect("nonce too long"), + ad.as_ptr(), + adlens.as_ptr(), + ad.len().try_into().expect("too many associated data items"), + abytes.try_into().expect("too many authentication bytes"), + ciphertext.as_ptr(), + ciphertext.len().try_into().expect("message too long"), + message.as_mut_ptr(), + ) + }; + match result { + 0 => Ok(()), + -1 => Err(()), + _ => panic!("unexpected return from Decrypt"), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let mut ciphertext = [0u8; 10]; + encrypt( + b"foo", + b"bar", + &[b"ad 1", b"ad two"], + b"hey", + &mut ciphertext, + ); + + let mut message = [0u8; 3]; + decrypt( + b"foo", + b"bar", + &[b"ad 1", b"ad two"], + &ciphertext, + &mut message, + ) + .unwrap(); + + assert_eq!(&message, b"hey"); + } +} |