Skip to content

Commit

Permalink
Update crypto deps to prerelease versions
Browse files Browse the repository at this point in the history
  • Loading branch information
dani-garcia committed Apr 24, 2024
1 parent 0a8ebaa commit 45e7416
Show file tree
Hide file tree
Showing 11 changed files with 360 additions and 390 deletions.
566 changes: 281 additions & 285 deletions Cargo.lock

Large diffs are not rendered by default.

24 changes: 14 additions & 10 deletions crates/bitwarden-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,30 @@ default = []
mobile = ["dep:uniffi"] # Mobile-specific features

[dependencies]
aes = { version = ">=0.8.2, <0.9", features = ["zeroize"] }
argon2 = { version = ">=0.5.0, <0.6", features = [
aes = { version = "0.9.0-pre", features = ["zeroize"] }
argon2 = { version = "0.6.0-pre.0", features = [
"std",
"zeroize",
], default-features = false }
base64 = ">=0.21.2, <0.22"
cbc = { version = ">=0.1.2, <0.2", features = ["alloc", "zeroize"] }
generic-array = { version = ">=0.14.7, <1.0", features = ["zeroize"] }
hkdf = ">=0.12.3, <0.13"
hmac = ">=0.12.1, <0.13"
blake2 = { version = "0.11.0-pre.3", features = ["zeroize"] }
cbc = { version = "0.2.0-pre", features = [
"alloc",
"zeroize",
], git = "https://github.com/RustCrypto/block-modes", rev = "532a46166bcc74bf718ca351cc3b5a86a2fcb2a3" }
hkdf = "0.13.0-pre.3"
hmac = "0.13.0-pre.3"
hybrid-array = { version = "0.2.0-rc.8", features = ["zeroize"] }
num-bigint = ">=0.4, <0.5"
num-traits = ">=0.2.15, <0.3"
pbkdf2 = { version = ">=0.12.1, <0.13", default-features = false }
pbkdf2 = { version = "0.13.0-pre.0", default-features = false }
rand = ">=0.8.5, <0.9"
rayon = ">=1.8.1, <2.0"
rsa = ">=0.9.2, <0.10"
rsa = "0.10.0-pre.1"
schemars = { version = ">=0.8, <0.9", features = ["uuid1"] }
serde = { version = ">=1.0, <2.0", features = ["derive"] }
sha1 = ">=0.10.5, <0.11"
sha2 = ">=0.10.6, <0.11"
sha1 = { version = "0.11.0-pre.3", features = ["zeroize"] }
sha2 = { version = "0.11.0-pre.3", features = ["zeroize"] }
subtle = ">=2.5.0, <3.0"
thiserror = ">=1.0.40, <2.0"
uniffi = { version = "=0.26.1", optional = true }
Expand Down
62 changes: 26 additions & 36 deletions crates/bitwarden-crypto/src/aes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@
//! In most cases you should use the [EncString][crate::EncString] with
//! [KeyEncryptable][crate::KeyEncryptable] & [KeyDecryptable][crate::KeyDecryptable] instead.

use aes::cipher::{
block_padding::Pkcs7,
typenum::{U16, U32},
BlockDecryptMut, BlockEncryptMut, KeyIvInit,
};
use generic_array::GenericArray;
use hmac::Mac;
use aes::cipher::{BlockModeDecrypt, BlockModeEncrypt, KeyIvInit};
use cbc::cipher::block_padding::Pkcs7;
use hmac::{KeyInit, Mac};
use subtle::ConstantTimeEq;

use crate::{
Expand All @@ -22,16 +18,11 @@ use crate::{
/// Decrypt using AES-256 in CBC mode.
///
/// Behaves similar to [decrypt_aes256_hmac], but does not validate the MAC.
pub(crate) fn decrypt_aes256(
iv: &[u8; 16],
data: Vec<u8>,
key: &GenericArray<u8, U32>,
) -> Result<Vec<u8>> {
pub(crate) fn decrypt_aes256(iv: &[u8; 16], data: Vec<u8>, key: &[u8; 32]) -> Result<Vec<u8>> {
// Decrypt data
let iv = GenericArray::from_slice(iv);
let mut data = data;
let decrypted_key_slice = cbc::Decryptor::<aes::Aes256>::new(key, iv)
.decrypt_padded_mut::<Pkcs7>(&mut data)
let decrypted_key_slice = cbc::Decryptor::<aes::Aes256>::new(key.as_ref(), iv.as_ref())
.decrypt_padded::<Pkcs7>(&mut data)
.map_err(|_| CryptoError::KeyDecrypt)?;

// Data is decrypted in place and returns a subslice of the original Vec, to avoid cloning it,
Expand All @@ -49,8 +40,8 @@ pub(crate) fn decrypt_aes256_hmac(
iv: &[u8; 16],
mac: &[u8; 32],
data: Vec<u8>,
mac_key: &GenericArray<u8, U32>,
key: &GenericArray<u8, U32>,
mac_key: &[u8; 32],
key: &[u8; 32],
) -> Result<Vec<u8>> {
let res = generate_mac(mac_key, iv, &data)?;
if res.ct_ne(mac).into() {
Expand All @@ -67,7 +58,7 @@ pub(crate) fn decrypt_aes256_hmac(
///
/// A AesCbc256_B64 EncString
#[allow(unused)]
pub(crate) fn encrypt_aes256(data_dec: &[u8], key: &GenericArray<u8, U32>) -> ([u8; 16], Vec<u8>) {
pub(crate) fn encrypt_aes256(data_dec: &[u8], key: &[u8; 32]) -> ([u8; 16], Vec<u8>) {
let rng = rand::thread_rng();
let (iv, data) = encrypt_aes256_internal(rng, data_dec, key);

Expand All @@ -83,8 +74,8 @@ pub(crate) fn encrypt_aes256(data_dec: &[u8], key: &GenericArray<u8, U32>) -> ([
/// A AesCbc256_HmacSha256_B64 EncString
pub(crate) fn encrypt_aes256_hmac(
data_dec: &[u8],
mac_key: &GenericArray<u8, U32>,
key: &GenericArray<u8, U32>,
mac_key: &[u8; 32],
key: &[u8; 32],
) -> Result<([u8; 16], [u8; 32], Vec<u8>)> {
let rng = rand::thread_rng();
let (iv, data) = encrypt_aes256_internal(rng, data_dec, key);
Expand All @@ -101,25 +92,24 @@ pub(crate) fn encrypt_aes256_hmac(
fn encrypt_aes256_internal(
mut rng: impl rand::RngCore,
data_dec: &[u8],
key: &GenericArray<u8, U32>,
key: &[u8; 32],
) -> ([u8; 16], Vec<u8>) {
let mut iv = [0u8; 16];
rng.fill_bytes(&mut iv);
let data = cbc::Encryptor::<aes::Aes256>::new(key, &iv.into())
.encrypt_padded_vec_mut::<Pkcs7>(data_dec);
let data = cbc::Encryptor::<aes::Aes256>::new(key.as_ref(), &iv.into())
.encrypt_padded_vec::<Pkcs7>(data_dec);

(iv, data)
}

/// Decrypt using AES-128 in CBC mode.
///
/// Behaves similar to [decrypt_aes128_hmac], but does not validate the MAC.
fn decrypt_aes128(iv: &[u8; 16], data: Vec<u8>, key: &GenericArray<u8, U16>) -> Result<Vec<u8>> {
fn decrypt_aes128(iv: &[u8; 16], data: Vec<u8>, key: &[u8; 16]) -> Result<Vec<u8>> {
// Decrypt data
let iv = GenericArray::from_slice(iv);
let mut data = data;
let decrypted_key_slice = cbc::Decryptor::<aes::Aes128>::new(key, iv)
.decrypt_padded_mut::<Pkcs7>(&mut data)
let decrypted_key_slice = cbc::Decryptor::<aes::Aes128>::new(key.as_ref(), iv.as_ref())
.decrypt_padded::<Pkcs7>(&mut data)
.map_err(|_| CryptoError::KeyDecrypt)?;

// Data is decrypted in place and returns a subslice of the original Vec, to avoid cloning it,
Expand All @@ -137,8 +127,8 @@ pub fn decrypt_aes128_hmac(
iv: &[u8; 16],
mac: &[u8; 32],
data: Vec<u8>,
mac_key: &GenericArray<u8, U16>,
key: &GenericArray<u8, U16>,
mac_key: &[u8; 16],
key: &[u8; 16],
) -> Result<Vec<u8>> {
let res = generate_mac(mac_key, iv, &data)?;
if res.ct_ne(mac).into() {
Expand All @@ -163,18 +153,18 @@ fn generate_mac(mac_key: &[u8], iv: &[u8], data: &[u8]) -> Result<[u8; 32]> {
#[cfg(test)]
mod tests {
use base64::{engine::general_purpose::STANDARD, Engine};
use generic_array::{sequence::GenericSequence, ArrayLength};
use rand::SeedableRng;

use super::*;

/// Helper function for generating a `GenericArray` of size 32 with each element being
/// Helper function for generating a `Array` of size 32 with each element being
/// a multiple of a given increment, starting from a given offset.
fn generate_generic_array<N: ArrayLength<u8>>(
offset: u8,
increment: u8,
) -> GenericArray<u8, N> {
GenericArray::generate(|i| offset + i as u8 * increment)
fn generate_generic_array<const N: usize>(offset: u8, increment: u8) -> [u8; N] {
let mut arr = [0u8; N];
for (i, item) in arr.iter_mut().enumerate() {
*item = offset + i as u8 * increment;
}
arr
}

/// Helper function for generating a vector of a given size with each element being
Expand Down
10 changes: 4 additions & 6 deletions crates/bitwarden-crypto/src/enc_string/symmetric.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use std::{fmt::Display, str::FromStr};

use aes::cipher::typenum::U32;
use base64::{engine::general_purpose::STANDARD, Engine};
use generic_array::GenericArray;
use serde::Deserialize;

use super::{check_length, from_b64, from_b64_vec, split_enc_string};
Expand Down Expand Up @@ -205,8 +203,8 @@ impl serde::Serialize for EncString {
impl EncString {
pub fn encrypt_aes256_hmac(
data_dec: &[u8],
mac_key: &GenericArray<u8, U32>,
key: &GenericArray<u8, U32>,
mac_key: &[u8; 32],
key: &[u8; 32],
) -> Result<EncString> {
let (iv, mac, data) = crate::aes::encrypt_aes256_hmac(data_dec, mac_key, key)?;
Ok(EncString::AesCbc256_HmacSha256_B64 { iv, mac, data })
Expand Down Expand Up @@ -245,8 +243,8 @@ impl KeyDecryptable<SymmetricCryptoKey, Vec<u8>> for EncString {
// variant uses a 16 byte key This means the key+mac are going to be
// parsed as a single 32 byte key, at the moment we split it manually
// When refactoring the key handling, this should be fixed.
let enc_key = key.key[0..16].into();
let mac_key = key.key[16..32].into();
let enc_key: &[u8; 16] = (&key.key[0..16]).try_into().expect("Valid size");
let mac_key: &[u8; 16] = (&key.key[16..32]).try_into().expect("Valid size");
let dec = crate::aes::decrypt_aes128_hmac(iv, mac, data.clone(), mac_key, enc_key)?;
Ok(dec)
}
Expand Down
13 changes: 5 additions & 8 deletions crates/bitwarden-crypto/src/keys/master_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ impl MasterKey {
password: &SensitiveVec,
purpose: HashPurpose,
) -> Result<SensitiveString> {
let hash = util::pbkdf2(&self.0.key, password.expose(), purpose as u32);
let hash = util::pbkdf2(self.0.key.as_slice(), password.expose(), purpose as u32);
Ok(hash.encode_base64(STANDARD))
}

Expand Down Expand Up @@ -224,13 +224,10 @@ mod tests {
let mut rng = rand_chacha::ChaCha8Rng::from_seed([0u8; 32]);

let master_key = MasterKey(SymmetricCryptoKey::new(
Box::pin(
[
31, 79, 104, 226, 150, 71, 177, 90, 194, 80, 172, 209, 17, 129, 132, 81, 138,
167, 69, 167, 254, 149, 2, 27, 39, 197, 64, 42, 22, 195, 86, 75,
]
.into(),
),
Box::pin([
31, 79, 104, 226, 150, 71, 177, 90, 194, 80, 172, 209, 17, 129, 132, 81, 138, 167,
69, 167, 254, 149, 2, 27, 39, 197, 64, 42, 22, 195, 86, 75,
]),
None,
));

Expand Down
7 changes: 2 additions & 5 deletions crates/bitwarden-crypto/src/keys/shareable_key.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use std::pin::Pin;

use aes::cipher::typenum::U64;
use generic_array::GenericArray;
use hmac::Mac;
use hmac::{KeyInit, Mac};
use zeroize::Zeroize;

use crate::{
Expand All @@ -27,8 +25,7 @@ pub fn derive_shareable_key(
.finalize()
.into_bytes();

let mut key: Pin<Box<GenericArray<u8, U64>>> =
hkdf_expand(&res, info).expect("Input is a valid size");
let mut key: Pin<Box<[u8; 64]>> = hkdf_expand(&res, info).expect("Input is a valid size");

// Zeroize the temporary buffer
res.zeroize();
Expand Down
27 changes: 11 additions & 16 deletions crates/bitwarden-crypto/src/keys/symmetric_crypto_key.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use std::pin::Pin;

use aes::cipher::typenum::U32;
use base64::engine::general_purpose::STANDARD;
use generic_array::GenericArray;
use rand::Rng;
use zeroize::Zeroize;

Expand All @@ -11,12 +9,12 @@ use crate::{CryptoError, Sensitive, SensitiveString, SensitiveVec};

/// A symmetric encryption key. Used to encrypt and decrypt [`EncString`](crate::EncString)
pub struct SymmetricCryptoKey {
// GenericArray is equivalent to [u8; N], which is a Copy type placed on the stack.
// [u8; N] is a Copy type placed on the stack.
// To keep the compiler from making stack copies when moving this struct around,
// we use a Box to keep the values on the heap. We also pin the box to make sure
// that the contents can't be pulled out of the box and moved
pub(crate) key: Pin<Box<GenericArray<u8, U32>>>,
pub(crate) mac_key: Option<Pin<Box<GenericArray<u8, U32>>>>,
pub(crate) key: Pin<Box<[u8; 32]>>,
pub(crate) mac_key: Option<Pin<Box<[u8; 32]>>>,
}

impl Drop for SymmetricCryptoKey {
Expand All @@ -36,8 +34,8 @@ impl SymmetricCryptoKey {

/// Generate a new random [SymmetricCryptoKey]
pub fn generate(mut rng: impl rand::RngCore) -> Self {
let mut key = Box::pin(GenericArray::<u8, U32>::default());
let mut mac_key = Box::pin(GenericArray::<u8, U32>::default());
let mut key = Box::pin([0u8; 32]);
let mut mac_key = Box::pin([0u8; 32]);

rng.fill(key.as_mut_slice());
rng.fill(mac_key.as_mut_slice());
Expand All @@ -48,10 +46,7 @@ impl SymmetricCryptoKey {
}
}

pub(crate) fn new(
key: Pin<Box<GenericArray<u8, U32>>>,
mac_key: Option<Pin<Box<GenericArray<u8, U32>>>>,
) -> Self {
pub(crate) fn new(key: Pin<Box<[u8; 32]>>, mac_key: Option<Pin<Box<[u8; 32]>>>) -> Self {
Self { key, mac_key }
}

Expand All @@ -66,9 +61,9 @@ impl SymmetricCryptoKey {
pub fn to_vec(&self) -> SensitiveVec {
let mut buf = SensitiveVec::new(Box::new(Vec::with_capacity(self.total_len())));

buf.expose_mut().extend_from_slice(&self.key);
buf.expose_mut().extend_from_slice(self.key.as_slice());
if let Some(mac) = &self.mac_key {
buf.expose_mut().extend_from_slice(mac);
buf.expose_mut().extend_from_slice(mac.as_slice());
}
buf
}
Expand Down Expand Up @@ -107,8 +102,8 @@ impl TryFrom<&mut [u8]> for SymmetricCryptoKey {
/// the data in it. This is to prevent the key from being left in memory.
fn try_from(value: &mut [u8]) -> Result<Self, Self::Error> {
let result = if value.len() == Self::KEY_LEN + Self::MAC_LEN {
let mut key = Box::pin(GenericArray::<u8, U32>::default());
let mut mac_key = Box::pin(GenericArray::<u8, U32>::default());
let mut key = Box::pin([0u8; 32]);
let mut mac_key = Box::pin([0u8; 32]);

key.copy_from_slice(&value[..Self::KEY_LEN]);
mac_key.copy_from_slice(&value[Self::KEY_LEN..]);
Expand All @@ -118,7 +113,7 @@ impl TryFrom<&mut [u8]> for SymmetricCryptoKey {
mac_key: Some(mac_key),
})
} else if value.len() == Self::KEY_LEN {
let mut key = Box::pin(GenericArray::<u8, U32>::default());
let mut key = Box::pin([0u8; 32]);

key.copy_from_slice(&value[..Self::KEY_LEN]);

Expand Down
16 changes: 6 additions & 10 deletions crates/bitwarden-crypto/src/keys/utils.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::pin::Pin;

use generic_array::{typenum::U32, GenericArray};
use sha2::Digest;

use crate::{util::hkdf_expand, Kdf, Result, Sensitive, SensitiveVec, SymmetricCryptoKey};
Expand Down Expand Up @@ -54,8 +53,8 @@ pub(super) fn derive_kdf_key(
}

pub(super) fn stretch_kdf_key(k: &SymmetricCryptoKey) -> Result<SymmetricCryptoKey> {
let key: Pin<Box<GenericArray<u8, U32>>> = hkdf_expand(&k.key, Some("enc"))?;
let mac_key: Pin<Box<GenericArray<u8, U32>>> = hkdf_expand(&k.key, Some("mac"))?;
let key: Pin<Box<[u8; 32]>> = hkdf_expand(k.key.as_slice(), Some("enc"))?;
let mac_key: Pin<Box<[u8; 32]>> = hkdf_expand(k.key.as_slice(), Some("mac"))?;

Ok(SymmetricCryptoKey::new(key, Some(mac_key)))
}
Expand All @@ -67,13 +66,10 @@ mod tests {
#[test]
fn test_stretch_kdf_key() {
let key = SymmetricCryptoKey::new(
Box::pin(
[
31, 79, 104, 226, 150, 71, 177, 90, 194, 80, 172, 209, 17, 129, 132, 81, 138,
167, 69, 167, 254, 149, 2, 27, 39, 197, 64, 42, 22, 195, 86, 75,
]
.into(),
),
Box::pin([
31, 79, 104, 226, 150, 71, 177, 90, 194, 80, 172, 209, 17, 129, 132, 81, 138, 167,
69, 167, 254, 149, 2, 27, 39, 197, 64, 42, 22, 195, 86, 75,
]),
None,
);

Expand Down
Loading

0 comments on commit 45e7416

Please sign in to comment.