Skip to content

Commit

Permalink
Document and introduce type alias
Browse files Browse the repository at this point in the history
  • Loading branch information
Hinton committed Jan 25, 2024
1 parent c57bea6 commit d5f2ae5
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 15 deletions.
12 changes: 10 additions & 2 deletions crates/bitwarden-crypto/src/decrypted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ use zeroize::{Zeroize, ZeroizeOnDrop};

use crate::CryptoError;

/// A wrapper for decrypted values.
///
/// Implements `Zeroize` and `ZeroizeOnDrop` to ensure that the value is zeroized on drop. Please be careful if cloning or copying the inner value using `expose` since any copy will not be zeroized.
#[derive(Zeroize, ZeroizeOnDrop)]
pub struct Decrypted<V: Zeroize> {
value: V,
Expand All @@ -12,18 +15,23 @@ impl<V: Zeroize> Decrypted<V> {
Self { value }
}

/// Expose the inner value. By exposing the inner value, you take responsibility for ensuring that any copy of the value is zeroized.
pub fn expose(&self) -> &V {
&self.value
}
}

impl TryFrom<Decrypted<Vec<u8>>> for Decrypted<String> {
/// Helper to convert a `Decrypted<Vec<u8>>` to a `Decrypted<String>`, care is taken to ensure any intermediate copies are zeroed to avoid leaking sensitive data.
impl TryFrom<DecryptedVec> for DecryptedString {
type Error = CryptoError;

fn try_from(mut v: Decrypted<Vec<u8>>) -> Result<Self, CryptoError> {
fn try_from(mut v: DecryptedVec) -> Result<Self, CryptoError> {
let value = std::mem::take(&mut v.value);

let rtn = String::from_utf8(value).map_err(|_| CryptoError::InvalidUtf8String);
rtn.map(Decrypted::new)
}
}

pub type DecryptedVec = Decrypted<Vec<u8>>;
pub type DecryptedString = Decrypted<String>;
15 changes: 8 additions & 7 deletions crates/bitwarden-crypto/src/enc_string/symmetric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use serde::Deserialize;

use super::{check_length, from_b64, from_b64_vec, split_enc_string};
use crate::{
decrypted::{DecryptedString, DecryptedVec},
error::{CryptoError, EncStringParseError, Result},
Decrypted, KeyDecryptable, KeyEncryptable, LocateKey, SymmetricCryptoKey,
};
Expand Down Expand Up @@ -228,8 +229,8 @@ impl KeyEncryptable<SymmetricCryptoKey, EncString> for &[u8] {
}
}

impl KeyDecryptable<SymmetricCryptoKey, Decrypted<Vec<u8>>> for EncString {
fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result<Decrypted<Vec<u8>>> {
impl KeyDecryptable<SymmetricCryptoKey, DecryptedVec> for EncString {
fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result<DecryptedVec> {
match self {
EncString::AesCbc256_HmacSha256_B64 { iv, mac, data } => {
let mac_key = key.mac_key.ok_or(CryptoError::InvalidMac)?;
Expand All @@ -247,9 +248,9 @@ impl KeyEncryptable<SymmetricCryptoKey, EncString> for String {
}
}

impl KeyDecryptable<SymmetricCryptoKey, Decrypted<String>> for EncString {
fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result<Decrypted<String>> {
let dec: Decrypted<Vec<u8>> = self.decrypt_with_key(key)?;
impl KeyDecryptable<SymmetricCryptoKey, DecryptedString> for EncString {
fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result<DecryptedString> {
let dec: DecryptedVec = self.decrypt_with_key(key)?;
dec.try_into()
}
}
Expand All @@ -269,7 +270,7 @@ impl schemars::JsonSchema for EncString {
#[cfg(test)]
mod tests {
use super::EncString;
use crate::{derive_symmetric_key, Decrypted, KeyDecryptable, KeyEncryptable};
use crate::{decrypted::DecryptedString, derive_symmetric_key, KeyDecryptable, KeyEncryptable};

#[test]
fn test_enc_string_roundtrip() {
Expand All @@ -278,7 +279,7 @@ mod tests {
let test_string = "encrypted_test_string";
let cipher = test_string.to_owned().encrypt_with_key(&key).unwrap();

let decrypted_str: Decrypted<String> = cipher.decrypt_with_key(&key).unwrap();
let decrypted_str: DecryptedString = cipher.decrypt_with_key(&key).unwrap();
assert_eq!(decrypted_str.expose(), test_string);
}

Expand Down
10 changes: 6 additions & 4 deletions crates/bitwarden-crypto/src/keys/device_key.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
error::Result, AsymmetricCryptoKey, AsymmetricEncString, EncString, KeyDecryptable,
KeyEncryptable, SymmetricCryptoKey, UserKey,
decrypted::DecryptedVec, error::Result, AsymmetricCryptoKey, AsymmetricEncString, EncString,
KeyDecryptable, KeyEncryptable, SymmetricCryptoKey, UserKey,
};

/// Device Key
Expand Down Expand Up @@ -60,8 +60,10 @@ impl DeviceKey {
protected_device_private_key: EncString,
protected_user_key: AsymmetricEncString,
) -> Result<UserKey> {
let device_private_key: Vec<u8> = protected_device_private_key.decrypt_with_key(&self.0)?;
let device_private_key = AsymmetricCryptoKey::from_der(device_private_key.as_slice())?;
let device_private_key: DecryptedVec =
protected_device_private_key.decrypt_with_key(&self.0)?;
let device_private_key =
AsymmetricCryptoKey::from_der(device_private_key.expose().as_slice())?;

let dec: Vec<u8> = protected_user_key.decrypt_with_key(&device_private_key)?;
let user_key: SymmetricCryptoKey = dec.as_slice().try_into()?;
Expand Down
5 changes: 3 additions & 2 deletions crates/bitwarden-crypto/src/keys/master_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize};
use sha2::Digest;

use crate::{
decrypted::DecryptedVec,
util::{self, hkdf_expand},
EncString, KeyDecryptable, Result, SymmetricCryptoKey, UserKey,
};
Expand Down Expand Up @@ -59,8 +60,8 @@ impl MasterKey {
pub fn decrypt_user_key(&self, user_key: EncString) -> Result<SymmetricCryptoKey> {
let stretched_key = stretch_master_key(self)?;

let dec: Vec<u8> = user_key.decrypt_with_key(&stretched_key)?;
SymmetricCryptoKey::try_from(dec.as_slice())
let dec: DecryptedVec = user_key.decrypt_with_key(&stretched_key)?;
SymmetricCryptoKey::try_from(dec.expose().as_slice())
}

pub fn encrypt_user_key(&self, user_key: &SymmetricCryptoKey) -> Result<EncString> {
Expand Down

0 comments on commit d5f2ae5

Please sign in to comment.