aboutsummaryrefslogtreecommitdiff
path: root/aezref/src
diff options
context:
space:
mode:
Diffstat (limited to 'aezref/src')
-rw-r--r--aezref/src/lib.rs155
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");
+ }
+}