Skip to content

Commit

Permalink
Add support for missing AES decrypt types
Browse files Browse the repository at this point in the history
  • Loading branch information
dani-garcia committed Feb 6, 2024
1 parent 1595306 commit a76b21b
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 2 deletions.
40 changes: 39 additions & 1 deletion crates/bitwarden-crypto/src/aes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
//! [KeyEncryptable][crate::KeyEncryptable] & [KeyDecryptable][crate::KeyDecryptable] instead.
use aes::cipher::{
block_padding::Pkcs7, typenum::U32, BlockDecryptMut, BlockEncryptMut, KeyIvInit,
block_padding::Pkcs7,
typenum::{U16, U32},
BlockDecryptMut, BlockEncryptMut, KeyIvInit,
};
use generic_array::GenericArray;
use hmac::Mac;
Expand Down Expand Up @@ -109,6 +111,42 @@ fn encrypt_aes256_internal(
(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>> {
// 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)
.map_err(|_| CryptoError::KeyDecrypt)?;

Check warning on line 123 in crates/bitwarden-crypto/src/aes.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/aes.rs#L117-L123

Added lines #L117 - L123 were not covered by tests

// Data is decrypted in place and returns a subslice of the original Vec, to avoid cloning it,
// we truncate to the subslice length
let decrypted_len = decrypted_key_slice.len();
data.truncate(decrypted_len);

Ok(data)
}

Check warning on line 131 in crates/bitwarden-crypto/src/aes.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/aes.rs#L127-L131

Added lines #L127 - L131 were not covered by tests

/// Decrypt using AES-128 in CBC mode with MAC.
///
/// Behaves similar to [decrypt_aes128], but also validates the MAC.
pub fn decrypt_aes128_hmac(
iv: &[u8; 16],
mac: &[u8; 32],
data: Vec<u8>,
mac_key: &GenericArray<u8, U16>,
key: &GenericArray<u8, U16>,
) -> Result<Vec<u8>> {
let res = generate_mac(mac_key, iv, &data)?;
if res.ct_ne(mac).into() {
return Err(CryptoError::InvalidMac);
}
decrypt_aes128(iv, data, key)
}

Check warning on line 148 in crates/bitwarden-crypto/src/aes.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/aes.rs#L136-L148

Added lines #L136 - L148 were not covered by tests

/// Generate a MAC using HMAC-SHA256.
fn generate_mac(mac_key: &[u8], iv: &[u8], data: &[u8]) -> Result<[u8; 32]> {
let mut hmac = PbkdfSha256Hmac::new_from_slice(mac_key).expect("HMAC can take key of any size");
Expand Down
15 changes: 14 additions & 1 deletion crates/bitwarden-crypto/src/enc_string/symmetric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,26 @@ impl KeyEncryptable<SymmetricCryptoKey, EncString> for &[u8] {
impl KeyDecryptable<SymmetricCryptoKey, Vec<u8>> for EncString {
fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result<Vec<u8>> {
match self {
EncString::AesCbc256_B64 { iv, data } => {
let dec = crate::aes::decrypt_aes256(iv, data.clone(), &key.key)?;
Ok(dec)

Check warning on line 241 in crates/bitwarden-crypto/src/enc_string/symmetric.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/enc_string/symmetric.rs#L239-L241

Added lines #L239 - L241 were not covered by tests
}
EncString::AesCbc128_HmacSha256_B64 { iv, mac, data } => {
// TODO: SymmetricCryptoKey is designed to handle 32 byte keys only, but this
// 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 dec = crate::aes::decrypt_aes128_hmac(iv, mac, data.clone(), mac_key, enc_key)?;
Ok(dec)

Check warning on line 251 in crates/bitwarden-crypto/src/enc_string/symmetric.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/enc_string/symmetric.rs#L243-L251

Added lines #L243 - L251 were not covered by tests
}
EncString::AesCbc256_HmacSha256_B64 { iv, mac, data } => {
let mac_key = key.mac_key.as_ref().ok_or(CryptoError::InvalidMac)?;
let dec =
crate::aes::decrypt_aes256_hmac(iv, mac, data.clone(), mac_key, &key.key)?;
Ok(dec)
}
_ => Err(CryptoError::InvalidKey),
}
}
}
Expand Down

0 comments on commit a76b21b

Please sign in to comment.