Add support for AES-OCB mode

This commit is contained in:
Henrik Böving 2020-05-08 22:14:35 +02:00
parent e446d819e3
commit 963e3994a5
2 changed files with 96 additions and 8 deletions

View File

@ -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)]

View File

@ -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() {