From 7b6ee1cb63919844539a51488118e67ae5065455 Mon Sep 17 00:00:00 2001 From: Franziskus Kiefer Date: Wed, 21 Apr 2021 10:58:45 +0200 Subject: [PATCH] cleanup and message limits --- src/aead.rs | 41 +++++++++++++++++++++++++++++++++-------- src/aead_impl.rs | 4 ++-- src/kdf.rs | 2 +- src/kem.rs | 4 ++-- src/lib.rs | 39 ++++++++++++++++++++++++++------------- 5 files changed, 64 insertions(+), 26 deletions(-) diff --git a/src/aead.rs b/src/aead.rs index 16ce13d..8e9fc49 100644 --- a/src/aead.rs +++ b/src/aead.rs @@ -80,8 +80,8 @@ pub(crate) trait AeadTrait: Debug + Sync { aad: &[u8], cipher_txt: &[u8], ) -> Result, Error>; - fn get_key_length(&self) -> usize; - fn get_nonce_length(&self) -> usize; + fn key_length(&self) -> usize; + fn nonce_length(&self) -> usize; } #[derive(Debug)] @@ -111,7 +111,7 @@ impl<'de> Deserialize<'de> for Aead { } } -fn get_aead_object(mode: Mode) -> Box { +fn aead_object(mode: Mode) -> Box { match mode { Mode::AesGcm128 => Box::new(AesGcm128::new()), Mode::AesGcm256 => Box::new(AesGcm256::new()), @@ -121,18 +121,30 @@ fn get_aead_object(mode: Mode) -> Box { } impl Aead { + /// Create a new Aead with the given `mode`. pub fn new(mode: Mode) -> Self { Self { mode, - aead: get_aead_object(mode), + aead: aead_object(mode), } } - pub fn get_nk(&self) -> usize { - self.aead.get_key_length() + + /// Get the key length of the used scheme. + pub fn nk(&self) -> usize { + self.aead.key_length() } - pub fn get_nn(&self) -> usize { - self.aead.get_nonce_length() + + /// Get the nonce length of the used scheme. + pub fn nn(&self) -> usize { + self.aead.nonce_length() } + + /// Encrypt the given `plain_txt` with the `aad`, `key`, and `nonce`. All + /// values are passed in as byte slices. + /// + /// The function returns a `Result`. + /// A byte vector with the cipher text and tag concatenated if successful. + /// Or an `Error` if any of the parameters are invalid. pub fn seal( &self, key: &[u8], @@ -142,6 +154,13 @@ impl Aead { ) -> Result, Error> { self.aead.seal(key, nonce, aad, plain_txt) } + + /// Decrypt a given `cipher_txt` with the `aad`, `key`, and `nonce`. All + /// values are passed in as byte slices. + /// + /// The function returns a `Result`. + /// A byte vector with the plaintext. + /// Or an `Error` if any of the parameters are invalid or the opening fails. pub fn open( &self, key: &[u8], @@ -151,4 +170,10 @@ impl Aead { ) -> Result, Error> { self.aead.open(key, nonce, aad, cipher_txt) } + + /// Get the message limit for this AEAD. + /// If the message limit is reached, the key must be rotated. + pub fn message_limit(&self) -> u32 { + (1 << self.nn()) - 1 + } } diff --git a/src/aead_impl.rs b/src/aead_impl.rs index 8e06b29..35bff8a 100644 --- a/src/aead_impl.rs +++ b/src/aead_impl.rs @@ -66,10 +66,10 @@ macro_rules! implement_aead { Err(_) => Err(Error::OpenError), } } - fn get_key_length(&self) -> usize { + fn key_length(&self) -> usize { $key_length } - fn get_nonce_length(&self) -> usize { + fn nonce_length(&self) -> usize { 12 } } diff --git a/src/kdf.rs b/src/kdf.rs index c5f91da..92819a0 100755 --- a/src/kdf.rs +++ b/src/kdf.rs @@ -92,7 +92,7 @@ impl Kdf { } } - pub(crate) fn get_nh(&self) -> usize { + pub(crate) fn nh(&self) -> usize { self.kdf.digest_length() } diff --git a/src/kem.rs b/src/kem.rs index b2c8e51..974dc2b 100755 --- a/src/kem.rs +++ b/src/kem.rs @@ -57,7 +57,7 @@ pub enum Error { } // Map KEM to KDF according to spec. -fn get_kdf(mode: Mode) -> kdf::Mode { +fn kdf(mode: Mode) -> kdf::Mode { match mode { Mode::DhKemP256 => kdf::Mode::HkdfSha256, Mode::DhKemP384 => kdf::Mode::HkdfSha384, @@ -146,7 +146,7 @@ impl Kem { pub(crate) fn new(mode: Mode) -> Self { Self { mode, - kem: kem_object(mode, get_kdf(mode)), + kem: kem_object(mode, kdf(mode)), } } diff --git a/src/lib.rs b/src/lib.rs index 91aa4e1..70eb7f6 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,6 +67,9 @@ pub enum HpkeError { /// An error in the crypto library occurred. CryptoError, + + /// The message limit for this AEAD, key, and nonce. + MessageLimitReached, } #[deprecated( @@ -216,7 +219,7 @@ impl<'a> Context<'a> { .hpke .aead .seal(&self.key, &self.compute_nonce(), aad, plain_txt)?; - self.increment_seq(); + self.increment_seq()?; Ok(ctxt) } @@ -238,7 +241,7 @@ impl<'a> Context<'a> { .hpke .aead .open(&self.key, &self.compute_nonce(), aad, cipher_txt)?; - self.increment_seq(); + self.increment_seq()?; Ok(ptxt) } @@ -254,14 +257,16 @@ impl<'a> Context<'a> { pub fn export(&self, exporter_context: &[u8], length: usize) -> Vec { self.hpke.kdf.labeled_expand( &self.exporter_secret, - &self.hpke.get_ciphersuite(), + &self.hpke.ciphersuite(), "sec", exporter_context, length, ) } - // TODO: not cool + /// def Context.ComputeNonce(seq): + /// seq_bytes = I2OSP(seq, Nn) + /// return xor(self.base_nonce, seq_bytes) fn compute_nonce(&self) -> Vec { let seq = self.sequence_number.to_be_bytes(); let mut enc_seq = vec![0u8; self.nonce.len() - seq.len()]; @@ -269,8 +274,16 @@ impl<'a> Context<'a> { util::xor_bytes(&enc_seq, &self.nonce) } - fn increment_seq(&mut self) { + /// def Context.IncrementSeq(): + /// if self.seq >= (1 << (8*Nn)) - 1: + /// raise MessageLimitReached + /// self.seq += 1 + fn increment_seq(&mut self) -> Result<(), HpkeError> { + if self.sequence_number >= self.hpke.aead.message_limit() { + return Err(HpkeError::MessageLimitReached); + } self.sequence_number += 1; + Ok(()) } } @@ -318,9 +331,9 @@ impl Hpke { kem_id, kdf_id, aead_id, - nk: aead.get_nk(), - nn: aead.get_nn(), - nh: kdf.get_nh(), + nk: aead.nk(), + nn: aead.nn(), + nh: kdf.nh(), kem, kdf, aead, @@ -518,7 +531,7 @@ impl Hpke { } #[inline] - fn get_ciphersuite(&self) -> Vec { + fn ciphersuite(&self) -> Vec { util::concat(&[ b"HPKE", &(self.kem_id as u16).to_be_bytes(), @@ -528,7 +541,7 @@ impl Hpke { } #[inline] - fn get_key_schedule_context(&self, info: &[u8], psk_id: &[u8], suite_id: &[u8]) -> Vec { + fn key_schedule_context(&self, info: &[u8], psk_id: &[u8], suite_id: &[u8]) -> Vec { let psk_id_hash = self .kdf .labeled_extract(&[0], suite_id, "psk_id_hash", psk_id); @@ -577,8 +590,8 @@ impl Hpke { psk_id: &[u8], ) -> Result { self.verify_psk_inputs(psk, psk_id)?; - let suite_id = self.get_ciphersuite(); - let key_schedule_context = self.get_key_schedule_context(info, psk_id, &suite_id); + let suite_id = self.ciphersuite(); + let key_schedule_context = self.key_schedule_context(info, psk_id, &suite_id); let secret = self .kdf .labeled_extract(shared_secret, &suite_id, "secret", psk); @@ -608,7 +621,7 @@ impl Hpke { /// 4. Cryptographic Dependencies /// Randomized algorithm to generate a key pair `(skX, pkX)` for the KEM. - /// This is equivalent to `derive_key_pair(get_random_vector(sk.len()))` + /// This is equivalent to `derive_key_pair(random_vector(sk.len()))` /// /// Returns an `HpkeKeyPair`. pub fn generate_key_pair(&self) -> HpkeKeyPair {