cleared errors

This commit is contained in:
mamoniot 2023-03-09 11:52:52 -05:00
parent f87aec2dc3
commit c14f2edff6
No known key found for this signature in database
GPG key ID: ADCCDBBE0E3D3B3B
4 changed files with 58 additions and 147 deletions

View file

@ -1,43 +0,0 @@
use criterion::{criterion_group, criterion_main, Criterion};
use std::time::Duration;
use zerotier_crypto::mimcvdf;
use zerotier_crypto::p384::*;
use zerotier_crypto::x25519::*;
pub fn criterion_benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("cryptography");
let mut input = 1;
let mut proof = 0;
group.bench_function("mimcvdf::delay(1000)", |b| {
b.iter(|| {
input += 1;
proof = mimcvdf::delay(input, 1000);
})
});
group.bench_function("mimcvdf::verify(1000)", |b| {
b.iter(|| {
assert!(mimcvdf::verify(proof, input, 1000));
})
});
let p384_a = P384KeyPair::generate();
let p384_b = P384KeyPair::generate();
let x25519_a = X25519KeyPair::generate();
let x25519_b = X25519KeyPair::generate();
let x25519_b_pub = x25519_b.public_bytes();
group.measurement_time(Duration::new(10, 0));
group.bench_function("ecdhp384", |b| {
b.iter(|| p384_a.agree(p384_b.public_key()).expect("ecdhp384 failed"))
});
group.bench_function("ecdhx25519", |b| b.iter(|| x25519_a.agree(&x25519_b_pub)));
group.finish();
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);

View file

@ -14,7 +14,7 @@ pub struct AesGcm<const ENCRYPT: bool> (CipherCtx);
impl<const ENCRYPT: bool> AesGcm<ENCRYPT> { impl<const ENCRYPT: bool> AesGcm<ENCRYPT> {
/// Create an AesGcm context with the given key, key must be 16, 24 or 32 bytes long. /// Create an AesGcm context with the given key, key must be 16, 24 or 32 bytes long.
/// OpenSSL internally processes and caches this key, so it is recommended to reuse this context whenever encrypting under the same key. Call `set_iv` to change the IV for each reuse. /// OpenSSL internally processes and caches this key, so it is recommended to reuse this context whenever encrypting under the same key. Call `reset_init_gcm` to change the IV for each reuse.
pub fn new<const KEY_SIZE: usize>(key: &Secret<KEY_SIZE>) -> Self { pub fn new<const KEY_SIZE: usize>(key: &Secret<KEY_SIZE>) -> Self {
let ctx = CipherCtx::new().unwrap(); let ctx = CipherCtx::new().unwrap();
unsafe { unsafe {
@ -34,7 +34,7 @@ impl<const ENCRYPT: bool> AesGcm<ENCRYPT> {
/// Set the IV of this AesGcm context. This call resets the IV but leaves the key and encryption algorithm alone. /// Set the IV of this AesGcm context. This call resets the IV but leaves the key and encryption algorithm alone.
/// This method must be called before any other method on AesGcm. /// This method must be called before any other method on AesGcm.
/// `iv` must be exactly 12 bytes in length, because that is what Aes supports. /// `iv` must be exactly 12 bytes in length, because that is what Aes supports.
pub fn set_iv(&self, iv: &[u8]) { pub fn reset_init_gcm(&self, iv: &[u8]) {
debug_assert_eq!(iv.len(), 12, "Aes IV must be 12 bytes long"); debug_assert_eq!(iv.len(), 12, "Aes IV must be 12 bytes long");
unsafe { unsafe {
self.0.cipher_init::<ENCRYPT>(ptr::null(), ptr::null(), iv.as_ptr()).unwrap(); self.0.cipher_init::<ENCRYPT>(ptr::null(), ptr::null(), iv.as_ptr()).unwrap();
@ -86,68 +86,18 @@ impl AesGcm<false> {
} }
} }
/// An OpenSSL AES_CTR context. Automatically frees itself on drop. AES_CTR is similar to AES_GCM except it produces no authentication tag.
/// Whether `ENCRYPT` is true or false decides respectively whether this context encrypts or decrypts.
/// Even though OpenSSL lets you set this dynamically almost no operations work when you do this without resetting the context.
pub struct AesCtr<const ENCRYPT: bool> (CipherCtx);
impl<const ENCRYPT: bool> AesCtr<ENCRYPT> {
/// Create an AesCtr context with the given key, key must be 16, 24 or 32 bytes long.
/// OpenSSL internally processes and caches this key, so it is recommended to reuse this context whenever encrypting under the same key. Call `set_iv` to change the IV for each reuse.
pub fn new<const KEY_SIZE: usize>(key: &Secret<KEY_SIZE>) -> Self {
let ctx = CipherCtx::new().unwrap();
unsafe {
let t = match KEY_SIZE {
16 => ffi::EVP_aes_128_ctr(),
24 => ffi::EVP_aes_192_ctr(),
32 => ffi::EVP_aes_256_ctr(),
_ => panic!("Aes KEY_SIZE must be 16, 24 or 32")
};
ctx.cipher_init::<true>(t, key.as_ptr(), ptr::null()).unwrap();
ffi::EVP_CIPHER_CTX_set_padding(ctx.as_ptr(), 0);
}
let ret = AesCtr(ctx);
ret
}
/// Set the IV of this AesCtr context. This call resets the IV but leaves the key and encryption algorithm alone.
/// This method must be called before any other method on AesCtr.
/// `iv` must be exactly 12 bytes in length, because that is what Aes supports.
pub fn set_iv(&self, iv: &[u8]) {
debug_assert_eq!(iv.len(), 12, "Aes IV must be 12 bytes long");
unsafe {
self.0.cipher_init::<true>(ptr::null(), ptr::null(), iv.as_ptr()).unwrap();
}
}
/// Encrypt or decrypt.
#[inline(always)]
pub fn crypt(&self, input: &[u8], output: &mut [u8]) {
debug_assert!(output.len() >= input.len(), "output buffer must fit the size of the input buffer");
unsafe { self.0.update::<ENCRYPT>(input, output.as_mut_ptr()).unwrap() };
}
/// Encrypt or decrypt in place.
#[inline(always)]
pub fn crypt_in_place(&self, data: &mut [u8]) {
let ptr = data.as_mut_ptr();
unsafe { self.0.update::<ENCRYPT>(data, ptr).unwrap() }
}
}
const AES_BLOCK_SIZE: usize = 16; const AES_BLOCK_SIZE: usize = 16;
/// An OpenSSL AES_ECB context. Automatically frees itself on drop. /// An OpenSSL AES_ECB context. Automatically frees itself on drop.
/// AES_ECB is very insecure if used incorrectly so its public interface supports only exactly what ZeroTier uses it for. /// AES_ECB is very insecure if used incorrectly so its public interface supports only exactly what ZeroTier uses it for.
pub struct AesEcb<const ENCRYPT: bool> (CipherCtx); pub struct Aes(CipherCtx, CipherCtx);
impl<const ENCRYPT: bool> AesEcb<ENCRYPT> { impl Aes {
/// Create an AesEcb context with the given key, key must be 16, 24 or 32 bytes long. /// Create an AesEcb context with the given key, key must be 16, 24 or 32 bytes long.
/// OpenSSL internally processes and caches this key, so it is recommended to reuse this context whenever encrypting under the same key. /// OpenSSL internally processes and caches this key, so it is recommended to reuse this context whenever encrypting under the same key.
pub fn new<const KEY_SIZE: usize>(key: &Secret<KEY_SIZE>) -> Self { pub fn new<const KEY_SIZE: usize>(key: &Secret<KEY_SIZE>) -> Self {
let ctx = CipherCtx::new().unwrap(); let ctx0 = CipherCtx::new().unwrap();
let ctx1 = CipherCtx::new().unwrap();
unsafe { unsafe {
let t = match KEY_SIZE { let t = match KEY_SIZE {
16 => ffi::EVP_aes_128_ecb(), 16 => ffi::EVP_aes_128_ecb(),
@ -155,20 +105,28 @@ impl<const ENCRYPT: bool> AesEcb<ENCRYPT> {
32 => ffi::EVP_aes_256_ecb(), 32 => ffi::EVP_aes_256_ecb(),
_ => panic!("Aes KEY_SIZE must be 16, 24 or 32") _ => panic!("Aes KEY_SIZE must be 16, 24 or 32")
}; };
ctx.cipher_init::<true>(t, key.as_ptr(), ptr::null()).unwrap(); ctx0.cipher_init::<true>(t, key.as_ptr(), ptr::null()).unwrap();
ffi::EVP_CIPHER_CTX_set_padding(ctx.as_ptr(), 0); ffi::EVP_CIPHER_CTX_set_padding(ctx0.as_ptr(), 0);
debug_assert_eq!(ffi::EVP_CIPHER_CTX_get_block_size(ctx.as_ptr()) as usize, AES_BLOCK_SIZE, "Aes block size is incorrect, something is very wrong."); ctx1.cipher_init::<false>(t, key.as_ptr(), ptr::null()).unwrap();
ffi::EVP_CIPHER_CTX_set_padding(ctx1.as_ptr(), 0);
} }
let ret = AesEcb(ctx); let ret = Aes(ctx0, ctx1);
ret ret
} }
/// Do not ever encrypt the same plaintext twice. Make sure data is always different between calls. /// Do not ever encrypt the same plaintext twice. Make sure data is always different between calls.
#[inline(always)] #[inline(always)]
pub fn crypt_in_place(&self, data: &mut [u8]) { pub fn encrypt_block_in_place(&self, data: &mut [u8]) {
debug_assert_eq!(data.len(), AES_BLOCK_SIZE, "AesEcb should not be used to encrypt more than one block at a time unless you really know what you are doing."); debug_assert_eq!(data.len(), AES_BLOCK_SIZE, "AesEcb should not be used to encrypt more than one block at a time unless you really know what you are doing.");
let ptr = data.as_mut_ptr(); let ptr = data.as_mut_ptr();
unsafe { self.0.update::<ENCRYPT>(data, ptr).unwrap() } unsafe { self.0.update::<true>(data, ptr).unwrap() }
}
/// Do not ever encrypt the same plaintext twice. Make sure data is always different between calls.
#[inline(always)]
pub fn decrypt_block_in_place(&self, data: &mut [u8]) {
debug_assert_eq!(data.len(), AES_BLOCK_SIZE, "AesEcb should not be used to encrypt more than one block at a time unless you really know what you are doing.");
let ptr = data.as_mut_ptr();
unsafe { self.1.update::<false>(data, ptr).unwrap() }
} }
} }
@ -193,31 +151,31 @@ mod test {
let mut cipher_out = [0u8; 127]; let mut cipher_out = [0u8; 127];
let mut plain_out = [0u8; 127]; let mut plain_out = [0u8; 127];
enc.set_iv(&iv0); enc.reset_init_gcm(&iv0);
enc.crypt(&plain, &mut cipher_out); enc.crypt(&plain, &mut cipher_out);
tag_out = enc.finish_encrypt(); tag_out = enc.finish_encrypt();
dec.set_iv(&iv0); dec.reset_init_gcm(&iv0);
dec.crypt(&cipher_out, &mut plain_out); dec.crypt(&cipher_out, &mut plain_out);
assert!(dec.finish_decrypt(&tag_out)); assert!(dec.finish_decrypt(&tag_out));
assert_eq!(plain, plain_out); assert_eq!(plain, plain_out);
enc.set_iv(&iv1); enc.reset_init_gcm(&iv1);
enc.crypt(&plain, &mut cipher_out); enc.crypt(&plain, &mut cipher_out);
tag_out = enc.finish_encrypt(); tag_out = enc.finish_encrypt();
dec.set_iv(&iv1); dec.reset_init_gcm(&iv1);
dec.crypt(&cipher_out, &mut plain_out); dec.crypt(&cipher_out, &mut plain_out);
assert!(dec.finish_decrypt(&tag_out)); assert!(dec.finish_decrypt(&tag_out));
assert_eq!(plain, plain_out); assert_eq!(plain, plain_out);
enc.set_iv(&iv0); enc.reset_init_gcm(&iv0);
enc.crypt(&plain, &mut cipher_out); enc.crypt(&plain, &mut cipher_out);
tag_out = enc.finish_encrypt(); tag_out = enc.finish_encrypt();
dec.set_iv(&iv1); dec.reset_init_gcm(&iv1);
dec.crypt(&cipher_out, &mut plain_out); dec.crypt(&cipher_out, &mut plain_out);
assert!(!dec.finish_decrypt(&tag_out)); assert!(!dec.finish_decrypt(&tag_out));
} }
@ -238,7 +196,7 @@ mod test {
let benchmark_iterations: usize = 80000; let benchmark_iterations: usize = 80000;
let start = SystemTime::now(); let start = SystemTime::now();
for _ in 0..benchmark_iterations { for _ in 0..benchmark_iterations {
c.set_iv(&iv); c.reset_init_gcm(&iv);
c.crypt_in_place(&mut buf); c.crypt_in_place(&mut buf);
} }
let duration = SystemTime::now().duration_since(start).unwrap(); let duration = SystemTime::now().duration_since(start).unwrap();
@ -251,7 +209,7 @@ mod test {
let start = SystemTime::now(); let start = SystemTime::now();
for _ in 0..benchmark_iterations { for _ in 0..benchmark_iterations {
c.set_iv(&iv); c.reset_init_gcm(&iv);
c.crypt_in_place(&mut buf); c.crypt_in_place(&mut buf);
} }
let duration = SystemTime::now().duration_since(start).unwrap(); let duration = SystemTime::now().duration_since(start).unwrap();
@ -266,7 +224,7 @@ mod test {
// Even though we are just wrapping other implementations, it's still good to test thoroughly! // Even though we are just wrapping other implementations, it's still good to test thoroughly!
for tv in NIST_AES_GCM_TEST_VECTORS.iter() { for tv in NIST_AES_GCM_TEST_VECTORS.iter() {
let gcm = AesGcm::new(unsafe { &Secret::<32>::from_bytes(tv.key) }); let gcm = AesGcm::new(unsafe { &Secret::<32>::from_bytes(tv.key) });
gcm.set_iv(tv.nonce); gcm.reset_init_gcm(tv.nonce);
gcm.aad(tv.aad); gcm.aad(tv.aad);
let mut ciphertext = Vec::new(); let mut ciphertext = Vec::new();
ciphertext.resize(tv.plaintext.len(), 0); ciphertext.resize(tv.plaintext.len(), 0);
@ -276,13 +234,13 @@ mod test {
assert!(ciphertext.as_slice().eq(tv.ciphertext)); assert!(ciphertext.as_slice().eq(tv.ciphertext));
let gcm = AesGcm::new(unsafe { &Secret::<32>::from_bytes(tv.key) }); let gcm = AesGcm::new(unsafe { &Secret::<32>::from_bytes(tv.key) });
gcm.set_iv(tv.nonce); gcm.reset_init_gcm(tv.nonce);
gcm.aad(tv.aad); gcm.aad(tv.aad);
let mut ct_copy = ciphertext.clone(); let mut ct_copy = ciphertext.clone();
gcm.crypt_in_place(ct_copy.as_mut()); gcm.crypt_in_place(ct_copy.as_mut());
assert!(gcm.finish_decrypt(&tag)); assert!(gcm.finish_decrypt(&tag));
gcm.set_iv(tv.nonce); gcm.reset_init_gcm(tv.nonce);
gcm.aad(tv.aad); gcm.aad(tv.aad);
gcm.crypt_in_place(ciphertext.as_mut()); gcm.crypt_in_place(ciphertext.as_mut());
tag[0] ^= 1; tag[0] ^= 1;

View file

@ -35,9 +35,12 @@ impl<const L: usize> Secret<L> {
/// Copy bytes into secret, then nuke the previous value, will panic if the slice does not match the size of this secret. /// Copy bytes into secret, then nuke the previous value, will panic if the slice does not match the size of this secret.
#[inline(always)] #[inline(always)]
pub fn from_bytes_then_nuke(b: &mut [u8]) -> Self { pub fn from_bytes_then_nuke(b: &mut [u8]) -> Self {
let ret = Self (b.try_into().unwrap()); let mut k = [0u8; L];
unsafe { OPENSSL_cleanse(b.as_mut_ptr().cast(), L) }; k.copy_from_slice(b);
ret unsafe {
OPENSSL_cleanse(b.as_mut_ptr().cast(), L)
};
Self (k)
} }
#[inline(always)] #[inline(always)]
pub unsafe fn from_bytes(b: &[u8]) -> Self { pub unsafe fn from_bytes(b: &[u8]) -> Self {

View file

@ -134,8 +134,8 @@ struct SessionKey {
ratchet_key: Secret<BASE_KEY_SIZE>, // Key used in derivation of the next session key ratchet_key: Secret<BASE_KEY_SIZE>, // Key used in derivation of the next session key
receive_key: Secret<AES_256_KEY_SIZE>, // Receive side AES-GCM key receive_key: Secret<AES_256_KEY_SIZE>, // Receive side AES-GCM key
send_key: Secret<AES_256_KEY_SIZE>, // Send side AES-GCM key send_key: Secret<AES_256_KEY_SIZE>, // Send side AES-GCM key
receive_cipher_pool: Mutex<Vec<Box<AesGcm>>>, // Pool of reusable sending ciphers receive_cipher_pool: Mutex<Vec<Box<AesGcm<false>>>>, // Pool of reusable sending ciphers
send_cipher_pool: Mutex<Vec<Box<AesGcm>>>, // Pool of reusable receiving ciphers send_cipher_pool: Mutex<Vec<Box<AesGcm<true>>>>, // Pool of reusable receiving ciphers
rekey_at_time: i64, // Rekey at or after this time (ticks) rekey_at_time: i64, // Rekey at or after this time (ticks)
created_at_counter: u64, // Counter at which session was created created_at_counter: u64, // Counter at which session was created
rekey_at_counter: u64, // Rekey at or after this counter rekey_at_counter: u64, // Rekey at or after this counter
@ -313,7 +313,7 @@ impl<Application: ApplicationLayer> Context<Application> {
psk, psk,
send_counter: AtomicU64::new(3), // 1 and 2 are reserved for init and final ack send_counter: AtomicU64::new(3), // 1 and 2 are reserved for init and final ack
receive_window: std::array::from_fn(|_| AtomicU64::new(0)), receive_window: std::array::from_fn(|_| AtomicU64::new(0)),
header_protection_cipher: Aes::new(header_protection_key.as_bytes()), header_protection_cipher: Aes::new(&header_protection_key),
state: RwLock::new(State { state: RwLock::new(State {
remote_session_id: None, remote_session_id: None,
keys: [None, None], keys: [None, None],
@ -357,8 +357,7 @@ impl<Application: ApplicationLayer> Context<Application> {
// Encrypt and add authentication tag. // Encrypt and add authentication tag.
let mut gcm = AesGcm::new( let mut gcm = AesGcm::new(
kbkdf::<AES_256_KEY_SIZE, KBKDF_KEY_USAGE_LABEL_KEX_ES>(noise_es.as_bytes()).as_bytes(), &kbkdf::<AES_256_KEY_SIZE, KBKDF_KEY_USAGE_LABEL_KEX_ES>(noise_es.as_bytes())
true,
); );
gcm.reset_init_gcm(&create_message_nonce(PACKET_TYPE_ALICE_NOISE_XK_INIT, 1)); gcm.reset_init_gcm(&create_message_nonce(PACKET_TYPE_ALICE_NOISE_XK_INIT, 1));
gcm.aad(&offer.noise_h); gcm.aad(&offer.noise_h);
@ -493,7 +492,7 @@ impl<Application: ApplicationLayer> Context<Application> {
} }
} else { } else {
if let Some(i) = self.sessions.read().unwrap().incoming.get(&local_session_id).cloned() { if let Some(i) = self.sessions.read().unwrap().incoming.get(&local_session_id).cloned() {
Aes::new(i.header_protection_key.as_bytes()) Aes::new(&i.header_protection_key)
.decrypt_block_in_place(&mut incoming_packet[HEADER_PROTECT_ENCRYPT_START..HEADER_PROTECT_ENCRYPT_END]); .decrypt_block_in_place(&mut incoming_packet[HEADER_PROTECT_ENCRYPT_START..HEADER_PROTECT_ENCRYPT_END]);
incoming = Some(i); incoming = Some(i);
} else { } else {
@ -731,8 +730,7 @@ impl<Application: ApplicationLayer> Context<Application> {
// Decrypt and authenticate init packet, also proving that caller knows our static identity. // Decrypt and authenticate init packet, also proving that caller knows our static identity.
let mut gcm = AesGcm::new( let mut gcm = AesGcm::new(
kbkdf::<AES_256_KEY_SIZE, KBKDF_KEY_USAGE_LABEL_KEX_ES>(noise_es.as_bytes()).as_bytes(), &kbkdf::<AES_256_KEY_SIZE, KBKDF_KEY_USAGE_LABEL_KEX_ES>(noise_es.as_bytes())
false,
); );
gcm.reset_init_gcm(&incoming_message_nonce); gcm.reset_init_gcm(&incoming_message_nonce);
gcm.aad(&noise_h); gcm.aad(&noise_h);
@ -782,8 +780,7 @@ impl<Application: ApplicationLayer> Context<Application> {
// Encrypt main section of reply and attach tag. // Encrypt main section of reply and attach tag.
let mut gcm = AesGcm::new( let mut gcm = AesGcm::new(
kbkdf::<AES_256_KEY_SIZE, KBKDF_KEY_USAGE_LABEL_KEX_ES_EE>(noise_es_ee.as_bytes()).as_bytes(), &kbkdf::<AES_256_KEY_SIZE, KBKDF_KEY_USAGE_LABEL_KEX_ES_EE>(noise_es_ee.as_bytes())
true,
); );
gcm.reset_init_gcm(&create_message_nonce(PACKET_TYPE_BOB_NOISE_XK_ACK, 1)); gcm.reset_init_gcm(&create_message_nonce(PACKET_TYPE_BOB_NOISE_XK_ACK, 1));
gcm.aad(&noise_h_next); gcm.aad(&noise_h_next);
@ -836,7 +833,7 @@ impl<Application: ApplicationLayer> Context<Application> {
Some(alice_session_id), Some(alice_session_id),
0, 0,
1, 1,
Some(&Aes::new(header_protection_key.as_bytes())), Some(&Aes::new(&header_protection_key)),
)?; )?;
return Ok(ReceiveResult::Ok(session)); return Ok(ReceiveResult::Ok(session));
@ -885,8 +882,7 @@ impl<Application: ApplicationLayer> Context<Application> {
// Decrypt and authenticate Bob's reply. // Decrypt and authenticate Bob's reply.
let mut gcm = AesGcm::new( let mut gcm = AesGcm::new(
kbkdf::<AES_256_KEY_SIZE, KBKDF_KEY_USAGE_LABEL_KEX_ES_EE>(noise_es_ee.as_bytes()).as_bytes(), &kbkdf::<AES_256_KEY_SIZE, KBKDF_KEY_USAGE_LABEL_KEX_ES_EE>(noise_es_ee.as_bytes())
false,
); );
gcm.reset_init_gcm(&incoming_message_nonce); gcm.reset_init_gcm(&incoming_message_nonce);
gcm.aad(&outgoing_offer.noise_h); gcm.aad(&outgoing_offer.noise_h);
@ -931,12 +927,10 @@ impl<Application: ApplicationLayer> Context<Application> {
reply_len = append_to_slice(&mut reply_buffer, reply_len, alice_s_public_blob)?; reply_len = append_to_slice(&mut reply_buffer, reply_len, alice_s_public_blob)?;
let mut gcm = AesGcm::new( let mut gcm = AesGcm::new(
kbkdf::<AES_256_KEY_SIZE, KBKDF_KEY_USAGE_LABEL_KEX_ES_EE_HK>(&hmac_sha512( &kbkdf::<AES_256_KEY_SIZE, KBKDF_KEY_USAGE_LABEL_KEX_ES_EE_HK>(&hmac_sha512(
noise_es_ee.as_bytes(), noise_es_ee.as_bytes(),
hk.as_bytes(), hk.as_bytes(),
)) ))
.as_bytes(),
true,
); );
gcm.reset_init_gcm(&reply_message_nonce); gcm.reset_init_gcm(&reply_message_nonce);
gcm.aad(&noise_h_next); gcm.aad(&noise_h_next);
@ -954,8 +948,7 @@ impl<Application: ApplicationLayer> Context<Application> {
reply_len = append_to_slice(&mut reply_buffer, reply_len, metadata)?; reply_len = append_to_slice(&mut reply_buffer, reply_len, metadata)?;
let mut gcm = AesGcm::new( let mut gcm = AesGcm::new(
kbkdf::<AES_256_KEY_SIZE, KBKDF_KEY_USAGE_LABEL_KEX_ES_EE_SE_HK_PSK>(noise_es_ee_se_hk_psk.as_bytes()).as_bytes(), &kbkdf::<AES_256_KEY_SIZE, KBKDF_KEY_USAGE_LABEL_KEX_ES_EE_SE_HK_PSK>(noise_es_ee_se_hk_psk.as_bytes())
true,
); );
gcm.reset_init_gcm(&reply_message_nonce); gcm.reset_init_gcm(&reply_message_nonce);
gcm.aad(&noise_h_next); gcm.aad(&noise_h_next);
@ -1082,7 +1075,7 @@ impl<Application: ApplicationLayer> Context<Application> {
psk, psk,
send_counter: AtomicU64::new(2), // 1 was already used during negotiation send_counter: AtomicU64::new(2), // 1 was already used during negotiation
receive_window: std::array::from_fn(|_| AtomicU64::new(0)), receive_window: std::array::from_fn(|_| AtomicU64::new(0)),
header_protection_cipher: Aes::new(incoming.header_protection_key.as_bytes()), header_protection_cipher: Aes::new(&incoming.header_protection_key),
state: RwLock::new(State { state: RwLock::new(State {
remote_session_id: Some(incoming.alice_session_id), remote_session_id: Some(incoming.alice_session_id),
keys: [ keys: [
@ -1587,14 +1580,14 @@ impl SessionKey {
} }
} }
fn get_send_cipher(&self, counter: u64) -> Result<Box<AesGcm>, Error> { fn get_send_cipher(&self, counter: u64) -> Result<Box<AesGcm<true>>, Error> {
if counter < self.expire_at_counter { if counter < self.expire_at_counter {
Ok(self Ok(self
.send_cipher_pool .send_cipher_pool
.lock() .lock()
.unwrap() .unwrap()
.pop() .pop()
.unwrap_or_else(|| Box::new(AesGcm::new(self.send_key.as_bytes(), true)))) .unwrap_or_else(|| Box::new(AesGcm::new(&self.send_key))))
} else { } else {
// Not only do we return an error, but we also destroy the key. // Not only do we return an error, but we also destroy the key.
let mut scp = self.send_cipher_pool.lock().unwrap(); let mut scp = self.send_cipher_pool.lock().unwrap();
@ -1605,19 +1598,19 @@ impl SessionKey {
} }
} }
fn return_send_cipher(&self, c: Box<AesGcm>) { fn return_send_cipher(&self, c: Box<AesGcm<true>>) {
self.send_cipher_pool.lock().unwrap().push(c); self.send_cipher_pool.lock().unwrap().push(c);
} }
fn get_receive_cipher(&self) -> Box<AesGcm> { fn get_receive_cipher(&self) -> Box<AesGcm<false>> {
self.receive_cipher_pool self.receive_cipher_pool
.lock() .lock()
.unwrap() .unwrap()
.pop() .pop()
.unwrap_or_else(|| Box::new(AesGcm::new(self.receive_key.as_bytes(), false))) .unwrap_or_else(|| Box::new(AesGcm::new(&self.receive_key)))
} }
fn return_receive_cipher(&self, c: Box<AesGcm>) { fn return_receive_cipher(&self, c: Box<AesGcm<false>>) {
self.receive_cipher_pool.lock().unwrap().push(c); self.receive_cipher_pool.lock().unwrap().push(c);
} }
} }
@ -1640,7 +1633,7 @@ impl<'a> PktReader<'a> {
fn read_decrypt_auth<'b>(&'b mut self, l: usize, k: Secret<AES_256_KEY_SIZE>, gcm_aad: &[u8], nonce: &[u8]) -> Result<&'b [u8], Error> { fn read_decrypt_auth<'b>(&'b mut self, l: usize, k: Secret<AES_256_KEY_SIZE>, gcm_aad: &[u8], nonce: &[u8]) -> Result<&'b [u8], Error> {
let mut tmp = self.1 + l; let mut tmp = self.1 + l;
if (tmp + AES_GCM_TAG_SIZE) <= self.0.len() { if (tmp + AES_GCM_TAG_SIZE) <= self.0.len() {
let mut gcm = AesGcm::new(k.as_bytes(), false); let mut gcm = AesGcm::new(&k);
gcm.reset_init_gcm(nonce); gcm.reset_init_gcm(nonce);
gcm.aad(gcm_aad); gcm.aad(gcm_aad);
gcm.crypt_in_place(&mut self.0[self.1..tmp]); gcm.crypt_in_place(&mut self.0[self.1..tmp]);
@ -1683,8 +1676,8 @@ fn mix_hash(h: &[u8; SHA384_HASH_SIZE], m: &[u8]) -> [u8; SHA384_HASH_SIZE] {
fn kbkdf<const OUTPUT_BYTES: usize, const LABEL: u8>(key: &[u8]) -> Secret<OUTPUT_BYTES> { fn kbkdf<const OUTPUT_BYTES: usize, const LABEL: u8>(key: &[u8]) -> Secret<OUTPUT_BYTES> {
//These are the values we have assigned to the 5 variables involved in https://csrc.nist.gov/publications/detail/sp/800-108/final: //These are the values we have assigned to the 5 variables involved in https://csrc.nist.gov/publications/detail/sp/800-108/final:
// K_in = key, i = 0x01, Label = 'Z'||'T'||LABEL, Context = 0x00, L = (OUTPUT_BYTES * 8) // K_in = key, i = 0x01, Label = 'Z'||'T'||LABEL, Context = 0x00, L = (OUTPUT_BYTES * 8)
Secret::<OUTPUT_BYTES>::from_bytes( Secret::<OUTPUT_BYTES>::from_bytes_then_nuke(
&hmac_sha512( &mut hmac_sha512(
key, key,
&[ &[
1, 1,