use openssl::symm::{Cipher, Crypter};
use rand::Rng;
use std::sync::Mutex;
use byteorder::{BigEndian, ByteOrder};
pub const NAME: super::Name = super::Name("aes256-ctr");
pub struct Key {
mac: crate::mac::MacKey,
crypter: Mutex<Crypter>,
buf: Mutex<cryptovec::CryptoVec>,
length: Mutex<[u8; 16]>,
}
pub static CIPHER: super::Cipher = super::Cipher {
_name: NAME,
key_len: 32,
iv_len: 16,
make_sealing_cipher,
make_opening_cipher,
};
fn make_sealing_cipher(k: &[u8], iv: &[u8], mac: crate::mac::MacKey) -> super::SealingCipher {
super::SealingCipher::Aes256Ctr(Key {
crypter: Mutex::new(
openssl::symm::Crypter::new(
Cipher::aes_256_ctr(),
openssl::symm::Mode::Encrypt,
&k,
Some(&iv),
)
.unwrap(),
),
mac,
buf: Mutex::new(cryptovec::CryptoVec::new()),
length: Mutex::new([0; 16]),
})
}
fn make_opening_cipher(k: &[u8], iv: &[u8], mac: crate::mac::MacKey) -> super::OpeningCipher {
super::OpeningCipher::Aes256Ctr(Key {
crypter: Mutex::new(
openssl::symm::Crypter::new(
Cipher::aes_256_ctr(),
openssl::symm::Mode::Encrypt,
&k,
Some(&iv),
)
.unwrap(),
),
mac,
buf: Mutex::new(cryptovec::CryptoVec::new()),
length: Mutex::new([0; 16]),
})
}
impl super::SealingKey for Key {
fn padding_length(&self, payload: &[u8]) -> usize {
let encrypted_len = payload.len() + 5;
let padding = 16 - (encrypted_len % 16);
let min_padding = if padding < 4 { padding + 16 } else { padding };
let mut rng = rand::rng();
(rng.random::<u8>() & 0xe0) as usize + min_padding
}
fn fill_padding(&self, padding_out: &mut [u8]) {
openssl::rand::rand_bytes(padding_out).unwrap()
}
fn tag_len(&self) -> usize {
self.mac.len()
}
fn seal(&self, sequence_number: u32, payload_tag: &mut [u8], tag_out: usize) {
let (payload, tag) = payload_tag.split_at_mut(tag_out);
self.mac.authenticate(sequence_number, &payload[..], tag);
let mut out = self.buf.lock().unwrap();
out.resize(payload.len());
let mut crypter = self.crypter.lock().unwrap();
let count = crypter.update(&payload, &mut out).unwrap();
crypter.finalize(&mut out[count..]).unwrap();
payload.clone_from_slice(&out);
}
}
impl super::OpeningKey for Key {
fn length_block_size(&self) -> usize { 16 }
fn decrypt_packet_length(
&self,
_sequence_number: u32,
encrypted_packet_length: &[u8],
) -> u32 {
let mut out = self.length.lock().unwrap();
let mut crypter = self.crypter.lock().unwrap();
let count = crypter.update(&encrypted_packet_length, &mut out[..]).unwrap();
crypter.finalize(&mut out[count..]).unwrap();
debug!("packet length {:?}", out);
BigEndian::read_u32(&out[..4])
}
fn tag_len(&self) -> usize {
self.mac.len()
}
fn open<'a>(
&self,
sequence_number: u32,
payload: &'a mut [u8],
tag: usize,
) -> Result<&'a [u8], crate::Error> {
debug!("payload = {:?}", payload);
let (payload, tag) = payload.split_at_mut(tag);
let mut out = self.buf.lock().unwrap();
out.resize(payload.len());
let mut c = self.crypter.lock().unwrap();
(&mut out[..16]).clone_from_slice(&self.length.lock().unwrap()[..]);
let count = c.update(&payload[16..], &mut out[16..]).unwrap();
c.finalize(&mut out[count..]).unwrap();
debug!("out = {:?}", &out[..]);
debug!("tag = {:?}", tag);
if !self.mac.verify(sequence_number, &out, tag) {
error!("WRONG MAC");
return Err(crate::Error::WrongMAC);
}
payload.clone_from_slice(&out);
Ok(payload)
}
}