use bytes::{BufMut, BytesMut};
use crate::{
v2::{
crypto::{Aes128Gcm, Aes256Gcm},
BLAKE3_KEY_DERIVE_CONTEXT,
},
CipherKind,
};
pub enum Cipher {
Aes128Gcm(Aes128Gcm),
Aes256Gcm(Aes256Gcm),
}
impl Cipher {
pub fn new(kind: CipherKind, key: &[u8], session_id: u64) -> Cipher {
let mut key_material = BytesMut::with_capacity(key.len() + 8);
key_material.put_slice(key);
key_material.put_u64(session_id);
let mut hasher = blake3::Hasher::new_derive_key(BLAKE3_KEY_DERIVE_CONTEXT);
hasher.update(&key_material);
let mut hasher_output = hasher.finalize_xof();
let mut derived_key = vec![0u8; kind.key_len()];
hasher_output.fill(&mut derived_key);
match kind {
CipherKind::AEAD2022_BLAKE3_AES_128_GCM => Cipher::Aes128Gcm(Aes128Gcm::new(&derived_key)),
CipherKind::AEAD2022_BLAKE3_AES_256_GCM => Cipher::Aes256Gcm(Aes256Gcm::new(&derived_key)),
_ => unreachable!("cipher {} is not an AES2022 AES-GCM cipher", kind),
}
}
pub fn nonce_size() -> usize {
debug_assert!(Aes128Gcm::nonce_size() == Aes256Gcm::nonce_size());
Aes128Gcm::nonce_size()
}
pub fn encrypt_packet(&self, salt: &[u8], plaintext_in_ciphertext_out: &mut [u8]) {
match *self {
Cipher::Aes128Gcm(ref c) => c.encrypt(salt, plaintext_in_ciphertext_out),
Cipher::Aes256Gcm(ref c) => c.encrypt(salt, plaintext_in_ciphertext_out),
}
}
pub fn decrypt_packet(&self, salt: &[u8], ciphertext_in_plaintext_out: &mut [u8]) -> bool {
match *self {
Cipher::Aes128Gcm(ref c) => c.decrypt(salt, ciphertext_in_plaintext_out),
Cipher::Aes256Gcm(ref c) => c.decrypt(salt, ciphertext_in_plaintext_out),
}
}
}