mirror of https://github.com/ctz/rustls
Simplify construction of nonces.
This commit is contained in:
parent
dc076dd762
commit
c8469a1045
188
src/cipher.rs
188
src/cipher.rs
|
@ -9,13 +9,7 @@ use crate::error::TLSError;
|
|||
use crate::session::SessionSecrets;
|
||||
use crate::suites::{SupportedCipherSuite, BulkAlgorithm};
|
||||
use crate::key_schedule::{derive_traffic_key, derive_traffic_iv};
|
||||
|
||||
// accum[i] ^= offset[i] for all i in 0..len(accum)
|
||||
fn xor(accum: &mut [u8], offset: &[u8]) {
|
||||
for i in 0..accum.len() {
|
||||
accum[i] ^= offset[i];
|
||||
}
|
||||
}
|
||||
use std::convert::TryInto;
|
||||
|
||||
/// Objects with this trait can decrypt TLS messages.
|
||||
pub trait MessageDecrypter : Send + Sync {
|
||||
|
@ -71,8 +65,6 @@ pub fn new_tls12(scs: &'static SupportedCipherSuite,
|
|||
let client_write_iv = &key_block[offs..offs + scs.fixed_iv_len];
|
||||
offs += scs.fixed_iv_len;
|
||||
let server_write_iv = &key_block[offs..offs + scs.fixed_iv_len];
|
||||
offs += scs.fixed_iv_len;
|
||||
let explicit_nonce_offs = &key_block[offs..offs + scs.explicit_nonce_len];
|
||||
|
||||
let (write_key, write_iv) = if secrets.randoms.we_are_client {
|
||||
(client_write_key, client_write_iv)
|
||||
|
@ -91,16 +83,34 @@ pub fn new_tls12(scs: &'static SupportedCipherSuite,
|
|||
match scs.bulk {
|
||||
BulkAlgorithm::AES_128_GCM |
|
||||
BulkAlgorithm::AES_256_GCM => {
|
||||
// The GCM nonce is constructed from a 32-bit 'salt' derived
|
||||
// from the master-secret, and a 64-bit explicit part,
|
||||
// with no specified construction. Thanks for that.
|
||||
//
|
||||
// We use the same construction as TLS1.3/ChaCha20Poly1305:
|
||||
// a starting point extracted from the key block, xored with
|
||||
// the sequence number.
|
||||
let write_iv = {
|
||||
offs += scs.fixed_iv_len;
|
||||
let explicit_nonce_offs = &key_block[offs..offs + scs.explicit_nonce_len];
|
||||
|
||||
let mut iv = Iv(Default::default());
|
||||
iv.0[..scs.fixed_iv_len].copy_from_slice(write_iv);
|
||||
iv.0[scs.fixed_iv_len..].copy_from_slice(&explicit_nonce_offs);
|
||||
iv
|
||||
};
|
||||
|
||||
(Box::new(GCMMessageDecrypter::new(aead_alg,
|
||||
read_key,
|
||||
read_iv)),
|
||||
Box::new(GCMMessageEncrypter::new(aead_alg,
|
||||
write_key,
|
||||
write_iv,
|
||||
explicit_nonce_offs)))
|
||||
write_iv)))
|
||||
}
|
||||
|
||||
BulkAlgorithm::CHACHA20_POLY1305 => {
|
||||
let read_iv = Iv::new(read_iv.try_into().unwrap());
|
||||
let write_iv = Iv::new(write_iv.try_into().unwrap());
|
||||
(Box::new(ChaCha20Poly1305MessageDecrypter::new(aead_alg,
|
||||
read_key,
|
||||
read_iv)),
|
||||
|
@ -115,28 +125,27 @@ pub fn new_tls13_read(scs: &'static SupportedCipherSuite,
|
|||
secret: &[u8]) -> Box<dyn MessageDecrypter> {
|
||||
let hash = scs.get_hash();
|
||||
let key = derive_traffic_key(hash, secret, scs.enc_key_len);
|
||||
let iv = derive_traffic_iv(hash, secret, scs.fixed_iv_len);
|
||||
let iv = derive_traffic_iv(hash, secret);
|
||||
let aead_alg = scs.get_aead_alg();
|
||||
|
||||
Box::new(TLS13MessageDecrypter::new(aead_alg, &key, &iv))
|
||||
Box::new(TLS13MessageDecrypter::new(aead_alg, &key, iv))
|
||||
}
|
||||
|
||||
pub fn new_tls13_write(scs: &'static SupportedCipherSuite,
|
||||
secret: &[u8]) -> Box<dyn MessageEncrypter> {
|
||||
let hash = scs.get_hash();
|
||||
let key = derive_traffic_key(hash, secret, scs.enc_key_len);
|
||||
let iv = derive_traffic_iv(hash, secret, scs.fixed_iv_len);
|
||||
let iv = derive_traffic_iv(hash, secret);
|
||||
let aead_alg = scs.get_aead_alg();
|
||||
|
||||
Box::new(TLS13MessageEncrypter::new(aead_alg, &key, &iv))
|
||||
Box::new(TLS13MessageEncrypter::new(aead_alg, &key, iv))
|
||||
}
|
||||
|
||||
/// A `MessageEncrypter` for AES-GCM AEAD ciphersuites. TLS 1.2 only.
|
||||
pub struct GCMMessageEncrypter {
|
||||
alg: &'static aead::Algorithm,
|
||||
enc_key: aead::LessSafeKey,
|
||||
enc_salt: [u8; 4],
|
||||
nonce_offset: [u8; 8],
|
||||
iv: Iv,
|
||||
}
|
||||
|
||||
/// A `MessageDecrypter` for AES-GCM AEAD ciphersuites. TLS1.2 only.
|
||||
|
@ -190,26 +199,11 @@ impl MessageDecrypter for GCMMessageDecrypter {
|
|||
|
||||
impl MessageEncrypter for GCMMessageEncrypter {
|
||||
fn encrypt(&self, msg: BorrowMessage, seq: u64) -> Result<Message, TLSError> {
|
||||
// The GCM nonce is constructed from a 32-bit 'salt' derived
|
||||
// from the master-secret, and a 64-bit explicit part,
|
||||
// with no specified construction. Thanks for that.
|
||||
//
|
||||
// We use the same construction as TLS1.3/ChaCha20Poly1305:
|
||||
// a starting point extracted from the key block, xored with
|
||||
// the sequence number.
|
||||
//
|
||||
let nonce = {
|
||||
let mut nonce = [0u8; 12];
|
||||
nonce.as_mut().write_all(&self.enc_salt).unwrap();
|
||||
codec::put_u64(seq, &mut nonce[4..]);
|
||||
xor(&mut nonce[4..], &self.nonce_offset);
|
||||
aead::Nonce::assume_unique_for_key(nonce)
|
||||
};
|
||||
|
||||
let total_len = msg.payload.len() + self.alg.tag_len();
|
||||
let mut buf = Vec::with_capacity(total_len);
|
||||
buf.extend_from_slice(&msg.payload);
|
||||
|
||||
let nonce = make_tls13_nonce(&self.iv, seq);
|
||||
let aad = make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len());
|
||||
|
||||
let mut payload = Vec::with_capacity(GCM_EXPLICIT_NONCE_LEN + total_len);
|
||||
|
@ -229,26 +223,15 @@ impl MessageEncrypter for GCMMessageEncrypter {
|
|||
}
|
||||
|
||||
impl GCMMessageEncrypter {
|
||||
fn new(alg: &'static aead::Algorithm,
|
||||
enc_key: &[u8],
|
||||
enc_iv: &[u8],
|
||||
nonce_offset: &[u8])
|
||||
fn new(alg: &'static aead::Algorithm, enc_key: &[u8], iv: Iv)
|
||||
-> GCMMessageEncrypter {
|
||||
let key = aead::UnboundKey::new(alg, enc_key)
|
||||
.unwrap();
|
||||
let mut ret = GCMMessageEncrypter {
|
||||
GCMMessageEncrypter {
|
||||
alg,
|
||||
enc_key: aead::LessSafeKey::new(key),
|
||||
enc_salt: [0u8; 4],
|
||||
nonce_offset: [0u8; 8],
|
||||
};
|
||||
|
||||
debug_assert_eq!(enc_iv.len(), 4);
|
||||
debug_assert_eq!(nonce_offset.len(), 8);
|
||||
|
||||
ret.enc_salt.as_mut().write_all(enc_iv).unwrap();
|
||||
ret.nonce_offset.as_mut().write_all(nonce_offset).unwrap();
|
||||
ret
|
||||
iv,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,16 +252,29 @@ impl GCMMessageDecrypter {
|
|||
}
|
||||
}
|
||||
|
||||
/// A TLS 1.3 write or read IV.
|
||||
pub(crate) struct Iv([u8; ring::aead::NONCE_LEN]);
|
||||
|
||||
impl Iv {
|
||||
pub(crate) fn new(value: [u8; ring::aead::NONCE_LEN]) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn value(&self) -> &[u8; 12] { &self.0 }
|
||||
}
|
||||
|
||||
|
||||
struct TLS13MessageEncrypter {
|
||||
alg: &'static aead::Algorithm,
|
||||
enc_key: aead::LessSafeKey,
|
||||
enc_offset: [u8; 12],
|
||||
iv: Iv,
|
||||
}
|
||||
|
||||
struct TLS13MessageDecrypter {
|
||||
alg: &'static aead::Algorithm,
|
||||
dec_key: aead::LessSafeKey,
|
||||
dec_offset: [u8; 12],
|
||||
iv: Iv,
|
||||
}
|
||||
|
||||
fn unpad_tls13(v: &mut Vec<u8>) -> ContentType {
|
||||
|
@ -293,6 +289,17 @@ fn unpad_tls13(v: &mut Vec<u8>) -> ContentType {
|
|||
}
|
||||
}
|
||||
|
||||
fn make_tls13_nonce(iv: &Iv, seq: u64) -> ring::aead::Nonce {
|
||||
let mut nonce = [0u8; ring::aead::NONCE_LEN];
|
||||
codec::put_u64(seq, &mut nonce[4..]);
|
||||
|
||||
nonce.iter_mut().zip(iv.0.iter()).for_each(|(nonce, iv)| {
|
||||
*nonce ^= *iv;
|
||||
});
|
||||
|
||||
aead::Nonce::assume_unique_for_key(nonce)
|
||||
}
|
||||
|
||||
fn make_tls13_aad(len: usize) -> ring::aead::Aad<[u8; 1 + 2 + 2]>{
|
||||
ring::aead::Aad::from([
|
||||
0x17, // ContentType::ApplicationData
|
||||
|
@ -305,18 +312,12 @@ fn make_tls13_aad(len: usize) -> ring::aead::Aad<[u8; 1 + 2 + 2]>{
|
|||
|
||||
impl MessageEncrypter for TLS13MessageEncrypter {
|
||||
fn encrypt(&self, msg: BorrowMessage, seq: u64) -> Result<Message, TLSError> {
|
||||
let nonce = {
|
||||
let mut nonce = [0u8; 12];
|
||||
codec::put_u64(seq, &mut nonce[4..]);
|
||||
xor(&mut nonce, &self.enc_offset);
|
||||
aead::Nonce::assume_unique_for_key(nonce)
|
||||
};
|
||||
|
||||
let total_len = msg.payload.len() + 1 + self.alg.tag_len();
|
||||
let mut buf = Vec::with_capacity(total_len);
|
||||
buf.extend_from_slice(&msg.payload);
|
||||
msg.typ.encode(&mut buf);
|
||||
|
||||
let nonce = make_tls13_nonce(&self.iv, seq);
|
||||
let aad = make_tls13_aad(total_len);
|
||||
|
||||
self.enc_key.seal_in_place(nonce, aad, &mut buf)
|
||||
|
@ -332,13 +333,6 @@ impl MessageEncrypter for TLS13MessageEncrypter {
|
|||
|
||||
impl MessageDecrypter for TLS13MessageDecrypter {
|
||||
fn decrypt(&self, mut msg: Message, seq: u64) -> Result<Message, TLSError> {
|
||||
let nonce = {
|
||||
let mut nonce = [0u8; 12];
|
||||
codec::put_u64(seq, &mut nonce[4..]);
|
||||
xor(&mut nonce, &self.dec_offset);
|
||||
aead::Nonce::assume_unique_for_key(nonce)
|
||||
};
|
||||
|
||||
let payload = msg.take_opaque_payload()
|
||||
.ok_or(TLSError::DecryptError)?;
|
||||
let mut buf = payload.0;
|
||||
|
@ -347,6 +341,7 @@ impl MessageDecrypter for TLS13MessageDecrypter {
|
|||
return Err(TLSError::DecryptError);
|
||||
}
|
||||
|
||||
let nonce = make_tls13_nonce(&self.iv, seq);
|
||||
let aad = make_tls13_aad(buf.len());
|
||||
let plain_len = self.dec_key.open_in_place(nonce, aad, &mut buf)
|
||||
.map_err(|_| TLSError::DecryptError)?
|
||||
|
@ -379,34 +374,28 @@ impl MessageDecrypter for TLS13MessageDecrypter {
|
|||
impl TLS13MessageEncrypter {
|
||||
fn new(alg: &'static aead::Algorithm,
|
||||
enc_key: &[u8],
|
||||
enc_iv: &[u8]) -> TLS13MessageEncrypter {
|
||||
enc_iv: Iv) -> TLS13MessageEncrypter {
|
||||
let key = aead::UnboundKey::new(alg, enc_key)
|
||||
.unwrap();
|
||||
let mut ret = TLS13MessageEncrypter {
|
||||
TLS13MessageEncrypter {
|
||||
alg,
|
||||
enc_key: aead::LessSafeKey::new(key),
|
||||
enc_offset: [0u8; 12],
|
||||
};
|
||||
|
||||
ret.enc_offset.as_mut().write_all(enc_iv).unwrap();
|
||||
ret
|
||||
iv: enc_iv,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TLS13MessageDecrypter {
|
||||
fn new(alg: &'static aead::Algorithm,
|
||||
dec_key: &[u8],
|
||||
dec_iv: &[u8]) -> TLS13MessageDecrypter {
|
||||
dec_iv: Iv) -> TLS13MessageDecrypter {
|
||||
let key = aead::UnboundKey::new(alg, dec_key)
|
||||
.unwrap();
|
||||
let mut ret = TLS13MessageDecrypter {
|
||||
TLS13MessageDecrypter {
|
||||
alg,
|
||||
dec_key: aead::LessSafeKey::new(key),
|
||||
dec_offset: [0u8; 12],
|
||||
};
|
||||
|
||||
ret.dec_offset.as_mut().write_all(dec_iv).unwrap();
|
||||
ret
|
||||
iv: dec_iv,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,7 +405,7 @@ impl TLS13MessageDecrypter {
|
|||
pub struct ChaCha20Poly1305MessageEncrypter {
|
||||
alg: &'static aead::Algorithm,
|
||||
enc_key: aead::LessSafeKey,
|
||||
enc_offset: [u8; 12],
|
||||
enc_offset: Iv,
|
||||
}
|
||||
|
||||
/// The RFC7905/RFC7539 ChaCha20Poly1305 construction.
|
||||
|
@ -424,39 +413,33 @@ pub struct ChaCha20Poly1305MessageEncrypter {
|
|||
/// TLS1.3 uses `TLS13MessageDecrypter`.
|
||||
pub struct ChaCha20Poly1305MessageDecrypter {
|
||||
dec_key: aead::LessSafeKey,
|
||||
dec_offset: [u8; 12],
|
||||
dec_offset: Iv,
|
||||
}
|
||||
|
||||
impl ChaCha20Poly1305MessageEncrypter {
|
||||
fn new(alg: &'static aead::Algorithm,
|
||||
enc_key: &[u8],
|
||||
enc_iv: &[u8]) -> ChaCha20Poly1305MessageEncrypter {
|
||||
enc_iv: Iv) -> ChaCha20Poly1305MessageEncrypter {
|
||||
let key = aead::UnboundKey::new(alg, enc_key)
|
||||
.unwrap();
|
||||
let mut ret = ChaCha20Poly1305MessageEncrypter {
|
||||
ChaCha20Poly1305MessageEncrypter {
|
||||
alg,
|
||||
enc_key: aead::LessSafeKey::new(key),
|
||||
enc_offset: [0u8; 12],
|
||||
};
|
||||
|
||||
ret.enc_offset.as_mut().write_all(enc_iv).unwrap();
|
||||
ret
|
||||
enc_offset: enc_iv,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ChaCha20Poly1305MessageDecrypter {
|
||||
fn new(alg: &'static aead::Algorithm,
|
||||
dec_key: &[u8],
|
||||
dec_iv: &[u8]) -> ChaCha20Poly1305MessageDecrypter {
|
||||
dec_iv: Iv) -> ChaCha20Poly1305MessageDecrypter {
|
||||
let key = aead::UnboundKey::new(alg, dec_key)
|
||||
.unwrap();
|
||||
let mut ret = ChaCha20Poly1305MessageDecrypter {
|
||||
ChaCha20Poly1305MessageDecrypter {
|
||||
dec_key: aead::LessSafeKey::new(key),
|
||||
dec_offset: [0u8; 12],
|
||||
};
|
||||
|
||||
ret.dec_offset.as_mut().write_all(dec_iv).unwrap();
|
||||
ret
|
||||
dec_offset: dec_iv,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -472,14 +455,7 @@ impl MessageDecrypter for ChaCha20Poly1305MessageDecrypter {
|
|||
return Err(TLSError::DecryptError);
|
||||
}
|
||||
|
||||
// Nonce is offset_96 ^ (0_32 || seq_64)
|
||||
let nonce = {
|
||||
let mut nonce = [0u8; 12];
|
||||
codec::put_u64(seq, &mut nonce[4..]);
|
||||
xor(&mut nonce, &self.dec_offset);
|
||||
aead::Nonce::assume_unique_for_key(nonce)
|
||||
};
|
||||
|
||||
let nonce = make_tls13_nonce(&self.dec_offset, seq);
|
||||
let aad = make_tls12_aad(seq, msg.typ, msg.version, buf.len() - CHACHAPOLY1305_OVERHEAD);
|
||||
|
||||
let plain_len = self.dec_key.open_in_place(nonce, aad, &mut buf)
|
||||
|
@ -502,13 +478,7 @@ impl MessageDecrypter for ChaCha20Poly1305MessageDecrypter {
|
|||
|
||||
impl MessageEncrypter for ChaCha20Poly1305MessageEncrypter {
|
||||
fn encrypt(&self, msg: BorrowMessage, seq: u64) -> Result<Message, TLSError> {
|
||||
let nonce = {
|
||||
let mut nonce = [0u8; 12];
|
||||
codec::put_u64(seq, &mut nonce[4..]);
|
||||
xor(&mut nonce, &self.enc_offset);
|
||||
aead::Nonce::assume_unique_for_key(nonce)
|
||||
};
|
||||
|
||||
let nonce = make_tls13_nonce(&self.enc_offset, seq);
|
||||
let aad = make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len());
|
||||
|
||||
let total_len = msg.payload.len() + self.alg.tag_len();
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
use ring::{hmac, digest};
|
||||
use crate::msgs::codec::Codec;
|
||||
use crate::error::TLSError;
|
||||
use std::convert::TryInto;
|
||||
use crate::cipher::Iv;
|
||||
|
||||
/// The kinds of secret we can extract from `KeySchedule`.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
|
@ -263,9 +265,11 @@ pub fn derive_traffic_key(hash: &'static digest::Algorithm, secret: &[u8], len:
|
|||
_hkdf_expand_label_vec(&hmac::Key::new(hmac_alg, secret), b"key", &[], len)
|
||||
}
|
||||
|
||||
pub fn derive_traffic_iv(hash: &'static digest::Algorithm, secret: &[u8], len: usize) -> Vec<u8> {
|
||||
pub(crate) fn derive_traffic_iv(hash: &'static digest::Algorithm, secret: &[u8]) -> Iv {
|
||||
let hmac_alg = convert_digest_to_hmac_alg(hash);
|
||||
_hkdf_expand_label_vec(&hmac::Key::new(hmac_alg, secret), b"iv", &[], len)
|
||||
let iv = _hkdf_expand_label_vec(&hmac::Key::new(hmac_alg, secret), b"iv", &[],
|
||||
ring::aead::NONCE_LEN);
|
||||
Iv::new(iv[..].try_into().unwrap())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -385,8 +389,7 @@ mod test {
|
|||
client_hts.to_vec());
|
||||
assert_eq!(derive_traffic_key(hash, &got_client_hts, client_hts_key.len()),
|
||||
client_hts_key.to_vec());
|
||||
assert_eq!(derive_traffic_iv(hash, &got_client_hts, client_hts_iv.len()),
|
||||
client_hts_iv.to_vec());
|
||||
assert_eq!(derive_traffic_iv(hash, &got_client_hts).value(), &client_hts_iv);
|
||||
|
||||
let got_server_hts = ks.derive(SecretKind::ServerHandshakeTrafficSecret,
|
||||
&hs_start_hash);
|
||||
|
@ -394,8 +397,7 @@ mod test {
|
|||
server_hts.to_vec());
|
||||
assert_eq!(derive_traffic_key(hash, &got_server_hts, server_hts_key.len()),
|
||||
server_hts_key.to_vec());
|
||||
assert_eq!(derive_traffic_iv(hash, &got_server_hts, server_hts_iv.len()),
|
||||
server_hts_iv.to_vec());
|
||||
assert_eq!(derive_traffic_iv(hash, &got_server_hts).value(), &server_hts_iv);
|
||||
|
||||
ks.input_empty();
|
||||
|
||||
|
@ -405,8 +407,7 @@ mod test {
|
|||
client_ats.to_vec());
|
||||
assert_eq!(derive_traffic_key(hash, &got_client_ats, client_ats_key.len()),
|
||||
client_ats_key.to_vec());
|
||||
assert_eq!(derive_traffic_iv(hash, &got_client_ats, client_ats_iv.len()),
|
||||
client_ats_iv.to_vec());
|
||||
assert_eq!(derive_traffic_iv(hash, &got_client_ats).value(), &client_ats_iv);
|
||||
|
||||
let got_server_ats = ks.derive(SecretKind::ServerApplicationTrafficSecret,
|
||||
&hs_full_hash);
|
||||
|
@ -414,8 +415,7 @@ mod test {
|
|||
server_ats.to_vec());
|
||||
assert_eq!(derive_traffic_key(hash, &got_server_ats, server_ats_key.len()),
|
||||
server_ats_key.to_vec());
|
||||
assert_eq!(derive_traffic_iv(hash, &got_server_ats, server_ats_iv.len()),
|
||||
server_ats_iv.to_vec());
|
||||
assert_eq!(derive_traffic_iv(hash, &got_server_ats).value(), &server_ats_iv);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue