Commit 963e3994 authored by Henrik Böving's avatar Henrik Böving
Browse files

Add support for AES-OCB mode

parent e446d819
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -21,6 +21,12 @@ 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;

// Keeping above for backwards compatability
pub const EVP_CTRL_AEAD_SET_IVLEN: c_int = EVP_CTRL_GCM_SET_IVLEN;
pub const EVP_CTRL_AEAD_GET_TAG: c_int = EVP_CTRL_GCM_GET_TAG;
pub const EVP_CTRL_AEAD_SET_TAG: c_int = EVP_CTRL_GCM_SET_TAG;


pub unsafe fn EVP_get_digestbynid(type_: c_int) -> *const EVP_MD {
    EVP_get_digestbyname(OBJ_nid2sn(type_))
}
@@ -275,6 +281,7 @@ extern "C" {
    pub fn EVP_aes_128_gcm() -> *const EVP_CIPHER;
    pub fn EVP_aes_128_xts() -> *const EVP_CIPHER;
    pub fn EVP_aes_128_ofb() -> *const EVP_CIPHER;
    pub fn EVP_aes_128_ocb() -> *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;
@@ -284,6 +291,7 @@ extern "C" {
    pub fn EVP_aes_192_ccm() -> *const EVP_CIPHER;
    pub fn EVP_aes_192_gcm() -> *const EVP_CIPHER;
    pub fn EVP_aes_192_ofb() -> *const EVP_CIPHER;
    pub fn EVP_aes_192_ocb() -> *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;
@@ -294,6 +302,7 @@ extern "C" {
    pub fn EVP_aes_256_gcm() -> *const EVP_CIPHER;
    pub fn EVP_aes_256_xts() -> *const EVP_CIPHER;
    pub fn EVP_aes_256_ofb() -> *const EVP_CIPHER;
    pub fn EVP_aes_256_ocb() -> *const EVP_CIPHER;
    #[cfg(ossl110)]
    pub fn EVP_chacha20() -> *const ::EVP_CIPHER;
    #[cfg(ossl110)]
+87 −8
Original line number Diff line number Diff line
@@ -130,6 +130,10 @@ impl Cipher {
        unsafe { Cipher(ffi::EVP_aes_128_ofb()) }
    }

    pub fn aes_128_ocb() -> Cipher {
        unsafe { Cipher(ffi::EVP_aes_128_ocb()) }
    }

    pub fn aes_192_ecb() -> Cipher {
        unsafe { Cipher(ffi::EVP_aes_192_ecb()) }
    }
@@ -166,6 +170,10 @@ impl Cipher {
        unsafe { Cipher(ffi::EVP_aes_192_ofb()) }
    }

    pub fn aes_192_ocb() -> Cipher {
        unsafe { Cipher(ffi::EVP_aes_192_ocb()) }
    }

    pub fn aes_256_ecb() -> Cipher {
        unsafe { Cipher(ffi::EVP_aes_256_ecb()) }
    }
@@ -206,6 +214,10 @@ impl Cipher {
        unsafe { Cipher(ffi::EVP_aes_256_ofb()) }
    }

    pub fn aes_256_ocb() -> Cipher {
        unsafe { Cipher(ffi::EVP_aes_256_ocb()) }
    }

    pub fn bf_cbc() -> Cipher {
        unsafe { Cipher(ffi::EVP_bf_cbc()) }
    }
@@ -298,6 +310,13 @@ impl Cipher {
        // NOTE: OpenSSL returns pointers to static structs, which makes this work as expected
        *self == Cipher::aes_128_ccm() || *self == Cipher::aes_256_ccm()
    }

    /// Determines whether the cipher is using OCB mode
    fn is_ocb(&self) -> bool {
        *self == Cipher::aes_128_ocb() ||
        *self == Cipher::aes_192_ocb() ||
        *self == Cipher::aes_256_ocb()
    }
}

unsafe impl Sync for Cipher {}
@@ -421,7 +440,7 @@ impl Crypter {
                        assert!(iv.len() <= c_int::max_value() as usize);
                        cvt(ffi::EVP_CIPHER_CTX_ctrl(
                            crypter.ctx,
                            ffi::EVP_CTRL_GCM_SET_IVLEN,
                            ffi::EVP_CTRL_AEAD_SET_IVLEN,
                            iv.len() as c_int,
                            ptr::null_mut(),
                        ))?;
@@ -463,7 +482,7 @@ impl Crypter {
            // NB: this constant is actually more general than just GCM.
            cvt(ffi::EVP_CIPHER_CTX_ctrl(
                self.ctx,
                ffi::EVP_CTRL_GCM_SET_TAG,
                ffi::EVP_CTRL_AEAD_SET_TAG,
                tag.len() as c_int,
                tag.as_ptr() as *mut _,
            ))
@@ -481,7 +500,7 @@ impl Crypter {
            // NB: this constant is actually more general than just GCM.
            cvt(ffi::EVP_CIPHER_CTX_ctrl(
                self.ctx,
                ffi::EVP_CTRL_GCM_SET_TAG,
                ffi::EVP_CTRL_AEAD_SET_TAG,
                tag_len as c_int,
                ptr::null_mut(),
            ))
@@ -607,7 +626,7 @@ impl Crypter {
            assert!(tag.len() <= c_int::max_value() as usize);
            cvt(ffi::EVP_CIPHER_CTX_ctrl(
                self.ctx,
                ffi::EVP_CTRL_GCM_GET_TAG,
                ffi::EVP_CTRL_AEAD_GET_TAG,
                tag.len() as c_int,
                tag.as_mut_ptr() as *mut _,
            ))
@@ -736,10 +755,13 @@ pub fn encrypt_aead(
    let mut c = Crypter::new(t, Mode::Encrypt, key, iv)?;
    let mut out = vec![0; data.len() + t.block_size()];

    if t.is_ccm() {
    let is_ccm = t.is_ccm();
    if is_ccm || t.is_ocb() {
        c.set_tag_len(tag.len())?;
        if is_ccm {
            c.set_data_len(data.len())?;
        }
    }

    c.aad_update(aad)?;
    let count = c.update(data, &mut out)?;
@@ -764,10 +786,13 @@ pub fn decrypt_aead(
    let mut c = Crypter::new(t, Mode::Decrypt, key, iv)?;
    let mut out = vec![0; data.len() + t.block_size()];

    if t.is_ccm() {
    let is_ccm = t.is_ccm();
    if is_ccm || t.is_ocb() {
        c.set_tag(tag)?;
        if is_ccm {
            c.set_data_len(data.len())?;
        }
    }

    c.aad_update(aad)?;
    let count = c.update(data, &mut out)?;
@@ -1387,6 +1412,60 @@ mod tests {
        assert!(out.is_err());
    }

    #[test]
    fn test_aes_128_ocb() {
        let key = "000102030405060708090a0b0c0d0e0f";
        let aad = "0001020304050607";
        let tag = "16dc76a46d47e1ead537209e8a96d14e";
        let iv = "000102030405060708090a0b";
        let pt = "0001020304050607";
        let ct = "92b657130a74b85a";

        let mut actual_tag = [0; 16];
        let out = encrypt_aead(
            Cipher::aes_128_ocb(),
            &Vec::from_hex(key).unwrap(),
            Some(&Vec::from_hex(iv).unwrap()),
            &Vec::from_hex(aad).unwrap(),
            &Vec::from_hex(pt).unwrap(),
            &mut actual_tag,
        )
        .unwrap();

        assert_eq!(ct, hex::encode(out));
        assert_eq!(tag, hex::encode(actual_tag));

        let out = decrypt_aead(
            Cipher::aes_128_ocb(),
            &Vec::from_hex(key).unwrap(),
            Some(&Vec::from_hex(iv).unwrap()),
            &Vec::from_hex(aad).unwrap(),
            &Vec::from_hex(ct).unwrap(),
            &Vec::from_hex(tag).unwrap(),
        )
        .unwrap();
        assert_eq!(pt, hex::encode(out));
     }

    #[test]
    fn test_aes_128_ocb_fail() {
        let key = "000102030405060708090a0b0c0d0e0f";
        let aad = "0001020304050607";
        let tag = "16dc76a46d47e1ead537209e8a96d14e";
        let iv = "000000000405060708090a0b";
        let ct = "92b657130a74b85a";

        let out = decrypt_aead(
            Cipher::aes_128_ocb(),
            &Vec::from_hex(key).unwrap(),
            Some(&Vec::from_hex(iv).unwrap()),
            &Vec::from_hex(aad).unwrap(),
            &Vec::from_hex(ct).unwrap(),
            &Vec::from_hex(tag).unwrap(),
        );
        assert!(out.is_err());
    }

    #[test]
    #[cfg(any(ossl110))]
    fn test_chacha20() {