Skip to content

Commit

Permalink
Add support for Hmac org keys (#435)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hinton authored Dec 15, 2023
1 parent 7ec2183 commit e6d0759
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 11 deletions.
11 changes: 2 additions & 9 deletions crates/bitwarden/src/client/encryption_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use {
crypto::{EncString, KeyDecryptable},
error::{CryptoError, Result},
},
rsa::{pkcs8::DecodePrivateKey, Oaep},
rsa::pkcs8::DecodePrivateKey,
};

use crate::crypto::SymmetricCryptoKey;
Expand Down Expand Up @@ -96,14 +96,7 @@ impl EncryptionSettings {

// Decrypt the org keys with the private key
for (org_id, org_enc_key) in org_enc_keys {
let data = match org_enc_key {
EncString::Rsa2048_OaepSha1_B64 { data } => data,
_ => return Err(CryptoError::InvalidKey.into()),
};

let dec = private_key
.decrypt(Oaep::new::<sha1::Sha1>(), &data)
.map_err(|_| CryptoError::KeyDecrypt)?;
let dec = org_enc_key.decrypt_with_private_key(private_key)?;

let org_key = SymmetricCryptoKey::try_from(dec.as_slice())?;

Expand Down
73 changes: 71 additions & 2 deletions crates/bitwarden/src/crypto/enc_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use std::{fmt::Display, str::FromStr};

use aes::cipher::{generic_array::GenericArray, typenum::U32};
use base64::Engine;
#[cfg(feature = "internal")]
use rsa::{Oaep, RsaPrivateKey};
use serde::{de::Visitor, Deserialize};

use super::{KeyDecryptable, KeyEncryptable, LocateKey};
Expand Down Expand Up @@ -144,12 +146,12 @@ impl FromStr for EncString {
Ok(EncString::Rsa2048_OaepSha1_B64 { data })
}
#[allow(deprecated)]
("5", 1) => {
("5", 2) => {
let data = from_b64_vec(parts[0])?;
Ok(EncString::Rsa2048_OaepSha256_HmacSha256_B64 { data })
}
#[allow(deprecated)]
("6", 1) => {
("6", 2) => {
let data = from_b64_vec(parts[0])?;
Ok(EncString::Rsa2048_OaepSha1_HmacSha256_B64 { data })
}
Expand All @@ -170,6 +172,29 @@ impl EncString {
s.map(|s| s.parse()).transpose()
}

/// TODO: Convert this to a trait method
#[cfg(feature = "internal")]
pub(crate) fn decrypt_with_private_key(&self, key: &RsaPrivateKey) -> Result<Vec<u8>> {
Ok(match self {
EncString::Rsa2048_OaepSha256_B64 { data } => {
key.decrypt(Oaep::new::<sha2::Sha256>(), data)
}
EncString::Rsa2048_OaepSha1_B64 { data } => {
key.decrypt(Oaep::new::<sha1::Sha1>(), data)
}
#[allow(deprecated)]
EncString::Rsa2048_OaepSha256_HmacSha256_B64 { data } => {
key.decrypt(Oaep::new::<sha2::Sha256>(), data)
}
#[allow(deprecated)]
EncString::Rsa2048_OaepSha1_HmacSha256_B64 { data } => {
key.decrypt(Oaep::new::<sha1::Sha1>(), data)
}
_ => return Err(CryptoError::InvalidKey.into()),
}
.map_err(|_| CryptoError::KeyDecrypt)?)
}

#[cfg(feature = "mobile")]
pub(crate) fn from_buffer(buf: &[u8]) -> Result<Self> {
if buf.is_empty() {
Expand Down Expand Up @@ -430,6 +455,50 @@ mod tests {
assert_eq!(decrypted_str, test_string);
}

#[cfg(feature = "internal")]
#[test]
fn test_enc_string_rsa2048_oaep_sha1_hmac_sha256_b64() {
use rsa::{pkcs8::DecodePrivateKey, RsaPrivateKey};

let rsa_private_key: &str = "-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXRVrCX+2hfOQS
8HzYUS2oc/jGVTZpv+/Ryuoh9d8ihYX9dd0cYh2tl6KWdFc88lPUH11Oxqy20Rk2
e5r/RF6T9yM0Me3NPnaKt+hlhLtfoc0h86LnhD56A9FDUfuI0dVnPcrwNv0YJIo9
4LwxtbqBULNvXl6wJ7WAbODrCQy5ZgMVg+iH+gGpwiqsZqHt+KuoHWcN53MSPDfa
F4/YMB99U3TziJMOOJask1TEEnakMPln11PczNDazT17DXIxYrbPfutPdh6sLs6A
QOajdZijfEvepgnOe7cQ7aeatiOJFrjTApKPGxOVRzEMX4XS4xbyhH0QxQeB6l16
l8C0uxIBAgMBAAECggEASaWfeVDA3cVzOPFSpvJm20OTE+R6uGOU+7vh36TX/POq
92qBuwbd0h0oMD32FxsXywd2IxtBDUSiFM9699qufTVuM0Q3tZw6lHDTOVG08+tP
dr8qSbMtw7PGFxN79fHLBxejjO4IrM9lapjWpxEF+11x7r+wM+0xRZQ8sNFYG46a
PfIaty4BGbL0I2DQ2y8I57iBCAy69eht59NLMm27fRWGJIWCuBIjlpfzET1j2HLX
UIh5bTBNzqaN039WH49HczGE3mQKVEJZc/efk3HaVd0a1Sjzyn0QY+N1jtZN3jTR
buDWA1AknkX1LX/0tUhuS3/7C3ejHxjw4Dk1ZLo5/QKBgQDIWvqFn0+IKRSu6Ua2
hDsufIHHUNLelbfLUMmFthxabcUn4zlvIscJO00Tq/ezopSRRvbGiqnxjv/mYxuc
vOUBeZtlus0Q9RTACBtw9TGoNTmQbEunJ2FOSlqbQxkBBAjgGEppRPt30iGj/VjA
hCATq2MYOa/X4dVR51BqQAFIEwKBgQDBSIfTFKC/hDk6FKZlgwvupWYJyU9Rkyfs
tPErZFmzoKhPkQ3YORo2oeAYmVUbS9I2iIYpYpYQJHX8jMuCbCz4ONxTCuSIXYQY
UcUq4PglCKp31xBAE6TN8SvhfME9/MvuDssnQinAHuF0GDAhF646T3LLS1not6Vs
zv7brwSoGwKBgQC88v/8cGfi80ssQZeMnVvq1UTXIeQcQnoY5lGHJl3K8mbS3TnX
E6c9j417Fdz+rj8KWzBzwWXQB5pSPflWcdZO886Xu/mVGmy9RWgLuVFhXwCwsVEP
jNX5ramRb0/vY0yzenUCninBsIxFSbIfrPtLUYCc4hpxr+sr2Mg/y6jpvQKBgBez
MRRs3xkcuXepuI2R+BCXL1/b02IJTUf1F+1eLLGd7YV0H+J3fgNc7gGWK51hOrF9
JBZHBGeOUPlaukmPwiPdtQZpu4QNE3l37VlIpKTF30E6mb+BqR+nht3rUjarnMXg
AoEZ18y6/KIjpSMpqC92Nnk/EBM9EYe6Cf4eA9ApAoGAeqEUg46UTlJySkBKURGp
Is3v1kkf5I0X8DnOhwb+HPxNaiEdmO7ckm8+tPVgppLcG0+tMdLjigFQiDUQk2y3
WjyxP5ZvXu7U96jaJRI8PFMoE06WeVYcdIzrID2HvqH+w0UQJFrLJ/0Mn4stFAEz
XKZBokBGnjFnTnKcs7nv/O8=
-----END PRIVATE KEY-----";
let private_key = RsaPrivateKey::from_pkcs8_pem(rsa_private_key).unwrap();
let enc_str: &str = "6.ThnNc67nNr7GELyuhGGfsXNP2zJnNqhrIsjntEQ27r2qmn8vwdHbTbfO0cwt6YgSibDN0PjiCZ1O3Wb/IFq+vwvyRwFqF9145wBF8CQCbkhV+M0XvO99kh0daovtt120Nve/5ETI5PbPag9VdalKRQWZypJaqQHm5TAQVf4F5wtLlCLMBkzqTk+wkFe7BPMTGn07T+O3eJbTxXvyMZewQ7icJF0MZVA7VyWX9qElmZ89FCKowbf1BMr5pbcQ+0KdXcSVW3to43VkTp7k7COwsuH3M/i1AuVP5YN8ixjyRpvaeGqX/ap2nCHK2Wj5VxgCGT7XEls6ZknnAp9nB9qVjQ==|s3ntw5H/KKD/qsS0lUghTHl5Sm9j6m7YEdNHf0OeAFQ=";
let enc_string: EncString = enc_str.parse().unwrap();

assert_eq!(enc_string.enc_type(), 6);

let res = enc_string.decrypt_with_private_key(&private_key).unwrap();

assert_eq!(std::str::from_utf8(&res).unwrap(), "EncryptMe!");
}

#[test]
fn test_enc_string_serialization() {
#[derive(serde::Serialize, serde::Deserialize)]
Expand Down

0 comments on commit e6d0759

Please sign in to comment.