Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
537 changes: 424 additions & 113 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions crates/bitwarden-core/src/auth/auth_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ impl AuthClient {

#[allow(missing_docs)]
pub fn make_key_connector_keys(&self) -> Result<KeyConnectorResponse, CryptoError> {
let mut rng = rand::thread_rng();
make_key_connector_keys(&mut rng)
make_key_connector_keys()
}

#[allow(missing_docs)]
Expand Down
26 changes: 2 additions & 24 deletions crates/bitwarden-core/src/auth/key_connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ pub struct KeyConnectorResponse {
pub keys: RsaKeyPair,
}

pub(super) fn make_key_connector_keys(
mut rng: impl rand::RngCore,
) -> Result<KeyConnectorResponse, CryptoError> {
let master_key = MasterKey::generate(&mut rng);
pub(super) fn make_key_connector_keys() -> Result<KeyConnectorResponse, CryptoError> {
let master_key = MasterKey::generate();
let (user_key, encrypted_user_key) = master_key.make_user_key()?;
let keys = user_key.make_key_pair()?;

Expand All @@ -22,23 +20,3 @@ pub(super) fn make_key_connector_keys(
keys,
})
}

#[cfg(test)]
mod tests {
use rand::SeedableRng;
use rand_chacha::ChaCha8Rng;

use super::*;

#[test]
fn test_make_key_connector_keys() {
let mut rng = ChaCha8Rng::from_seed([0u8; 32]);

let result = make_key_connector_keys(&mut rng).unwrap();

assert_eq!(
result.master_key.to_string(),
"PgDvL4lfQNZ/W7joHwmloSyEDsPOmn87GBvhiO9xGh4="
);
}
}
22 changes: 12 additions & 10 deletions crates/bitwarden-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,28 @@ bitwarden-encoding = { workspace = true }
bitwarden-error = { workspace = true }
bitwarden-uniffi-error = { workspace = true, optional = true }
cbc = { version = ">=0.1.2, <0.2", features = ["alloc", "zeroize"] }
chacha20poly1305 = { version = "0.10.1" }
chacha20poly1305 = { version = "0.11.0-rc.1" }
ciborium = { version = ">=0.2.2, <0.3" }
coset = { version = ">=0.3.8, <0.4" }
ed25519-dalek = { workspace = true, features = ["rand_core"] }
digest = { version = "=0.11.0-rc.3" }
ed25519-dalek = { version = "=3.0.0-pre.1", features = ["rand_core"] }
generic-array = { version = ">=0.14.7, <1.0", features = ["zeroize"] }
hkdf = ">=0.12.3, <0.13"
hmac = ">=0.12.1, <0.13"
hkdf = "=0.13.0-rc.2"
hmac = "=0.13.0-rc.2"
num-bigint = ">=0.4, <0.5"
num-traits = ">=0.2.15, <0.3"
pbkdf2 = { version = ">=0.12.1, <0.13", default-features = false }
rand = ">=0.8.5, <0.9"
rand_chacha = ">=0.3.1, <0.4.0"
pbkdf2 = { version = "=0.13.0-rc.1", default-features = false }
rand = "0.9.2"
rand_chacha = "=0.9.0"
rand_core = { version = "0.9.3", features = ["os_rng"] }
rayon = ">=1.8.1, <2.0"
rsa = ">=0.9.2, <0.10"
rsa = "=0.10.0-rc.9"
schemars = { workspace = true }
serde = { workspace = true }
serde_bytes = { workspace = true }
serde_repr.workspace = true
sha1 = ">=0.10.5, <0.11"
sha2 = ">=0.10.6, <0.11"
sha1 = "=0.11.0-rc.2"
sha2 = "=0.11.0-rc.2"
subtle = ">=2.5.0, <3.0"
thiserror = { workspace = true }
tsify = { workspace = true, optional = true }
Expand Down
4 changes: 2 additions & 2 deletions crates/bitwarden-crypto/src/aes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

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

Expand Down Expand Up @@ -66,7 +66,7 @@ pub(crate) fn encrypt_aes256_hmac(
mac_key: &GenericArray<u8, U32>,
key: &GenericArray<u8, U32>,
) -> Result<([u8; 16], [u8; 32], Vec<u8>)> {
let rng = rand::thread_rng();
let rng = rand::rng();
let (iv, data) = encrypt_aes256_internal(rng, data_dec, key);
let mac = generate_mac(mac_key, &iv, &data)?;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl CryptoKey for AsymmetricCryptoKey {}
impl AsymmetricCryptoKey {
/// Generate a random AsymmetricCryptoKey (RSA-2048).
pub fn make(algorithm: PublicKeyEncryptionAlgorithm) -> Self {
Self::make_internal(algorithm, &mut rand::thread_rng())
Self::make_internal(algorithm, &mut rand::rng())
}

fn make_internal<R: rand::CryptoRng + rand::RngCore>(
Expand Down
2 changes: 1 addition & 1 deletion crates/bitwarden-crypto/src/keys/key_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl KeyId {
// We do not use the uuid crate's random generation functionality here to make sure the
// entropy sampling aligns with the rest of this crates usage of CSPRNGs.
let mut random_seed = [0u8; UUID_SEED_SIZE];
rand::thread_rng().fill_bytes(&mut random_seed);
rand::rng().fill_bytes(&mut random_seed);

let uuid = uuid::Builder::from_random_bytes(random_seed)
.with_version(uuid::Version::Random)
Expand Down
12 changes: 8 additions & 4 deletions crates/bitwarden-crypto/src/keys/master_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::pin::Pin;

use bitwarden_encoding::B64;
use generic_array::GenericArray;
use rand::Rng;
use rand_core::CryptoRng;
use typenum::U32;
use zeroize::Zeroize;

Expand Down Expand Up @@ -40,10 +40,14 @@ impl MasterKey {
}

/// Generate a new random master key for KeyConnector.
pub fn generate(mut rng: impl rand::RngCore) -> Self {
pub fn generate() -> Self {
Self::generate_internal(&mut rand::rng())
}

pub(crate) fn generate_internal<R: CryptoRng + ?Sized>(csprng: &mut R) -> Self {
let mut key = Box::pin(GenericArray::<u8, U32>::default());

rng.fill(key.as_mut_slice());
csprng.fill_bytes(key.as_mut_slice());
Self::KeyConnectorKey(key)
}

Expand All @@ -70,7 +74,7 @@ impl MasterKey {

/// Generate a new random user key and encrypt it with the master key.
pub fn make_user_key(&self) -> Result<(UserKey, EncString)> {
make_user_key(rand::thread_rng(), self)
make_user_key(rand::rng(), self)
}

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

use generic_array::GenericArray;
use hmac::Mac;
use hmac::{KeyInit, Mac};
use typenum::{U32, U64};
use zeroize::{Zeroize, Zeroizing};

Expand All @@ -18,13 +18,11 @@ pub fn derive_shareable_key(
info: Option<&str>,
) -> Aes256CbcHmacKey {
// Because all inputs are fixed size, we can unwrap all errors here without issue
let res = Zeroizing::new(
PbkdfSha256Hmac::new_from_slice(format!("bitwarden-{name}").as_bytes())
.expect("hmac new_from_slice should not fail")
.chain_update(secret)
.finalize()
.into_bytes(),
);
let res = PbkdfSha256Hmac::new_from_slice(format!("bitwarden-{name}").as_bytes())
.expect("hmac new_from_slice should not fail")
.chain_update(secret)
.finalize()
.into_bytes();

let mut key: Pin<Box<GenericArray<u8, U64>>> =
hkdf_expand(&res, info).expect("Input is a valid size");
Expand Down
6 changes: 3 additions & 3 deletions crates/bitwarden-crypto/src/keys/symmetric_crypto_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub struct XChaCha20Poly1305Key {
impl XChaCha20Poly1305Key {
/// Creates a new XChaCha20Poly1305Key with a securely sampled cryptographic key and key id.
pub fn make() -> Self {
let mut rng = rand::thread_rng();
let mut rng = rand::rng();
let mut enc_key = Box::pin(GenericArray::<u8, U32>::default());
rng.fill(enc_key.as_mut_slice());
let mut key_id = [0u8; KEY_ID_SIZE];
Expand Down Expand Up @@ -155,13 +155,13 @@ impl SymmetricCryptoKey {

/// Generate a new random AES256_CBC_HMAC [SymmetricCryptoKey]
pub fn make_aes256_cbc_hmac_key() -> Self {
let rng = rand::thread_rng();
let rng = rand::rng();
Self::make_aes256_cbc_hmac_key_internal(rng)
}

/// Generate a new random XChaCha20Poly1305 [SymmetricCryptoKey]
pub fn make_xchacha20_poly1305_key() -> Self {
let mut rng = rand::thread_rng();
let mut rng = rand::rng();
let mut enc_key = Box::pin(GenericArray::<u8, U32>::default());
rng.fill(enc_key.as_mut_slice());
Self::XChaCha20Poly1305Key(XChaCha20Poly1305Key {
Expand Down
4 changes: 2 additions & 2 deletions crates/bitwarden-crypto/src/rsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub struct RsaKeyPair {

/// Generate a new RSA key pair of 2048 bits
pub(crate) fn make_key_pair(key: &SymmetricCryptoKey) -> Result<RsaKeyPair> {
let mut rng = rand::thread_rng();
let mut rng = rand::rng();
let bits = 2048;
let priv_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
let pub_key = RsaPublicKey::from(&priv_key);
Expand Down Expand Up @@ -56,7 +56,7 @@ pub(crate) fn make_key_pair(key: &SymmetricCryptoKey) -> Result<RsaKeyPair> {

/// Encrypt data using RSA-OAEP-SHA1 with a 2048 bit key
pub(super) fn encrypt_rsa2048_oaep_sha1(public_key: &RsaPublicKey, data: &[u8]) -> Result<Vec<u8>> {
let mut rng = rand::thread_rng();
let mut rng = rand::rng();

let padding = Oaep::new::<Sha1>();
public_key
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ impl TryInto<Argon2RawSettings> for &Header {

fn make_salt() -> [u8; ENVELOPE_ARGON2_SALT_SIZE] {
let mut salt = [0u8; ENVELOPE_ARGON2_SALT_SIZE];
rand::thread_rng().fill_bytes(&mut salt);
rand::rng().fill_bytes(&mut salt);
salt
}

Expand Down
2 changes: 1 addition & 1 deletion crates/bitwarden-crypto/src/signing/signing_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl SigningKey {
SignatureAlgorithm::Ed25519 => SigningKey {
id: KeyId::make(),
inner: RawSigningKey::Ed25519(Box::pin(ed25519_dalek::SigningKey::generate(
&mut rand::thread_rng(),
&mut rand::rng(),
))),
},
}
Expand Down
8 changes: 4 additions & 4 deletions crates/bitwarden-crypto/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use generic_array::GenericArray;
use hmac::digest::OutputSizeUser;
use rand::{
Rng,
distributions::{Alphanumeric, DistString, Distribution, Standard},
distr::{Alphanumeric, Distribution, SampleString, StandardUniform},
};
use zeroize::{Zeroize, Zeroizing};

Expand Down Expand Up @@ -33,18 +33,18 @@ pub(crate) fn hkdf_expand<T: ArrayLength<u8>>(
/// Generate random bytes that are cryptographically secure
pub fn generate_random_bytes<T>() -> Zeroizing<T>
where
Standard: Distribution<T>,
StandardUniform: Distribution<T>,
T: Zeroize,
{
Zeroizing::new(rand::thread_rng().r#gen::<T>())
Zeroizing::new(rand::rng().random())
}

/// Generate a random alphanumeric string of a given length
///
/// Note: Do not use this generating user facing passwords. Use the `bitwarden-generator` crate for
/// that.
pub fn generate_random_alphanumeric(len: usize) -> String {
Alphanumeric.sample_string(&mut rand::thread_rng(), len)
Alphanumeric.sample_string(&mut rand::rng(), len)
}

/// Derive pbkdf2 of a given password and salt
Expand Down
30 changes: 9 additions & 21 deletions crates/bitwarden-crypto/src/xchacha20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
//! `https://eprint.iacr.org/2019/016.pdf`
//! `https://soatok.blog/2024/09/10/invisible-salamanders-are-not-what-you-think/`

use chacha20poly1305::{AeadCore, AeadInPlace, KeyInit, XChaCha20Poly1305};
use generic_array::GenericArray;
use rand::{CryptoRng, RngCore};
use chacha20poly1305::{
AeadCore, KeyInit, XChaCha20Poly1305,
aead::{AeadInOut, array::Array},
};
use typenum::Unsigned;

use crate::CryptoError;
Expand All @@ -25,7 +26,7 @@ pub(crate) const NONCE_SIZE: usize = <XChaCha20Poly1305 as AeadCore>::NonceSize:
pub(crate) const KEY_SIZE: usize = 32;

pub(crate) struct XChaCha20Poly1305Ciphertext {
nonce: GenericArray<u8, <XChaCha20Poly1305 as AeadCore>::NonceSize>,
nonce: Array<u8, <XChaCha20Poly1305 as AeadCore>::NonceSize>,
encrypted_bytes: Vec<u8>,
}

Expand All @@ -44,20 +45,11 @@ pub(crate) fn encrypt_xchacha20_poly1305(
plaintext_secret_data: &[u8],
associated_data: &[u8],
) -> XChaCha20Poly1305Ciphertext {
let rng = rand::thread_rng();
encrypt_xchacha20_poly1305_internal(rng, key, plaintext_secret_data, associated_data)
}
let nonce = &XChaCha20Poly1305::generate_nonce().expect("nonce generation osrng cannot fail");

fn encrypt_xchacha20_poly1305_internal(
rng: impl RngCore + CryptoRng,
key: &[u8; KEY_SIZE],
plaintext_secret_data: &[u8],
associated_data: &[u8],
) -> XChaCha20Poly1305Ciphertext {
let nonce = &XChaCha20Poly1305::generate_nonce(rng);
// This buffer contains the plaintext, that will be encrypted in-place
let mut buffer = plaintext_secret_data.to_vec();
XChaCha20Poly1305::new(GenericArray::from_slice(key))
XChaCha20Poly1305::new(&Array::from(*key))
.encrypt_in_place(nonce, associated_data, &mut buffer)
.expect("encryption failed");

Expand All @@ -74,12 +66,8 @@ pub(crate) fn decrypt_xchacha20_poly1305(
associated_data: &[u8],
) -> Result<Vec<u8>, CryptoError> {
let mut buffer = ciphertext.to_vec();
XChaCha20Poly1305::new(GenericArray::from_slice(key))
.decrypt_in_place(
GenericArray::from_slice(nonce),
associated_data,
&mut buffer,
)
XChaCha20Poly1305::new(&Array::from(*key))
.decrypt_in_place(&Array::from(*nonce), associated_data, &mut buffer)
.map_err(|_| CryptoError::KeyDecrypt)?;
Ok(buffer)
}
Expand Down
Loading