From 047550f2368d134c9d5dca60aeb0b56fe151a323 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sun, 3 May 2020 00:21:07 -0400 Subject: move to ring for things that it supports it doesn't support AES_256_CBC_HMAC_SHA256, so we can't move that over yet (see https://github.com/briansmith/ring/issues/588) --- src/cipherstring.rs | 52 +++++++++++++++++++++++----------------------------- src/error.rs | 18 +++--------------- src/identity.rs | 29 +++++++++++++++++++---------- 3 files changed, 45 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/cipherstring.rs b/src/cipherstring.rs index 2398b07..09d5c88 100644 --- a/src/cipherstring.rs +++ b/src/cipherstring.rs @@ -1,7 +1,6 @@ use crate::prelude::*; use block_modes::BlockMode as _; -use hmac::Mac as _; use rand::RngCore as _; pub struct CipherString { @@ -58,6 +57,8 @@ impl CipherString { ) -> Result { let iv = random_iv(); + // ring doesn't currently support CBC ciphers, so we have to do it + // manually. see https://github.com/briansmith/ring/issues/588 let cipher = block_modes::Cbc::< aes::Aes256, block_modes::block_padding::Pkcs7, @@ -65,12 +66,12 @@ impl CipherString { .context(crate::error::CreateBlockMode)?; let ciphertext = cipher.encrypt_vec(plaintext); - let mut digest = - hmac::Hmac::::new_varkey(keys.mac_key()) - .map_err(|_| Error::InvalidMacKey)?; - digest.input(&iv); - digest.input(&ciphertext); - let mac = digest.result().code().to_vec(); + let mut digest = ring::hmac::Context::with_key( + &ring::hmac::Key::new(ring::hmac::HMAC_SHA256, keys.mac_key()), + ); + digest.update(&iv); + digest.update(&ciphertext); + let mac = digest.sign().as_ref().to_vec(); Ok(Self { ty: 2, @@ -111,18 +112,25 @@ impl CipherString { } if let Some(mac) = &self.mac { - let mut digest = - hmac::Hmac::::new_varkey(keys.mac_key()) - .map_err(|_| Error::InvalidMacKey)?; - digest.input(&self.iv); - digest.input(&self.ciphertext); - let calculated_mac = digest.result().code(); - - if !macs_equal(mac, &calculated_mac, keys.mac_key())? { + let key = + ring::hmac::Key::new(ring::hmac::HMAC_SHA256, keys.mac_key()); + // it'd be nice to not have to pull this into a vec, but ring + // doesn't currently support non-contiguous verification. see + // https://github.com/briansmith/ring/issues/615 + let data: Vec<_> = self + .iv + .iter() + .chain(self.ciphertext.iter()) + .copied() + .collect(); + + if ring::hmac::verify(&key, &data, mac).is_err() { return Err(Error::InvalidMac); } } + // ring doesn't currently support CBC ciphers, so we have to do it + // manually. see https://github.com/briansmith/ring/issues/588 Ok(block_modes::Cbc::< aes::Aes256, block_modes::block_padding::Pkcs7, @@ -144,20 +152,6 @@ impl std::fmt::Display for CipherString { } } -fn macs_equal(mac1: &[u8], mac2: &[u8], mac_key: &[u8]) -> Result { - let mut digest = hmac::Hmac::::new_varkey(mac_key) - .map_err(|_| Error::InvalidMacKey)?; - digest.input(mac1); - let hmac1 = digest.result().code(); - - let mut digest = hmac::Hmac::::new_varkey(mac_key) - .map_err(|_| Error::InvalidMacKey)?; - digest.input(mac2); - let hmac2 = digest.result().code(); - - Ok(hmac1 == hmac2) -} - fn random_iv() -> Vec { let mut iv = vec![0_u8; 16]; let mut rng = rand::thread_rng(); diff --git a/src/error.rs b/src/error.rs index b1ce2b6..2222f66 100644 --- a/src/error.rs +++ b/src/error.rs @@ -22,18 +22,9 @@ pub enum Error { res: std::process::ExitStatus, }, - // no Error impl - // #[snafu(display("failed to expand with hkdf: {}", source))] - // HkdfExpand { source: hkdf::InvalidLength }, #[snafu(display("failed to expand with hkdf"))] HkdfExpand, - // no Error impl - // #[snafu(display("failed to create hkdf: {}", source))] - // HkdfFromPrk { source: hkdf::InvalidPrkLength }, - #[snafu(display("failed to create hkdf"))] - HkdfFromPrk, - #[snafu(display("username or password incorrect"))] IncorrectPassword, @@ -49,12 +40,6 @@ pub enum Error { #[snafu(display("invalid mac"))] InvalidMac, - // no Error impl - // #[snafu(display("invalid mac key: {}", source))] - // InvalidMacKey { source: hmac::crypto_mac::InvalidKeyLength }, - #[snafu(display("invalid mac key"))] - InvalidMacKey, - #[snafu(display("failed to load config: {}", source))] LoadConfig { source: std::io::Error }, @@ -73,6 +58,9 @@ pub enum Error { #[snafu(display("failed to load db: {}", source))] LoadDbJson { source: serde_json::Error }, + #[snafu(display("pbkdf2 requires at least 1 iteration (got 0)"))] + Pbkdf2ZeroIterations, + #[snafu(display("pinentry cancelled"))] PinentryCancelled, diff --git a/src/identity.rs b/src/identity.rs index 1baac0f..8415765 100644 --- a/src/identity.rs +++ b/src/identity.rs @@ -12,33 +12,42 @@ impl Identity { password: &crate::locked::Password, iterations: u32, ) -> Result { + let iterations = std::num::NonZeroU32::new(iterations) + .context(crate::error::Pbkdf2ZeroIterations)?; + let mut keys = crate::locked::Vec::new(); keys.extend(std::iter::repeat(0).take(64)); let enc_key = &mut keys.data_mut()[0..32]; - pbkdf2::pbkdf2::>( - password.password(), + ring::pbkdf2::derive( + ring::pbkdf2::PBKDF2_HMAC_SHA256, + iterations, email.as_bytes(), - iterations as usize, + password.password(), enc_key, ); let mut hash = crate::locked::Vec::new(); hash.extend(std::iter::repeat(0).take(32)); - pbkdf2::pbkdf2::>( - enc_key, + ring::pbkdf2::derive( + ring::pbkdf2::PBKDF2_HMAC_SHA256, + std::num::NonZeroU32::new(1).unwrap(), password.password(), - 1, + enc_key, hash.data_mut(), ); - let hkdf = hkdf::Hkdf::::from_prk(enc_key) - .map_err(|_| Error::HkdfFromPrk)?; - hkdf.expand(b"enc", enc_key) + let hkdf = + ring::hkdf::Prk::new_less_safe(ring::hkdf::HKDF_SHA256, enc_key); + hkdf.expand(&[b"enc"], ring::hkdf::HKDF_SHA256) + .map_err(|_| Error::HkdfExpand)? + .fill(enc_key) .map_err(|_| Error::HkdfExpand)?; let mac_key = &mut keys.data_mut()[32..64]; - hkdf.expand(b"mac", mac_key) + hkdf.expand(&[b"mac"], ring::hkdf::HKDF_SHA256) + .map_err(|_| Error::HkdfExpand)? + .fill(mac_key) .map_err(|_| Error::HkdfExpand)?; let keys = crate::locked::Keys::new(keys); -- cgit v1.2.3-54-g00ecf