From 2f293642a1e45593f0d2d91f00a8037053c383fd Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Wed, 21 Apr 2021 19:20:48 -0400 Subject: [PATCH] implement Clone for LessSafeKey OpeningKey and SealingKey intentionally avoid implementing Clone, because they're attached to a fixed nonce sequence that should be unique. LessSafeKey isn't attached to a nonce sequence, though, and making it Clone lets callers avoid repeating key setup work. --- src/aead.rs | 1 + src/aead/aes.rs | 2 ++ src/aead/aes_gcm.rs | 1 + src/aead/chacha.rs | 1 + src/aead/gcm.rs | 1 + src/aead/less_safe_key.rs | 1 + tests/aead_tests.rs | 46 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 53 insertions(+) diff --git a/src/aead.rs b/src/aead.rs index 3c233c528b..b403c3f083 100644 --- a/src/aead.rs +++ b/src/aead.rs @@ -128,6 +128,7 @@ where impl Eq for Aad where A: Eq {} #[allow(clippy::large_enum_variant, variant_size_differences)] +#[derive(Clone)] enum KeyInner { AesGcm(aes_gcm::Key), ChaCha20Poly1305(chacha20_poly1305::Key), diff --git a/src/aead/aes.rs b/src/aead/aes.rs index 16d41a840b..0209a88f38 100644 --- a/src/aead/aes.rs +++ b/src/aead/aes.rs @@ -26,6 +26,7 @@ use crate::{ }; use core::ops::RangeFrom; +#[derive(Clone)] pub(crate) struct Key { inner: AES_KEY, cpu_features: cpu::Features, @@ -306,6 +307,7 @@ impl Key { // Keep this in sync with AES_KEY in aes.h. #[repr(C)] +#[derive(Clone)] pub(super) struct AES_KEY { pub rd_key: [u32; 4 * (MAX_ROUNDS + 1)], pub rounds: c::uint, diff --git a/src/aead/aes_gcm.rs b/src/aead/aes_gcm.rs index 0f7253c2fc..260abcdfc5 100644 --- a/src/aead/aes_gcm.rs +++ b/src/aead/aes_gcm.rs @@ -40,6 +40,7 @@ pub static AES_256_GCM: aead::Algorithm = aead::Algorithm { max_input_len: AES_GCM_MAX_INPUT_LEN, }; +#[derive(Clone)] pub struct Key { gcm_key: gcm::Key, // First because it has a large alignment requirement. aes_key: aes::Key, diff --git a/src/aead/chacha.rs b/src/aead/chacha.rs index e1c62f590e..dee5da1f2a 100644 --- a/src/aead/chacha.rs +++ b/src/aead/chacha.rs @@ -32,6 +32,7 @@ mod fallback; use core::ops::RangeFrom; +#[derive(Clone)] pub struct Key { words: [u32; KEY_LEN / 4], cpu_features: cpu::Features, diff --git a/src/aead/gcm.rs b/src/aead/gcm.rs index 40d9cf74ad..45737401c0 100644 --- a/src/aead/gcm.rs +++ b/src/aead/gcm.rs @@ -22,6 +22,7 @@ use core::ops::BitXorAssign; #[cfg(not(target_arch = "aarch64"))] mod gcm_nohw; +#[derive(Clone)] pub struct Key { h_table: HTable, cpu_features: cpu::Features, diff --git a/src/aead/less_safe_key.rs b/src/aead/less_safe_key.rs index 55bb6162de..4e8dd32309 100644 --- a/src/aead/less_safe_key.rs +++ b/src/aead/less_safe_key.rs @@ -20,6 +20,7 @@ use core::ops::RangeFrom; /// `NonceSequence` cannot reasonably be used. /// /// Prefer to use `OpeningKey`/`SealingKey` and `NonceSequence` when practical. +#[derive(Clone)] pub struct LessSafeKey { inner: KeyInner, algorithm: &'static Algorithm, diff --git a/tests/aead_tests.rs b/tests/aead_tests.rs index 08620728b3..869c0df19c 100644 --- a/tests/aead_tests.rs +++ b/tests/aead_tests.rs @@ -513,6 +513,52 @@ fn test_aead_key_debug() { ); } +fn test_aead_lesssafekey_clone_for_algorithm(algorithm: &'static aead::Algorithm) { + let test_bytes: Vec = (0..32).collect(); + let key_bytes = &test_bytes[..algorithm.key_len()]; + let nonce_bytes = &test_bytes[..algorithm.nonce_len()]; + + let key1: aead::LessSafeKey = + aead::LessSafeKey::new(aead::UnboundKey::new(algorithm, &key_bytes).unwrap()); + let key2 = key1.clone(); + + // LessSafeKey doesn't support AsRef or PartialEq, so instead just check that both keys produce + // the same encrypted output. + let mut buf1: Vec = (0..100).collect(); + let mut buf2 = buf1.clone(); + let tag1 = key1 + .seal_in_place_separate_tag( + aead::Nonce::try_assume_unique_for_key(&nonce_bytes).unwrap(), + aead::Aad::empty(), + &mut buf1, + ) + .unwrap(); + let tag2 = key2 + .seal_in_place_separate_tag( + aead::Nonce::try_assume_unique_for_key(&nonce_bytes).unwrap(), + aead::Aad::empty(), + &mut buf2, + ) + .unwrap(); + assert_eq!(tag1.as_ref(), tag2.as_ref()); + assert_eq!(buf1, buf2); +} + +#[test] +fn test_aead_lesssafekey_clone_aes_128_gcm() { + test_aead_lesssafekey_clone_for_algorithm(&aead::AES_128_GCM); +} + +#[test] +fn test_aead_lesssafekey_clone_aes_256_gcm() { + test_aead_lesssafekey_clone_for_algorithm(&aead::AES_256_GCM); +} + +#[test] +fn test_aead_lesssafekey_clone_chacha20_poly1305() { + test_aead_lesssafekey_clone_for_algorithm(&aead::CHACHA20_POLY1305); +} + fn make_key>( algorithm: &'static aead::Algorithm, key: &[u8],