Skip to content

Commit d47e8c0

Browse files
committed
Switch bitwarden symmetric crypto key bytes to serialized bytes generic
1 parent 99d909c commit d47e8c0

File tree

9 files changed

+271
-156
lines changed

9 files changed

+271
-156
lines changed

crates/bitwarden-core/src/auth/auth_request.rs

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -106,44 +106,48 @@ pub(crate) fn approve_auth_request(
106106
)?)
107107
}
108108

109-
#[test]
110-
fn test_auth_request() {
111-
let request = new_auth_request("[email protected]").unwrap();
112-
113-
let secret = vec![
114-
111, 32, 97, 169, 4, 241, 174, 74, 239, 206, 113, 86, 174, 68, 216, 238, 52, 85, 156, 27,
115-
134, 149, 54, 55, 91, 147, 45, 130, 131, 237, 51, 31, 191, 106, 155, 14, 160, 82, 47, 40,
116-
96, 31, 114, 127, 212, 187, 167, 110, 205, 116, 198, 243, 218, 72, 137, 53, 248, 43, 255,
117-
67, 35, 61, 245, 93,
118-
];
119-
120-
let private_key =
121-
AsymmetricCryptoKey::from_der(&STANDARD.decode(&request.private_key).unwrap().into())
122-
.unwrap();
123-
124-
let encrypted = UnsignedSharedKey::encapsulate_key_unsigned(
125-
&SymmetricCryptoKey::try_from(secret.clone()).unwrap(),
126-
&private_key.to_public_key(),
127-
)
128-
.unwrap();
129-
130-
let decrypted = auth_request_decrypt_user_key(request.private_key, encrypted).unwrap();
131-
132-
assert_eq!(decrypted.to_encoded(), secret);
133-
}
134-
135109
#[cfg(test)]
136110
mod tests {
137111
use std::num::NonZeroU32;
138112

139-
use bitwarden_crypto::{Kdf, MasterKey, SerializedBytes, SpkiPublicKeyDerContentFormat};
113+
use bitwarden_crypto::{
114+
BitwardenLegacyKeyContentFormat, Kdf, MasterKey, SerializedBytes,
115+
SpkiPublicKeyDerContentFormat,
116+
};
140117

141118
use super::*;
142119
use crate::key_management::{
143120
crypto::{AuthRequestMethod, InitUserCryptoMethod, InitUserCryptoRequest},
144121
SymmetricKeyId,
145122
};
146123

124+
#[test]
125+
fn test_auth_request() {
126+
let request = new_auth_request("[email protected]").unwrap();
127+
128+
let secret = vec![
129+
111, 32, 97, 169, 4, 241, 174, 74, 239, 206, 113, 86, 174, 68, 216, 238, 52, 85, 156,
130+
27, 134, 149, 54, 55, 91, 147, 45, 130, 131, 237, 51, 31, 191, 106, 155, 14, 160, 82,
131+
47, 40, 96, 31, 114, 127, 212, 187, 167, 110, 205, 116, 198, 243, 218, 72, 137, 53,
132+
248, 43, 255, 67, 35, 61, 245, 93,
133+
];
134+
135+
let private_key =
136+
AsymmetricCryptoKey::from_der(&STANDARD.decode(&request.private_key).unwrap().into())
137+
.unwrap();
138+
139+
let secret = SerializedBytes::<BitwardenLegacyKeyContentFormat>::from(secret);
140+
let encrypted = UnsignedSharedKey::encapsulate_key_unsigned(
141+
&SymmetricCryptoKey::try_from(&secret).unwrap(),
142+
&private_key.to_public_key(),
143+
)
144+
.unwrap();
145+
146+
let decrypted = auth_request_decrypt_user_key(request.private_key, encrypted).unwrap();
147+
148+
assert_eq!(decrypted.to_encoded().to_vec(), secret.to_vec());
149+
}
150+
147151
#[test]
148152
fn test_approve() {
149153
let client = Client::new(None);
@@ -183,7 +187,7 @@ mod tests {
183187
let dec = auth_request_decrypt_user_key(private_key.to_owned(), enc_user_key).unwrap();
184188

185189
assert_eq!(
186-
&dec.to_encoded(),
190+
&dec.to_encoded().to_vec(),
187191
&[
188192
201, 37, 234, 213, 21, 75, 40, 70, 149, 213, 234, 16, 19, 251, 162, 245, 161, 74,
189193
34, 245, 211, 151, 211, 192, 95, 10, 117, 50, 88, 223, 23, 157
@@ -202,7 +206,7 @@ mod tests {
202206
.unwrap();
203207

204208
assert_eq!(
205-
&dec.to_encoded(),
209+
&dec.to_encoded().to_vec(),
206210
&[
207211
109, 128, 172, 147, 206, 123, 134, 95, 16, 36, 155, 113, 201, 18, 186, 230, 216,
208212
212, 173, 188, 74, 11, 134, 131, 137, 242, 105, 178, 105, 126, 52, 139, 248, 91,

crates/bitwarden-core/src/auth/login/access_token.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use std::path::{Path, PathBuf};
22

33
use base64::{engine::general_purpose::STANDARD, Engine};
4-
use bitwarden_crypto::{EncString, KeyDecryptable, SymmetricCryptoKey};
4+
use bitwarden_crypto::{
5+
BitwardenLegacyKeyContentFormat, EncString, KeyDecryptable, SerializedBytes, SymmetricCryptoKey,
6+
};
57
use chrono::Utc;
68
use schemars::JsonSchema;
79
use serde::{Deserialize, Serialize};
@@ -67,7 +69,9 @@ pub(crate) async fn login_access_token(
6769

6870
let payload: Payload = serde_json::from_slice(&decrypted_payload)?;
6971
let encryption_key = STANDARD.decode(&payload.encryption_key)?;
70-
let encryption_key = SymmetricCryptoKey::try_from(encryption_key)?;
72+
let encryption_key =
73+
SerializedBytes::<BitwardenLegacyKeyContentFormat>::from(encryption_key);
74+
let encryption_key = SymmetricCryptoKey::try_from(&encryption_key)?;
7175

7276
let access_token_obj: JwtToken = r.access_token.parse()?;
7377

crates/bitwarden-crypto/src/content_format.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ impl<C: ConstContentFormat> AsRef<[u8]> for SerializedBytes<C> {
7979
}
8080
}
8181

82+
impl<C: ConstContentFormat> SerializedBytes<C> {
83+
/// Returns the serialized bytes as a `Vec<u8>`.
84+
pub fn to_vec(&self) -> Vec<u8> {
85+
self.inner.clone()
86+
}
87+
}
88+
8289
/// Content format for UTF-8 encoded text. Used for most text messages.
8390
#[derive(PartialEq, Eq, Clone, Debug)]
8491
pub(crate) struct Utf8ContentFormat;
@@ -128,7 +135,7 @@ impl CoseContentFormat for CoseKeyContentFormat {}
128135
/// A legacy content format for Bitwarden keys. See `ContentFormat::BitwardenLegacyKey`
129136
#[allow(unused)]
130137
#[derive(PartialEq, Eq, Clone, Debug)]
131-
pub(crate) struct BitwardenLegacyKeyContentFormat;
138+
pub struct BitwardenLegacyKeyContentFormat;
132139
impl ConstContentFormat for BitwardenLegacyKeyContentFormat {
133140
fn content_format() -> ContentFormat {
134141
ContentFormat::BitwardenLegacyKey

crates/bitwarden-crypto/src/enc_string/asymmetric.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use crate::{
1010
error::{CryptoError, EncStringParseError, Result},
1111
rsa::encrypt_rsa2048_oaep_sha1,
1212
util::FromStrVisitor,
13-
AsymmetricCryptoKey, AsymmetricPublicCryptoKey, RawPrivateKey, RawPublicKey,
14-
SymmetricCryptoKey,
13+
AsymmetricCryptoKey, AsymmetricPublicCryptoKey, BitwardenLegacyKeyContentFormat, RawPrivateKey,
14+
RawPublicKey, SerializedBytes, SymmetricCryptoKey,
1515
};
1616
// This module is a workaround to avoid deprecated warnings that come from the ZeroizeOnDrop
1717
// macro expansion
@@ -169,7 +169,7 @@ impl UnsignedSharedKey {
169169
Ok(UnsignedSharedKey::Rsa2048_OaepSha1_B64 {
170170
data: encrypt_rsa2048_oaep_sha1(
171171
rsa_public_key,
172-
&encapsulated_key.to_encoded(),
172+
&encapsulated_key.to_encoded().as_ref().to_vec(),
173173
)?,
174174
})
175175
}
@@ -200,7 +200,7 @@ impl UnsignedSharedKey {
200200
match decapsulation_key.inner() {
201201
RawPrivateKey::RsaOaepSha1(rsa_private_key) => {
202202
use UnsignedSharedKey::*;
203-
let mut key_data = match self {
203+
let key_data = match self {
204204
Rsa2048_OaepSha256_B64 { data } => {
205205
rsa_private_key.decrypt(Oaep::new::<sha2::Sha256>(), data)
206206
}
@@ -217,7 +217,9 @@ impl UnsignedSharedKey {
217217
}
218218
}
219219
.map_err(|_| CryptoError::KeyDecrypt)?;
220-
SymmetricCryptoKey::try_from(key_data.as_mut_slice())
220+
SymmetricCryptoKey::try_from(
221+
&SerializedBytes::<BitwardenLegacyKeyContentFormat>::from(key_data),
222+
)
221223
}
222224
}
223225
}

crates/bitwarden-crypto/src/keys/device_key.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ impl TryFrom<String> for DeviceKey {
9191
#[cfg(test)]
9292
mod tests {
9393
use super::*;
94-
use crate::derive_symmetric_key;
94+
use crate::{derive_symmetric_key, BitwardenLegacyKeyContentFormat};
9595

9696
#[test]
9797
fn test_trust_device() {
@@ -114,21 +114,29 @@ mod tests {
114114
#[test]
115115
fn test_decrypt_user_key() {
116116
// Example keys from desktop app
117-
let user_key: &mut [u8] = &mut [
117+
let user_key: &[u8] = &[
118118
109, 128, 172, 147, 206, 123, 134, 95, 16, 36, 155, 113, 201, 18, 186, 230, 216, 212,
119119
173, 188, 74, 11, 134, 131, 137, 242, 105, 178, 105, 126, 52, 139, 248, 91, 215, 21,
120120
128, 91, 226, 222, 165, 67, 251, 34, 83, 81, 77, 147, 225, 76, 13, 41, 102, 45, 183,
121121
218, 106, 89, 254, 208, 251, 101, 130, 10,
122122
];
123-
let user_key = SymmetricCryptoKey::try_from(user_key).unwrap();
123+
let user_key = SymmetricCryptoKey::try_from(&SerializedBytes::<
124+
BitwardenLegacyKeyContentFormat,
125+
>::from(user_key))
126+
.unwrap();
124127

125-
let key_data: &mut [u8] = &mut [
128+
let key_data: &[u8] = &[
126129
114, 235, 60, 115, 172, 156, 203, 145, 195, 130, 215, 250, 88, 146, 215, 230, 12, 109,
127130
245, 222, 54, 217, 255, 211, 221, 105, 230, 236, 65, 52, 209, 133, 76, 208, 113, 254,
128131
194, 216, 156, 19, 230, 62, 32, 93, 87, 7, 144, 156, 117, 142, 250, 32, 182, 118, 187,
129132
8, 247, 7, 203, 201, 65, 147, 206, 247,
130133
];
131-
let device_key = DeviceKey(key_data.try_into().unwrap());
134+
let device_key = DeviceKey(
135+
SymmetricCryptoKey::try_from(
136+
&SerializedBytes::<BitwardenLegacyKeyContentFormat>::from(key_data),
137+
)
138+
.unwrap(),
139+
);
132140

133141
let protected_user_key: UnsignedSharedKey = "4.f+VbbacRhO2q4MOUSdt1AIjQ2FuLAvg4aDxJMXAh3VxvbmUADj8Ct/R7XEpPUqApmbRS566jS0eRVy8Sk08ogoCdj1IFN9VsIky2i2X1WHK1fUnr3UBmXE3tl2NPBbx56U+h73S2jNTSyet2W18Jg2q7/w8KIhR3J41QrG9aGoOTN93to3hb5W4z6rdrSI0e7GkizbwcIA0NH7Z1JyAhrjPm9+tjRjg060YbEbGaWTAOkZWfgbLjr8bY455DteO2xxG139cOx7EBo66N+YhjsLi0ozkeUyPQkoWBdKMcQllS7jCfB4fDyJA05ALTbk74syKkvqFxqwmQbg+aVn+dcw==".parse().unwrap();
134142

crates/bitwarden-crypto/src/keys/master_key.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@ use base64::{engine::general_purpose::STANDARD, Engine};
44
use generic_array::GenericArray;
55
use rand::Rng;
66
use typenum::U32;
7-
use zeroize::{Zeroize, Zeroizing};
7+
use zeroize::Zeroize;
88

99
use super::{
1010
kdf::{Kdf, KdfDerivedKeyMaterial},
1111
utils::stretch_key,
1212
};
1313
use crate::{
1414
util::{self},
15-
CryptoError, EncString, KeyDecryptable, Result, SymmetricCryptoKey, UserKey,
15+
BitwardenLegacyKeyContentFormat, CryptoError, EncString, KeyDecryptable, Result,
16+
SerializedBytes, SymmetricCryptoKey, UserKey,
1617
};
1718

1819
#[allow(missing_docs)]
@@ -129,16 +130,16 @@ pub(super) fn encrypt_user_key(
129130
user_key: &SymmetricCryptoKey,
130131
) -> Result<EncString> {
131132
let stretched_master_key = stretch_key(master_key)?;
132-
let user_key_bytes = Zeroizing::new(user_key.to_encoded());
133-
EncString::encrypt_aes256_hmac(&user_key_bytes, &stretched_master_key)
133+
let user_key_bytes = user_key.to_encoded();
134+
EncString::encrypt_aes256_hmac(user_key_bytes.as_ref(), &stretched_master_key)
134135
}
135136

136137
/// Helper function to decrypt a user key with a master or pin key or key-connector-key.
137138
pub(super) fn decrypt_user_key(
138139
key: &Pin<Box<GenericArray<u8, U32>>>,
139140
user_key: EncString,
140141
) -> Result<SymmetricCryptoKey> {
141-
let mut dec: Vec<u8> = match user_key {
142+
let dec: Vec<u8> = match user_key {
142143
// Legacy. user_keys were encrypted using `Aes256Cbc_B64` a long time ago. We've since
143144
// moved to using `Aes256Cbc_HmacSha256_B64`. However, we still need to support
144145
// decrypting these old keys.
@@ -159,7 +160,9 @@ pub(super) fn decrypt_user_key(
159160
}
160161
};
161162

162-
SymmetricCryptoKey::try_from(dec.as_mut_slice())
163+
SymmetricCryptoKey::try_from(&SerializedBytes::<BitwardenLegacyKeyContentFormat>::from(
164+
dec,
165+
))
163166
}
164167

165168
/// Generate a new random user key and encrypt it with the master key.

0 commit comments

Comments
 (0)