Commit 702319d1 authored by Ming-Wei Shih's avatar Ming-Wei Shih
Browse files

Support AES wrap and wrap_pad in Cipher

parent 28b3925a
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -27,6 +27,9 @@ pub const EVP_PKEY_POLY1305: c_int = NID_poly1305;
#[cfg(ossl110)]
pub const EVP_PKEY_HKDF: c_int = NID_hkdf;

#[cfg(ossl102)]
pub const EVP_CIPHER_CTX_FLAG_WRAP_ALLOW: c_int = 0x1;

pub const EVP_CTRL_GCM_SET_IVLEN: c_int = 0x9;
pub const EVP_CTRL_GCM_GET_TAG: c_int = 0x10;
pub const EVP_CTRL_GCM_SET_TAG: c_int = 0x11;
+13 −0
Original line number Diff line number Diff line
@@ -283,6 +283,7 @@ extern "C" {
        ptr: *mut c_void,
    ) -> c_int;
    pub fn EVP_CIPHER_CTX_rand_key(ctx: *mut EVP_CIPHER_CTX, key: *mut c_uchar) -> c_int;
    pub fn EVP_CIPHER_CTX_set_flags(ctx: *mut EVP_CIPHER_CTX, flags: c_int);

    pub fn EVP_md_null() -> *const EVP_MD;
    pub fn EVP_md5() -> *const EVP_MD;
@@ -329,6 +330,10 @@ extern "C" {
    pub fn EVP_aes_128_ofb() -> *const EVP_CIPHER;
    #[cfg(ossl110)]
    pub fn EVP_aes_128_ocb() -> *const EVP_CIPHER;
    #[cfg(ossl102)]
    pub fn EVP_aes_128_wrap() -> *const EVP_CIPHER;
    #[cfg(ossl110)]
    pub fn EVP_aes_128_wrap_pad() -> *const EVP_CIPHER;
    pub fn EVP_aes_192_ecb() -> *const EVP_CIPHER;
    pub fn EVP_aes_192_cbc() -> *const EVP_CIPHER;
    pub fn EVP_aes_192_cfb1() -> *const EVP_CIPHER;
@@ -340,6 +345,10 @@ extern "C" {
    pub fn EVP_aes_192_ofb() -> *const EVP_CIPHER;
    #[cfg(ossl110)]
    pub fn EVP_aes_192_ocb() -> *const EVP_CIPHER;
    #[cfg(ossl102)]
    pub fn EVP_aes_192_wrap() -> *const EVP_CIPHER;
    #[cfg(ossl110)]
    pub fn EVP_aes_192_wrap_pad() -> *const EVP_CIPHER;
    pub fn EVP_aes_256_ecb() -> *const EVP_CIPHER;
    pub fn EVP_aes_256_cbc() -> *const EVP_CIPHER;
    pub fn EVP_aes_256_cfb1() -> *const EVP_CIPHER;
@@ -352,6 +361,10 @@ extern "C" {
    pub fn EVP_aes_256_ofb() -> *const EVP_CIPHER;
    #[cfg(ossl110)]
    pub fn EVP_aes_256_ocb() -> *const EVP_CIPHER;
    #[cfg(ossl102)]
    pub fn EVP_aes_256_wrap() -> *const EVP_CIPHER;
    #[cfg(ossl110)]
    pub fn EVP_aes_256_wrap_pad() -> *const EVP_CIPHER;
    #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_CHACHA")))]
    pub fn EVP_chacha20() -> *const EVP_CIPHER;
    #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_CHACHA")))]
+36 −0
Original line number Diff line number Diff line
@@ -191,6 +191,18 @@ impl Cipher {
        unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_ocb() as *mut _) }
    }

    /// Requires OpenSSL 1.0.2 or newer.
    #[cfg(ossl102)]
    pub fn aes_128_wrap() -> &'static CipherRef {
        unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_wrap() as *mut _) }
    }

    /// Requires OpenSSL 1.1.0 or newer.
    #[cfg(ossl110)]
    pub fn aes_128_wrap_pad() -> &'static CipherRef {
        unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_wrap_pad() as *mut _) }
    }

    pub fn aes_192_ecb() -> &'static CipherRef {
        unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ecb() as *mut _) }
    }
@@ -236,6 +248,18 @@ impl Cipher {
        unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ocb() as *mut _) }
    }

    /// Requires OpenSSL 1.0.2 or newer.
    #[cfg(ossl102)]
    pub fn aes_192_wrap() -> &'static CipherRef {
        unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_wrap() as *mut _) }
    }

    /// Requires OpenSSL 1.1.0 or newer.
    #[cfg(ossl110)]
    pub fn aes_192_wrap_pad() -> &'static CipherRef {
        unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_wrap_pad() as *mut _) }
    }

    pub fn aes_256_ecb() -> &'static CipherRef {
        unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ecb() as *mut _) }
    }
@@ -281,6 +305,18 @@ impl Cipher {
        unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ocb() as *mut _) }
    }

    /// Requires OpenSSL 1.0.2 or newer.
    #[cfg(ossl102)]
    pub fn aes_256_wrap() -> &'static CipherRef {
        unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_wrap() as *mut _) }
    }

    /// Requires OpenSSL 1.1.0 or newer.
    #[cfg(ossl110)]
    pub fn aes_256_wrap_pad() -> &'static CipherRef {
        unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_wrap_pad() as *mut _) }
    }

    #[cfg(not(osslconf = "OPENSSL_NO_BF"))]
    pub fn bf_cbc() -> &'static CipherRef {
        unsafe { CipherRef::from_ptr(ffi::EVP_bf_cbc() as *mut _) }
+180 −0
Original line number Diff line number Diff line
@@ -55,6 +55,8 @@ use crate::error::ErrorStack;
#[cfg(not(boringssl))]
use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef};
use crate::{cvt, cvt_p};
#[cfg(ossl102)]
use bitflags::bitflags;
use cfg_if::cfg_if;
use foreign_types::{ForeignType, ForeignTypeRef};
use libc::{c_int, c_uchar};
@@ -80,6 +82,15 @@ foreign_type_and_impl_send_sync! {
    pub struct CipherCtxRef;
}

#[cfg(ossl102)]
bitflags! {
    /// Flags for `EVP_CIPHER_CTX`.
    pub struct CipherCtxFlags : c_int {
        /// The flag used to opt into AES key wrap ciphers.
        const FLAG_WRAP_ALLOW = ffi::EVP_CIPHER_CTX_FLAG_WRAP_ALLOW;
    }
}

impl CipherCtx {
    /// Creates a new context.
    #[corresponds(EVP_CIPHER_CTX_new)]
@@ -509,6 +520,17 @@ impl CipherCtxRef {
        Ok(())
    }

    /// Set ctx flags.
    ///
    /// This function is currently used to enable AES key wrap feature supported by OpenSSL 1.0.2 or newer.
    #[corresponds(EVP_CIPHER_CTX_set_flags)]
    #[cfg(ossl102)]
    pub fn set_flags(&mut self, flags: CipherCtxFlags) {
        unsafe {
            ffi::EVP_CIPHER_CTX_set_flags(self.as_ptr(), flags.bits());
        }
    }

    /// Writes data into the context.
    ///
    /// Providing no output buffer will cause the input to be considered additional authenticated data (AAD).
@@ -915,4 +937,162 @@ mod test {
        ctx.cipher_update(&vec![0; block_size + 1], Some(&mut vec![0; block_size - 1]))
            .unwrap();
    }

    #[cfg(ossl102)]
    fn cipher_wrap_test(cipher: &CipherRef, pt: &str, ct: &str, key: &str, iv: Option<&str>) {
        let pt = hex::decode(pt).unwrap();
        let key = hex::decode(key).unwrap();
        let expected = hex::decode(ct).unwrap();
        let iv = iv.map(|v| hex::decode(v).unwrap());
        let padding = 8 - pt.len() % 8;
        let mut computed = vec![0; pt.len() + padding + cipher.block_size() * 2];
        let mut ctx = CipherCtx::new().unwrap();

        ctx.set_flags(CipherCtxFlags::FLAG_WRAP_ALLOW);
        ctx.encrypt_init(Some(cipher), Some(&key), iv.as_deref())
            .unwrap();

        let count = ctx.cipher_update(&pt, Some(&mut computed)).unwrap();
        let rest = ctx.cipher_final(&mut computed[count..]).unwrap();
        computed.truncate(count + rest);

        if computed != expected {
            println!("Computed: {}", hex::encode(&computed));
            println!("Expected: {}", hex::encode(&expected));
            if computed.len() != expected.len() {
                println!(
                    "Lengths differ: {} in computed vs {} expected",
                    computed.len(),
                    expected.len()
                );
            }
            panic!("test failure");
        }
    }

    #[test]
    #[cfg(ossl102)]
    fn test_aes128_wrap() {
        let pt = "00112233445566778899aabbccddeeff";
        let ct = "7940ff694448b5bb5139c959a4896832e55d69aa04daa27e";
        let key = "2b7e151628aed2a6abf7158809cf4f3c";
        let iv = "0001020304050607";

        cipher_wrap_test(Cipher::aes_128_wrap(), pt, ct, key, Some(iv));
    }

    #[test]
    #[cfg(ossl102)]
    fn test_aes128_wrap_default_iv() {
        let pt = "00112233445566778899aabbccddeeff";
        let ct = "38f1215f0212526f8a70b51955b9fbdc9fe3041d9832306e";
        let key = "2b7e151628aed2a6abf7158809cf4f3c";

        cipher_wrap_test(Cipher::aes_128_wrap(), pt, ct, key, None);
    }

    #[test]
    #[cfg(ossl110)]
    fn test_aes128_wrap_pad() {
        let pt = "00112233445566778899aabbccddee";
        let ct = "f13998f5ab32ef82a1bdbcbe585e1d837385b529572a1e1b";
        let key = "2b7e151628aed2a6abf7158809cf4f3c";
        let iv = "00010203";

        cipher_wrap_test(Cipher::aes_128_wrap_pad(), pt, ct, key, Some(iv));
    }

    #[test]
    #[cfg(ossl110)]
    fn test_aes128_wrap_pad_default_iv() {
        let pt = "00112233445566778899aabbccddee";
        let ct = "3a501085fb8cf66f4186b7df851914d471ed823411598add";
        let key = "2b7e151628aed2a6abf7158809cf4f3c";

        cipher_wrap_test(Cipher::aes_128_wrap_pad(), pt, ct, key, None);
    }

    #[test]
    #[cfg(ossl102)]
    fn test_aes192_wrap() {
        let pt = "9f6dee187d35302116aecbfd059657efd9f7589c4b5e7f5b";
        let ct = "83b89142dfeeb4871e078bfb81134d33e23fedc19b03a1cf689973d3831b6813";
        let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b";
        let iv = "0001020304050607";

        cipher_wrap_test(Cipher::aes_192_wrap(), pt, ct, key, Some(iv));
    }

    #[test]
    #[cfg(ossl102)]
    fn test_aes192_wrap_default_iv() {
        let pt = "9f6dee187d35302116aecbfd059657efd9f7589c4b5e7f5b";
        let ct = "c02c2cf11505d3e4851030d5534cbf5a1d7eca7ba8839adbf239756daf1b43e6";
        let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b";

        cipher_wrap_test(Cipher::aes_192_wrap(), pt, ct, key, None);
    }

    #[test]
    #[cfg(ossl110)]
    fn test_aes192_wrap_pad() {
        let pt = "00112233445566778899aabbccddee";
        let ct = "b4f6bb167ef7caf061a74da82b36ad038ca057ab51e98d3a";
        let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b";
        let iv = "00010203";

        cipher_wrap_test(Cipher::aes_192_wrap_pad(), pt, ct, key, Some(iv));
    }

    #[test]
    #[cfg(ossl110)]
    fn test_aes192_wrap_pad_default_iv() {
        let pt = "00112233445566778899aabbccddee";
        let ct = "b2c37a28cc602753a7c944a4c2555a2df9c98b2eded5312e";
        let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b";

        cipher_wrap_test(Cipher::aes_192_wrap_pad(), pt, ct, key, None);
    }

    #[test]
    #[cfg(ossl102)]
    fn test_aes256_wrap() {
        let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51";
        let ct = "cc05da2a7f56f7dd0c144231f90bce58648fa20a8278f5a6b7d13bba6aa57a33229d4333866b7fd6";
        let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";
        let iv = "0001020304050607";

        cipher_wrap_test(Cipher::aes_256_wrap(), pt, ct, key, Some(iv));
    }

    #[test]
    #[cfg(ossl102)]
    fn test_aes256_wrap_default_iv() {
        let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51";
        let ct = "0b24f068b50e52bc6987868411c36e1b03900866ed12af81eb87cef70a8d1911731c1d7abf789d88";
        let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";

        cipher_wrap_test(Cipher::aes_256_wrap(), pt, ct, key, None);
    }

    #[test]
    #[cfg(ossl110)]
    fn test_aes256_wrap_pad() {
        let pt = "00112233445566778899aabbccddee";
        let ct = "91594e044ccc06130d60e6c84a996aa4f96a9faff8c5f6e7";
        let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";
        let iv = "00010203";

        cipher_wrap_test(Cipher::aes_256_wrap_pad(), pt, ct, key, Some(iv));
    }

    #[test]
    #[cfg(ossl110)]
    fn test_aes256_wrap_pad_default_iv() {
        let pt = "00112233445566778899aabbccddee";
        let ct = "dc3c166a854afd68aea624a4272693554bf2e4fcbae602cd";
        let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";

        cipher_wrap_test(Cipher::aes_256_wrap_pad(), pt, ct, key, None);
    }
}