Skip to content

Commit

Permalink
Initial work on TDE
Browse files Browse the repository at this point in the history
  • Loading branch information
Hinton committed Jan 12, 2024
1 parent bbc47bb commit 833d759
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 4 deletions.
109 changes: 109 additions & 0 deletions crates/bitwarden/src/crypto/device_key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use rsa::{
pkcs8::{DecodePrivateKey, EncodePrivateKey, EncodePublicKey},
Oaep, RsaPrivateKey,
};

use sha1::Sha1;

use super::{
rsa::generate_rsa, AsymmEncString, EncString, KeyDecryptable, KeyEncryptable,
SymmetricCryptoKey, UserKey,
};
use crate::error::Result;

/// Device Key
///
/// Encrypts the DevicePrivateKey
/// Allows the device to decrypt the UserKey, via the DevicePrivateKey.
#[derive(Debug)]
pub(crate) struct DeviceKey(SymmetricCryptoKey);

#[derive(Debug)]
struct CreateDeviceKey {
device_key: DeviceKey,
/// UserKey encrypted with DevicePublicKey
protected_user_key: AsymmEncString,
/// DevicePrivateKey encrypted with [DeviceKey]
protected_device_private_key: EncString,
/// DevicePublicKey encrypted with [UserKey](super::UserKey)
protected_device_public_key: EncString,
}

// We need to support the following scenarios:
//
// - Creating device key and encrypting users key
// - Decrypting users key using device key

impl DeviceKey {
/// Generate a new device key
fn trust_device(user_key: UserKey) -> Result<CreateDeviceKey> {
let device_key = DeviceKey(SymmetricCryptoKey::generate(rand::thread_rng()));

let device_private_key = generate_rsa();

let mut rng = rand::thread_rng();
let padding = Oaep::new::<Sha1>();

let protected_user_key = AsymmEncString::Rsa2048_OaepSha1_B64 {
data: device_private_key
.to_public_key()
.encrypt(&mut rng, padding, &user_key.0.key)
.map_err(|e| e.to_string())?,
};

let spki = device_private_key
.to_public_key()
.to_public_key_der()
.map_err(|_| "Invalid key")?;

let protected_device_public_key = spki.as_bytes().encrypt_with_key(&user_key.0)?;

let pkcs8 = device_private_key
.to_pkcs8_der()
.map_err(|_| "Invalid key")?;

let protected_device_private_key = pkcs8.as_bytes().encrypt_with_key(&device_key.0)?;

Ok(CreateDeviceKey {
device_key,
protected_user_key,
protected_device_private_key,
protected_device_public_key,
})
}

/// Decrypt the user key using the device key
async fn decrypt_user_key(
&self,
protected_device_private_key: EncString,
protected_user_key: AsymmEncString,
) -> Result<UserKey> {
let device_private_key: Vec<u8> = protected_device_private_key.decrypt_with_key(&self.0)?;
let device_private_key = RsaPrivateKey::from_pkcs8_der(device_private_key.as_slice())
.map_err(|e| e.to_string())?;

Check warning on line 83 in crates/bitwarden/src/crypto/device_key.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden/src/crypto/device_key.rs#L76-L83

Added lines #L76 - L83 were not covered by tests

let user_key: SymmetricCryptoKey = protected_user_key
.decrypt(&device_private_key)?
.as_slice()
.try_into()?;

Check warning on line 88 in crates/bitwarden/src/crypto/device_key.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden/src/crypto/device_key.rs#L85-L88

Added lines #L85 - L88 were not covered by tests

Ok(UserKey(user_key))
}

Check warning on line 91 in crates/bitwarden/src/crypto/device_key.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden/src/crypto/device_key.rs#L90-L91

Added lines #L90 - L91 were not covered by tests
}

#[cfg(test)]
mod tests {
use crate::crypto::symmetric_crypto_key::derive_symmetric_key;

use super::*;

#[test]
fn test_trust_device() {
let user_key = UserKey(derive_symmetric_key("test"));

// Call trust_device function
let result = DeviceKey::trust_device(user_key).unwrap();

println!("result: {:?}", result);
}
}
3 changes: 2 additions & 1 deletion crates/bitwarden/src/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ pub use symmetric_crypto_key::SymmetricCryptoKey;
mod shareable_key;
pub(crate) use shareable_key::derive_shareable_key;

#[cfg(feature = "internal")]
mod device_key;
#[cfg(feature = "internal")]
mod master_key;
#[cfg(feature = "internal")]
Expand All @@ -58,7 +60,6 @@ pub(crate) use user_key::UserKey;
mod rsa;
#[cfg(feature = "internal")]
pub use self::rsa::RsaKeyPair;

#[cfg(feature = "internal")]
mod fingerprint;
#[cfg(feature = "internal")]
Expand Down
12 changes: 9 additions & 3 deletions crates/bitwarden/src/crypto/rsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ pub struct RsaKeyPair {
}

pub(super) fn make_key_pair(key: &SymmetricCryptoKey) -> Result<RsaKeyPair> {
let mut rng = rand::thread_rng();
let bits = 2048;
let priv_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
let priv_key = generate_rsa();
let pub_key = RsaPublicKey::from(&priv_key);

let spki = pub_key
Expand All @@ -39,3 +37,11 @@ pub(super) fn make_key_pair(key: &SymmetricCryptoKey) -> Result<RsaKeyPair> {
private: protected,
})
}

// TODO: Move this to AsymmCryptoKey
/// Generate a new random AsymmetricCryptoKey (RSA-2048)
pub(crate) fn generate_rsa() -> RsaPrivateKey {
let mut rng = rand::thread_rng();
let bits = 2048;
RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key")
}

0 comments on commit 833d759

Please sign in to comment.