rc_crypto/aead/
aes_gcm.rsuse crate::{aead, error::*};
use nss::aes;
pub static AES_128_GCM: aead::Algorithm = aead::Algorithm {
key_len: 16,
tag_len: 16,
nonce_len: 96 / 8,
open,
seal,
};
pub static AES_256_GCM: aead::Algorithm = aead::Algorithm {
key_len: 32,
tag_len: 16,
nonce_len: 96 / 8,
open,
seal,
};
pub(crate) fn open(
key: &aead::Key,
nonce: aead::Nonce,
aad: &aead::Aad<'_>,
ciphertext_and_tag: &[u8],
) -> Result<Vec<u8>> {
aes_gcm(
key,
nonce,
aad,
ciphertext_and_tag,
aead::Direction::Opening,
)
}
pub(crate) fn seal(
key: &aead::Key,
nonce: aead::Nonce,
aad: &aead::Aad<'_>,
plaintext: &[u8],
) -> Result<Vec<u8>> {
aes_gcm(key, nonce, aad, plaintext, aead::Direction::Sealing)
}
fn aes_gcm(
key: &aead::Key,
nonce: aead::Nonce,
aad: &aead::Aad<'_>,
data: &[u8],
direction: aead::Direction,
) -> Result<Vec<u8>> {
Ok(aes::aes_gcm_crypt(
&key.key_value,
&nonce.0,
aad.0,
data,
direction.to_nss_operation(),
)?)
}
#[cfg(test)]
mod test {
use super::*;
const NONCE_HEX: &str = "cafebabefacedbaddecaf888";
const KEY_HEX: &str = "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308";
const AAD_HEX: &str = "feedfacedeadbeeffeedfacedeadbeefabaddad2";
const TAG_HEX: &str = "76fc6ece0f4e1768cddf8853bb2d551b";
const CIPHERTEXT_HEX: &str =
"522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662";
const CLEARTEXT_HEX: &str =
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39";
#[test]
fn test_decrypt() {
let key_bytes = hex::decode(KEY_HEX).unwrap();
let key = aead::Key::new(&AES_256_GCM, &key_bytes).unwrap();
let mut ciphertext_and_tag = hex::decode(CIPHERTEXT_HEX).unwrap();
let tag = hex::decode(TAG_HEX).unwrap();
ciphertext_and_tag.extend(&tag);
let iv = hex::decode(NONCE_HEX).unwrap();
let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap();
let aad_bytes = hex::decode(AAD_HEX).unwrap();
let aad = aead::Aad::from(&aad_bytes);
let cleartext_bytes = open(&key, nonce, &aad, &ciphertext_and_tag).unwrap();
let encoded_cleartext = hex::encode(cleartext_bytes);
assert_eq!(&CLEARTEXT_HEX, &encoded_cleartext);
}
#[test]
fn test_encrypt() {
let key_bytes = hex::decode(KEY_HEX).unwrap();
let key = aead::Key::new(&AES_256_GCM, &key_bytes).unwrap();
let cleartext = hex::decode(CLEARTEXT_HEX).unwrap();
let iv = hex::decode(NONCE_HEX).unwrap();
let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap();
let aad_bytes = hex::decode(AAD_HEX).unwrap();
let aad = aead::Aad::from(&aad_bytes);
let ciphertext_bytes = seal(&key, nonce, &aad, &cleartext).unwrap();
let expected_tag = hex::decode(TAG_HEX).unwrap();
let mut expected_ciphertext = hex::decode(CIPHERTEXT_HEX).unwrap();
expected_ciphertext.extend(&expected_tag);
assert_eq!(&expected_ciphertext, &ciphertext_bytes);
}
#[test]
fn test_roundtrip() {
let key_bytes = hex::decode(KEY_HEX).unwrap();
let key = aead::Key::new(&AES_256_GCM, &key_bytes).unwrap();
let cleartext = hex::decode(CLEARTEXT_HEX).unwrap();
let iv = hex::decode(NONCE_HEX).unwrap();
let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap();
let ciphertext_bytes = seal(&key, nonce, &aead::Aad::empty(), &cleartext).unwrap();
let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap();
let roundtriped_cleartext_bytes =
open(&key, nonce, &aead::Aad::empty(), &ciphertext_bytes).unwrap();
assert_eq!(roundtriped_cleartext_bytes, cleartext);
}
}