From 7eea3010ea21f78ed8ba3f0dcb09e2e9f6a964a7 Mon Sep 17 00:00:00 2001 From: Hinton Date: Fri, 17 May 2024 16:43:41 +0200 Subject: [PATCH] Revert "[PM-5791] Change decrypt to return Sensitive (#536)" --- Cargo.lock | 1 - .../src/enc_string/asymmetric.rs | 42 ++- .../src/enc_string/symmetric.rs | 49 ++-- .../src/keys/asymmetric_crypto_key.rs | 134 ++++----- .../bitwarden-crypto/src/keys/device_key.rs | 8 +- .../bitwarden-crypto/src/keys/master_key.rs | 7 +- crates/bitwarden-crypto/src/lib.rs | 8 +- .../src/sensitive/sensitive.rs | 19 -- crates/bitwarden-exporters/Cargo.toml | 1 - crates/bitwarden-exporters/src/csv.rs | 69 ++--- .../bitwarden-exporters/src/encrypted_json.rs | 64 ++--- crates/bitwarden-exporters/src/json.rs | 193 +++++++------ crates/bitwarden-exporters/src/lib.rs | 68 ++--- crates/bitwarden/src/auth/auth_request.rs | 25 +- .../bitwarden/src/auth/login/access_token.rs | 9 +- crates/bitwarden/src/auth/tde.rs | 10 +- .../src/client/encryption_settings.rs | 12 +- crates/bitwarden/src/mobile/crypto.rs | 21 +- .../src/mobile/vault/client_attachments.rs | 1 - .../src/mobile/vault/client_sends.rs | 5 +- .../src/platform/fido2/authenticator.rs | 4 +- crates/bitwarden/src/platform/fido2/client.rs | 10 +- .../projects/project_response.rs | 6 +- .../src/secrets_manager/secrets/list.rs | 6 +- .../secrets/secret_response.rs | 14 +- crates/bitwarden/src/secrets_manager/state.rs | 9 +- crates/bitwarden/src/tool/exporters/mod.rs | 18 +- .../bitwarden/src/vault/cipher/attachment.rs | 15 +- crates/bitwarden/src/vault/cipher/card.rs | 14 +- crates/bitwarden/src/vault/cipher/cipher.rs | 268 ++++-------------- crates/bitwarden/src/vault/cipher/field.rs | 6 +- crates/bitwarden/src/vault/cipher/identity.rs | 38 +-- crates/bitwarden/src/vault/cipher/login.rs | 83 +++--- crates/bitwarden/src/vault/collection.rs | 5 +- crates/bitwarden/src/vault/folder.rs | 5 +- .../bitwarden/src/vault/password_history.rs | 5 +- crates/bitwarden/src/vault/send.rs | 68 +++-- 37 files changed, 533 insertions(+), 787 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d9636181..46cae9189 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -460,7 +460,6 @@ dependencies = [ "bitwarden-crypto", "chrono", "csv", - "itertools 0.12.1", "serde", "serde_json", "thiserror", diff --git a/crates/bitwarden-crypto/src/enc_string/asymmetric.rs b/crates/bitwarden-crypto/src/enc_string/asymmetric.rs index f4c8b0f7c..f9bda838a 100644 --- a/crates/bitwarden-crypto/src/enc_string/asymmetric.rs +++ b/crates/bitwarden-crypto/src/enc_string/asymmetric.rs @@ -9,7 +9,7 @@ use super::{from_b64_vec, split_enc_string}; use crate::{ error::{CryptoError, EncStringParseError, Result}, rsa::encrypt_rsa2048_oaep_sha1, - AsymmetricCryptoKey, AsymmetricEncryptable, DecryptedString, DecryptedVec, KeyDecryptable, + AsymmetricCryptoKey, AsymmetricEncryptable, KeyDecryptable, }; // This module is a workaround to avoid deprecated warnings that come from the ZeroizeOnDrop @@ -166,8 +166,8 @@ impl AsymmetricEncString { } } -impl KeyDecryptable for AsymmetricEncString { - fn decrypt_with_key(&self, key: &AsymmetricCryptoKey) -> Result { +impl KeyDecryptable> for AsymmetricEncString { + fn decrypt_with_key(&self, key: &AsymmetricCryptoKey) -> Result> { use AsymmetricEncString::*; match self { Rsa2048_OaepSha256_B64 { data } => key.key.decrypt(Oaep::new::(), data), @@ -181,15 +181,14 @@ impl KeyDecryptable for AsymmetricEncString { key.key.decrypt(Oaep::new::(), data) } } - .map(|v| DecryptedVec::new(Box::new(v))) .map_err(|_| CryptoError::KeyDecrypt) } } -impl KeyDecryptable for AsymmetricEncString { - fn decrypt_with_key(&self, key: &AsymmetricCryptoKey) -> Result { - let dec: DecryptedVec = self.decrypt_with_key(key)?; - dec.try_into() +impl KeyDecryptable for AsymmetricEncString { + fn decrypt_with_key(&self, key: &AsymmetricCryptoKey) -> Result { + let dec: Vec = self.decrypt_with_key(key)?; + String::from_utf8(dec).map_err(|_| CryptoError::InvalidUtf8String) } } @@ -210,11 +209,8 @@ mod tests { use schemars::schema_for; use super::{AsymmetricCryptoKey, AsymmetricEncString, KeyDecryptable}; - use crate::{DecryptedString, SensitiveString}; - fn rsa_private_key_string() -> SensitiveString { - SensitiveString::test( - "-----BEGIN PRIVATE KEY----- + const RSA_PRIVATE_KEY: &str = "-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXRVrCX+2hfOQS 8HzYUS2oc/jGVTZpv+/Ryuoh9d8ihYX9dd0cYh2tl6KWdFc88lPUH11Oxqy20Rk2 e5r/RF6T9yM0Me3NPnaKt+hlhLtfoc0h86LnhD56A9FDUfuI0dVnPcrwNv0YJIo9 @@ -241,44 +237,42 @@ AoEZ18y6/KIjpSMpqC92Nnk/EBM9EYe6Cf4eA9ApAoGAeqEUg46UTlJySkBKURGp Is3v1kkf5I0X8DnOhwb+HPxNaiEdmO7ckm8+tPVgppLcG0+tMdLjigFQiDUQk2y3 WjyxP5ZvXu7U96jaJRI8PFMoE06WeVYcdIzrID2HvqH+w0UQJFrLJ/0Mn4stFAEz XKZBokBGnjFnTnKcs7nv/O8= ------END PRIVATE KEY-----", - ) - } +-----END PRIVATE KEY-----"; #[test] fn test_enc_string_rsa2048_oaep_sha256_b64() { - let private_key = AsymmetricCryptoKey::from_pem(rsa_private_key_string()).unwrap(); + let private_key = AsymmetricCryptoKey::from_pem(RSA_PRIVATE_KEY).unwrap(); let enc_str: &str = "3.YFqzW9LL/uLjCnl0RRLtndzGJ1FV27mcwQwGjfJPOVrgCX9nJSUYCCDd0iTIyOZ/zRxG47b6L1Z3qgkEfcxjmrSBq60gijc3E2TBMAg7OCLVcjORZ+i1sOVOudmOPWro6uA8refMrg4lqbieDlbLMzjVEwxfi5WpcL876cD0vYyRwvLO3bzFrsE7x33HHHtZeOPW79RqMn5efsB5Dj9wVheC9Ix9AYDjbo+rjg9qR6guwKmS7k2MSaIQlrDR7yu8LP+ePtiSjx+gszJV5jQGfcx60dtiLQzLS/mUD+RmU7B950Bpx0H7x56lT5yXZbWK5YkoP6qd8B8D2aKbP68Ywg=="; let enc_string: AsymmetricEncString = enc_str.parse().unwrap(); assert_eq!(enc_string.enc_type(), 3); - let res: DecryptedString = enc_string.decrypt_with_key(&private_key).unwrap(); - assert_eq!(res.expose(), "EncryptMe!"); + let res: String = enc_string.decrypt_with_key(&private_key).unwrap(); + assert_eq!(res, "EncryptMe!"); } #[test] fn test_enc_string_rsa2048_oaep_sha1_b64() { - let private_key = AsymmetricCryptoKey::from_pem(rsa_private_key_string()).unwrap(); + let private_key = AsymmetricCryptoKey::from_pem(RSA_PRIVATE_KEY).unwrap(); let enc_str: &str = "4.ZheRb3PCfAunyFdQYPfyrFqpuvmln9H9w5nDjt88i5A7ug1XE0LJdQHCIYJl0YOZ1gCOGkhFu/CRY2StiLmT3iRKrrVBbC1+qRMjNNyDvRcFi91LWsmRXhONVSPjywzrJJXglsztDqGkLO93dKXNhuKpcmtBLsvgkphk/aFvxbaOvJ/FHdK/iV0dMGNhc/9tbys8laTdwBlI5xIChpRcrfH+XpSFM88+Bu03uK67N9G6eU1UmET+pISJwJvMuIDMqH+qkT7OOzgL3t6I0H2LDj+CnsumnQmDsvQzDiNfTR0IgjpoE9YH2LvPXVP2wVUkiTwXD9cG/E7XeoiduHyHjw=="; let enc_string: AsymmetricEncString = enc_str.parse().unwrap(); assert_eq!(enc_string.enc_type(), 4); - let res: DecryptedString = enc_string.decrypt_with_key(&private_key).unwrap(); - assert_eq!(res.expose(), "EncryptMe!"); + let res: String = enc_string.decrypt_with_key(&private_key).unwrap(); + assert_eq!(res, "EncryptMe!"); } #[test] fn test_enc_string_rsa2048_oaep_sha1_hmac_sha256_b64() { - let private_key = AsymmetricCryptoKey::from_pem(rsa_private_key_string()).unwrap(); + let private_key = AsymmetricCryptoKey::from_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: AsymmetricEncString = enc_str.parse().unwrap(); assert_eq!(enc_string.enc_type(), 6); - let res: DecryptedString = enc_string.decrypt_with_key(&private_key).unwrap(); - assert_eq!(res.expose(), "EncryptMe!"); + let res: String = enc_string.decrypt_with_key(&private_key).unwrap(); + assert_eq!(res, "EncryptMe!"); } #[test] diff --git a/crates/bitwarden-crypto/src/enc_string/symmetric.rs b/crates/bitwarden-crypto/src/enc_string/symmetric.rs index e8c4c2d04..d312882d7 100644 --- a/crates/bitwarden-crypto/src/enc_string/symmetric.rs +++ b/crates/bitwarden-crypto/src/enc_string/symmetric.rs @@ -8,7 +8,7 @@ use serde::Deserialize; use super::{check_length, from_b64, from_b64_vec, split_enc_string}; use crate::{ error::{CryptoError, EncStringParseError, Result}, - DecryptedString, DecryptedVec, KeyDecryptable, KeyEncryptable, LocateKey, SymmetricCryptoKey, + KeyDecryptable, KeyEncryptable, LocateKey, SymmetricCryptoKey, }; /// # Encrypted string primitive @@ -233,15 +233,11 @@ impl KeyEncryptable for &[u8] { } } -impl KeyDecryptable for EncString { - fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { +impl KeyDecryptable> for EncString { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result> { match self { EncString::AesCbc256_B64 { iv, data } => { - let dec = DecryptedVec::new(Box::new(crate::aes::decrypt_aes256( - iv, - data.clone(), - &key.key, - )?)); + let dec = crate::aes::decrypt_aes256(iv, data.clone(), &key.key)?; Ok(dec) } EncString::AesCbc128_HmacSha256_B64 { iv, mac, data } => { @@ -251,24 +247,13 @@ impl KeyDecryptable for EncString { // When refactoring the key handling, this should be fixed. let enc_key = key.key[0..16].into(); let mac_key = key.key[16..32].into(); - let dec = DecryptedVec::new(Box::new(crate::aes::decrypt_aes128_hmac( - iv, - mac, - data.clone(), - mac_key, - enc_key, - )?)); + let dec = crate::aes::decrypt_aes128_hmac(iv, mac, data.clone(), mac_key, enc_key)?; Ok(dec) } EncString::AesCbc256_HmacSha256_B64 { iv, mac, data } => { let mac_key = key.mac_key.as_ref().ok_or(CryptoError::InvalidMac)?; - let dec = DecryptedVec::new(Box::new(crate::aes::decrypt_aes256_hmac( - iv, - mac, - data.clone(), - mac_key, - &key.key, - )?)); + let dec = + crate::aes::decrypt_aes256_hmac(iv, mac, data.clone(), mac_key, &key.key)?; Ok(dec) } } @@ -281,10 +266,10 @@ impl KeyEncryptable for String { } } -impl KeyDecryptable for EncString { - fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { - let dec: DecryptedVec = self.decrypt_with_key(key)?; - dec.try_into() +impl KeyDecryptable for EncString { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { + let dec: Vec = self.decrypt_with_key(key)?; + String::from_utf8(dec).map_err(|_| CryptoError::InvalidUtf8String) } } @@ -316,8 +301,8 @@ mod tests { let test_string = "encrypted_test_string"; let cipher = test_string.to_owned().encrypt_with_key(&key).unwrap(); - let decrypted_str: SensitiveString = cipher.decrypt_with_key(&key).unwrap(); - assert_eq!(decrypted_str.expose(), test_string); + let decrypted_str: String = cipher.decrypt_with_key(&key).unwrap(); + assert_eq!(decrypted_str, test_string); } #[test] @@ -414,8 +399,8 @@ mod tests { let enc_string: EncString = enc_str.parse().unwrap(); assert_eq!(enc_string.enc_type(), 0); - let dec_str: SensitiveString = enc_string.decrypt_with_key(&key).unwrap(); - assert_eq!(dec_str.expose(), "EncryptMe!"); + let dec_str: String = enc_string.decrypt_with_key(&key).unwrap(); + assert_eq!(dec_str, "EncryptMe!"); } #[test] @@ -427,8 +412,8 @@ mod tests { let enc_string: EncString = enc_str.parse().unwrap(); assert_eq!(enc_string.enc_type(), 1); - let dec_str: SensitiveString = enc_string.decrypt_with_key(&key).unwrap(); - assert_eq!(dec_str.expose(), "EncryptMe!"); + let dec_str: String = enc_string.decrypt_with_key(&key).unwrap(); + assert_eq!(dec_str, "EncryptMe!"); } #[test] diff --git a/crates/bitwarden-crypto/src/keys/asymmetric_crypto_key.rs b/crates/bitwarden-crypto/src/keys/asymmetric_crypto_key.rs index 9636defe1..be523bbc6 100644 --- a/crates/bitwarden-crypto/src/keys/asymmetric_crypto_key.rs +++ b/crates/bitwarden-crypto/src/keys/asymmetric_crypto_key.rs @@ -3,10 +3,7 @@ use std::pin::Pin; use rsa::{pkcs8::DecodePublicKey, RsaPrivateKey, RsaPublicKey}; use super::key_encryptable::CryptoKey; -use crate::{ - error::{CryptoError, Result}, - SensitiveString, SensitiveVec, -}; +use crate::error::{CryptoError, Result}; /// Trait to allow both [`AsymmetricCryptoKey`] and [`AsymmetricPublicCryptoKey`] to be used to /// encrypt [AsymmetricEncString](crate::AsymmetricEncString). @@ -23,9 +20,9 @@ pub struct AsymmetricPublicCryptoKey { impl AsymmetricPublicCryptoKey { /// Build a public key from the SubjectPublicKeyInfo DER. - pub fn from_der(der: SensitiveVec) -> Result { + pub fn from_der(der: &[u8]) -> Result { Ok(Self { - key: rsa::RsaPublicKey::from_public_key_der(der.expose()) + key: rsa::RsaPublicKey::from_public_key_der(der) .map_err(|_| CryptoError::InvalidKey)?, }) } @@ -68,21 +65,17 @@ impl AsymmetricCryptoKey { } } - pub fn from_pem(pem: SensitiveString) -> Result { + pub fn from_pem(pem: &str) -> Result { use rsa::pkcs8::DecodePrivateKey; Ok(Self { - key: Box::pin( - RsaPrivateKey::from_pkcs8_pem(pem.expose()).map_err(|_| CryptoError::InvalidKey)?, - ), + key: Box::pin(RsaPrivateKey::from_pkcs8_pem(pem).map_err(|_| CryptoError::InvalidKey)?), }) } - pub fn from_der(der: SensitiveVec) -> Result { + pub fn from_der(der: &[u8]) -> Result { use rsa::pkcs8::DecodePrivateKey; Ok(Self { - key: Box::pin( - RsaPrivateKey::from_pkcs8_der(der.expose()).map_err(|_| CryptoError::InvalidKey)?, - ), + key: Box::pin(RsaPrivateKey::from_pkcs8_der(der).map_err(|_| CryptoError::InvalidKey)?), }) } @@ -124,17 +117,15 @@ impl std::fmt::Debug for AsymmetricCryptoKey { #[cfg(test)] mod tests { - use base64::engine::general_purpose::STANDARD; + use base64::{engine::general_purpose::STANDARD, Engine}; use crate::{ - AsymmetricCryptoKey, AsymmetricEncString, AsymmetricPublicCryptoKey, DecryptedString, - KeyDecryptable, SensitiveString, + AsymmetricCryptoKey, AsymmetricEncString, AsymmetricPublicCryptoKey, KeyDecryptable, }; #[test] fn test_asymmetric_crypto_key() { - let pem_key_str = SensitiveString::test( - "-----BEGIN PRIVATE KEY----- + let pem_key_str = "-----BEGIN PRIVATE KEY----- MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDiTQVuzhdygFz5 qv14i+XFDGTnDravzUQT1hPKPGUZOUSZ1gwdNgkWqOIaOnR65BHEnL0sp4bnuiYc afeK2JAW5Sc8Z7IxBNSuAwhQmuKx3RochMIiuCkI2/p+JvUQoJu6FBNm8OoJ4Cwm @@ -161,75 +152,74 @@ Zy2o6PPxhfkagaDjqEeN9Lrs5LD4nEvDkr5CG1vOjmMCgYEAvIBFKRm31NyF8jLi CVuPwC5PzrW5iThDmsWTaXFpB3esUsbICO2pEz872oeQS+Em4GO5vXUlpbbFPzup PFhA8iMJ8TAvemhvc7oM0OZqpU6p3K4seHf6BkwLxumoA3vDJfovu9RuXVcJVOnf DnqOsltgPomWZ7xVfMkm9niL2OA= ------END PRIVATE KEY-----", - ); +-----END PRIVATE KEY-----"; - let der_key_vec = SensitiveString::test("MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDiTQVuzhdygFz5qv14i+XFDGTnDravzUQT1hPKPGUZOUSZ1gwdNgkWqOIaOnR65BHEnL0sp4bnuiYcafeK2JAW5Sc8Z7IxBNSuAwhQmuKx3RochMIiuCkI2/p+JvUQoJu6FBNm8OoJ4CwmqqHGZESMfnpQDCuDrB3JdJEdXhtmnl0C48sGjOk3WaBMcgGqn8LbJDUlyu1zdqyvb0waJf0iV4PJm2fkUl7+57D/2TkpbCqURVnZK1FFIEg8mr6FzSN1F2pOfktkNYZwP7MSNR7o81CkRSCMr7EkIVa+MZYMBx106BMK7FXgWB7nbSpsWKxBk7ZDHkID2famrEcVtrzDAgMBAAECggEBAKwq9OssGGKgjhvUnyrLJHAZ0dqIMyzk+dotkLjX4gKiszJmyqiep6N5sStLNbsZMPtoU/RZMCW0VbJgXFhiEp2YkZU/Py5UAoqw++53J+kx0d/IkPphKbb3xUec0+1mg5O6GljDCQuiZXS1dIa/WfeZcezclW6Dz9WovY6ePjJ+8vEBR1icbNKzyeINd6MtPtpcgQPHtDwHvhPyUDbKDYGbLvjh9nui8h4+ZUlXKuVRjB0ChxiKV1xJRjkrEVoulOOicd5r597WfB2ghax3pvRZ4MdXemCXm3gQYqPVKachvGU+1cPQR/MBJZpxT+EZA97xwtFS3gqwbxJaNFcoE8ECgYEA9OaeYZhQPDo485tI1u/Z7L/3PNape9hBQIXoW7+MgcQ5NiWqYh8Jnj43EIYa0wM/ECQINr1Za8Q5e6KRJ30FcU+kfyjuQ0jeXdNELGU/fx5XXNg/vV8GevHwxRlwzqZTCg6UExUZzbYEQqd7l+wPyETGeua5xCEywA1nX/D101kCgYEA7I6aMFjhEjO71RmzNhqjKJt6DOghoOfQTjhaaanNEhLYSbenFz1mlb21mW67ulmz162saKdIYLxQNJIP8ZPmxh4ummOJI8w9ClHfo8WuCI2hCjJ19xbQJocSbTA5aJg6lA1IDVZMDbQwsnAByPRGpaLHBT/Q9ByeKvCMB+9amXsCgYEAx65yXSkP4sumPBrVHUub6MntERIGRxBgw/drKcPZEMWp0FiNwEuGUBxyUWrG3F69QK/gcqGZE6F/LSu0JvptQaKqgXQiMYJsrRvhbkFvsHpQyUcZUZL1ebFjm5HOxPAgrQaN/bEqxOwwNRjSUWEMzUImg3c06JIZCzbinvudtKECgYEAkY3JF/iIPI/yglP27lKDlCfeeHSYxI3+oTKRhzSAxx8rUGidenJAXeDGDauR/T7Wpt3pGNfddBBK9Z3uC4Iq3DqUCFE4f/taj7ADAJ1Q0Vh7/28/IJM77ojr8J1cpZwNZy2o6PPxhfkagaDjqEeN9Lrs5LD4nEvDkr5CG1vOjmMCgYEAvIBFKRm31NyF8jLiCVuPwC5PzrW5iThDmsWTaXFpB3esUsbICO2pEz872oeQS+Em4GO5vXUlpbbFPzupPFhA8iMJ8TAvemhvc7oM0OZqpU6p3K4seHf6BkwLxumoA3vDJfovu9RuXVcJVOnfDnqOsltgPomWZ7xVfMkm9niL2OA=").decode_base64(STANDARD).unwrap(); + let der_key_vec = STANDARD.decode("MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDiTQVuzhdygFz5qv14i+XFDGTnDravzUQT1hPKPGUZOUSZ1gwdNgkWqOIaOnR65BHEnL0sp4bnuiYcafeK2JAW5Sc8Z7IxBNSuAwhQmuKx3RochMIiuCkI2/p+JvUQoJu6FBNm8OoJ4CwmqqHGZESMfnpQDCuDrB3JdJEdXhtmnl0C48sGjOk3WaBMcgGqn8LbJDUlyu1zdqyvb0waJf0iV4PJm2fkUl7+57D/2TkpbCqURVnZK1FFIEg8mr6FzSN1F2pOfktkNYZwP7MSNR7o81CkRSCMr7EkIVa+MZYMBx106BMK7FXgWB7nbSpsWKxBk7ZDHkID2famrEcVtrzDAgMBAAECggEBAKwq9OssGGKgjhvUnyrLJHAZ0dqIMyzk+dotkLjX4gKiszJmyqiep6N5sStLNbsZMPtoU/RZMCW0VbJgXFhiEp2YkZU/Py5UAoqw++53J+kx0d/IkPphKbb3xUec0+1mg5O6GljDCQuiZXS1dIa/WfeZcezclW6Dz9WovY6ePjJ+8vEBR1icbNKzyeINd6MtPtpcgQPHtDwHvhPyUDbKDYGbLvjh9nui8h4+ZUlXKuVRjB0ChxiKV1xJRjkrEVoulOOicd5r597WfB2ghax3pvRZ4MdXemCXm3gQYqPVKachvGU+1cPQR/MBJZpxT+EZA97xwtFS3gqwbxJaNFcoE8ECgYEA9OaeYZhQPDo485tI1u/Z7L/3PNape9hBQIXoW7+MgcQ5NiWqYh8Jnj43EIYa0wM/ECQINr1Za8Q5e6KRJ30FcU+kfyjuQ0jeXdNELGU/fx5XXNg/vV8GevHwxRlwzqZTCg6UExUZzbYEQqd7l+wPyETGeua5xCEywA1nX/D101kCgYEA7I6aMFjhEjO71RmzNhqjKJt6DOghoOfQTjhaaanNEhLYSbenFz1mlb21mW67ulmz162saKdIYLxQNJIP8ZPmxh4ummOJI8w9ClHfo8WuCI2hCjJ19xbQJocSbTA5aJg6lA1IDVZMDbQwsnAByPRGpaLHBT/Q9ByeKvCMB+9amXsCgYEAx65yXSkP4sumPBrVHUub6MntERIGRxBgw/drKcPZEMWp0FiNwEuGUBxyUWrG3F69QK/gcqGZE6F/LSu0JvptQaKqgXQiMYJsrRvhbkFvsHpQyUcZUZL1ebFjm5HOxPAgrQaN/bEqxOwwNRjSUWEMzUImg3c06JIZCzbinvudtKECgYEAkY3JF/iIPI/yglP27lKDlCfeeHSYxI3+oTKRhzSAxx8rUGidenJAXeDGDauR/T7Wpt3pGNfddBBK9Z3uC4Iq3DqUCFE4f/taj7ADAJ1Q0Vh7/28/IJM77ojr8J1cpZwNZy2o6PPxhfkagaDjqEeN9Lrs5LD4nEvDkr5CG1vOjmMCgYEAvIBFKRm31NyF8jLiCVuPwC5PzrW5iThDmsWTaXFpB3esUsbICO2pEz872oeQS+Em4GO5vXUlpbbFPzupPFhA8iMJ8TAvemhvc7oM0OZqpU6p3K4seHf6BkwLxumoA3vDJfovu9RuXVcJVOnfDnqOsltgPomWZ7xVfMkm9niL2OA=").unwrap(); // Load the two different formats and check they are the same key let pem_key = AsymmetricCryptoKey::from_pem(pem_key_str).unwrap(); - let der_key = AsymmetricCryptoKey::from_der(der_key_vec.clone()).unwrap(); + let der_key = AsymmetricCryptoKey::from_der(&der_key_vec).unwrap(); assert_eq!(pem_key.key, der_key.key); // Check that the keys can be converted back to DER - assert_eq!(&der_key.to_der().unwrap(), der_key_vec.expose()); - assert_eq!(&pem_key.to_der().unwrap(), der_key_vec.expose()); + assert_eq!(der_key.to_der().unwrap(), der_key_vec); + assert_eq!(pem_key.to_der().unwrap(), der_key_vec); } #[test] fn test_encrypt_public_decrypt_private() { - let private_key = SensitiveString::test(concat!( - "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCu9xd+vmkIPoqH", - "NejsFZzkd1xuCn1TqGTT7ANhAEnbI/yaVt3caI30kwUC2WIToFpNgu7Ej0x2TteY", - "OgrLrdcC4jy1SifmKYv/v3ZZxrd/eqttmH2k588panseRwHK3LVk7xA+URhQ/bjL", - "gPM59V0uR1l+z1fmooeJPFz5WSXNObc9Jqnh45FND+U/UYHXTLSomTn7jgZFxJBK", - "veS7q6Lat7wAnYZCF2dnPmhZoJv+SKPltA8HAGsgQGWBF1p5qxV1HrAUk8kBBnG2", - "paj0w8p5UM6RpDdCuvKH7j1LiuWffn3b9Z4dgzmE7jsMmvzoQtypzIKaSxhqzvFO", - "od9V8dJdAgMBAAECggEAGGIYjOIB1rOKkDHP4ljXutI0mCRPl3FMDemiBeppoIfZ", - "G/Q3qpAKmndDt0Quwh/yfcNdvZhf1kwCCTWri/uPz5fSUIyDV3TaTRu0ZWoHaBVj", - "Hxylg+4HRZUQj+Vi50/PWr/jQmAAVMcrMfcoTl82q2ynmP/R1vM3EsXOCjTliv5B", - "XlMPRjj/9PDBH0dnnVcAPDOpflzOTL2f4HTFEMlmg9/tZBnd96J/cmfhjAv9XpFL", - "FBAFZzs5pz0rwCNSR8QZNonnK7pngVUlGDLORK58y84tGmxZhGdne3CtCWey/sJ4", - "7QF0Pe8YqWBU56926IY6DcSVBuQGZ6vMCNlU7J8D2QKBgQDXyh3t2TicM/n1QBLk", - "zLoGmVUmxUGziHgl2dnJiGDtyOAU3+yCorPgFaCie29s5qm4b0YEGxUxPIrRrEro", - "h0FfKn9xmr8CdmTPTcjJW1+M7bxxq7oBoU/QzKXgIHlpeCjjnvPJt0PcNkNTjCXv", - "shsrINh2rENoe/x79eEfM/N5eQKBgQDPkYSmYyALoNq8zq0A4BdR+F5lb5Fj5jBH", - "Jk68l6Uti+0hRbJ2d1tQTLkU+eCPQLGBl6fuc1i4K5FV7v14jWtRPdD7wxrkRi3j", - "ilqQwLBOU6Bj3FK4DvlLF+iYTuBWj2/KcxflXECmsjitKHLK6H7kFEiuJql+NAHU", - "U9EFXepLBQKBgQDQ+HCnZ1bFHiiP8m7Zl9EGlvK5SwlnPV9s+F1KJ4IGhCNM09UM", - "ZVfgR9F5yCONyIrPiyK40ylgtwqQJlOcf281I8irUXpsfg7+Gou5Q31y0r9NLUpC", - "Td8niyePtqMdGjouxD2+OHXFCd+FRxFt4IMi7vnxYr0csAVAXkqWlw7PsQKBgH/G", - "/PnQm7GM3BrOwAGB8dksJDAddkshMScblezTDYP0V43b8firkTLliCo5iNum357/", - "VQmdSEhXyag07yR/Kklg3H2fpbZQ3X7tdMMXW3FcWagfwWw9C4oGtdDM/Z1Lv23J", - "XDR9je8QV4OBGul+Jl8RfYx3kG94ZIfo8Qt0vP5hAoGARjAzdCGYz42NwaUk8n94", - "W2RuKHtTV9vtjaAbfPFbZoGkT7sXNJVlrA0C+9f+H9rOTM3mX59KrjmLVzde4Vhs", - "avWMShuK4vpAiDQLU7GyABvi5CR6Ld+AT+LSzxHhVe0ASOQPNCA2SOz3RQvgPi7R", - "GDgRMUB6cL3IRVzcR0dC6cY=", - )) - .decode_base64(STANDARD) - .unwrap(); - - let public_key = SensitiveString::test(concat!( - "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArvcXfr5pCD6KhzXo7BWc", - "5Hdcbgp9U6hk0+wDYQBJ2yP8mlbd3GiN9JMFAtliE6BaTYLuxI9Mdk7XmDoKy63X", - "AuI8tUon5imL/792Wca3f3qrbZh9pOfPKWp7HkcByty1ZO8QPlEYUP24y4DzOfVd", - "LkdZfs9X5qKHiTxc+VklzTm3PSap4eORTQ/lP1GB10y0qJk5+44GRcSQSr3ku6ui", - "2re8AJ2GQhdnZz5oWaCb/kij5bQPBwBrIEBlgRdaeasVdR6wFJPJAQZxtqWo9MPK", - "eVDOkaQ3Qrryh+49S4rln3592/WeHYM5hO47DJr86ELcqcyCmksYas7xTqHfVfHS", - "XQIDAQAB", - )) - .decode_base64(STANDARD) - .unwrap(); - - let private_key = AsymmetricCryptoKey::from_der(private_key).unwrap(); - let public_key = AsymmetricPublicCryptoKey::from_der(public_key).unwrap(); + let private_key = STANDARD + .decode(concat!( + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCu9xd+vmkIPoqH", + "NejsFZzkd1xuCn1TqGTT7ANhAEnbI/yaVt3caI30kwUC2WIToFpNgu7Ej0x2TteY", + "OgrLrdcC4jy1SifmKYv/v3ZZxrd/eqttmH2k588panseRwHK3LVk7xA+URhQ/bjL", + "gPM59V0uR1l+z1fmooeJPFz5WSXNObc9Jqnh45FND+U/UYHXTLSomTn7jgZFxJBK", + "veS7q6Lat7wAnYZCF2dnPmhZoJv+SKPltA8HAGsgQGWBF1p5qxV1HrAUk8kBBnG2", + "paj0w8p5UM6RpDdCuvKH7j1LiuWffn3b9Z4dgzmE7jsMmvzoQtypzIKaSxhqzvFO", + "od9V8dJdAgMBAAECggEAGGIYjOIB1rOKkDHP4ljXutI0mCRPl3FMDemiBeppoIfZ", + "G/Q3qpAKmndDt0Quwh/yfcNdvZhf1kwCCTWri/uPz5fSUIyDV3TaTRu0ZWoHaBVj", + "Hxylg+4HRZUQj+Vi50/PWr/jQmAAVMcrMfcoTl82q2ynmP/R1vM3EsXOCjTliv5B", + "XlMPRjj/9PDBH0dnnVcAPDOpflzOTL2f4HTFEMlmg9/tZBnd96J/cmfhjAv9XpFL", + "FBAFZzs5pz0rwCNSR8QZNonnK7pngVUlGDLORK58y84tGmxZhGdne3CtCWey/sJ4", + "7QF0Pe8YqWBU56926IY6DcSVBuQGZ6vMCNlU7J8D2QKBgQDXyh3t2TicM/n1QBLk", + "zLoGmVUmxUGziHgl2dnJiGDtyOAU3+yCorPgFaCie29s5qm4b0YEGxUxPIrRrEro", + "h0FfKn9xmr8CdmTPTcjJW1+M7bxxq7oBoU/QzKXgIHlpeCjjnvPJt0PcNkNTjCXv", + "shsrINh2rENoe/x79eEfM/N5eQKBgQDPkYSmYyALoNq8zq0A4BdR+F5lb5Fj5jBH", + "Jk68l6Uti+0hRbJ2d1tQTLkU+eCPQLGBl6fuc1i4K5FV7v14jWtRPdD7wxrkRi3j", + "ilqQwLBOU6Bj3FK4DvlLF+iYTuBWj2/KcxflXECmsjitKHLK6H7kFEiuJql+NAHU", + "U9EFXepLBQKBgQDQ+HCnZ1bFHiiP8m7Zl9EGlvK5SwlnPV9s+F1KJ4IGhCNM09UM", + "ZVfgR9F5yCONyIrPiyK40ylgtwqQJlOcf281I8irUXpsfg7+Gou5Q31y0r9NLUpC", + "Td8niyePtqMdGjouxD2+OHXFCd+FRxFt4IMi7vnxYr0csAVAXkqWlw7PsQKBgH/G", + "/PnQm7GM3BrOwAGB8dksJDAddkshMScblezTDYP0V43b8firkTLliCo5iNum357/", + "VQmdSEhXyag07yR/Kklg3H2fpbZQ3X7tdMMXW3FcWagfwWw9C4oGtdDM/Z1Lv23J", + "XDR9je8QV4OBGul+Jl8RfYx3kG94ZIfo8Qt0vP5hAoGARjAzdCGYz42NwaUk8n94", + "W2RuKHtTV9vtjaAbfPFbZoGkT7sXNJVlrA0C+9f+H9rOTM3mX59KrjmLVzde4Vhs", + "avWMShuK4vpAiDQLU7GyABvi5CR6Ld+AT+LSzxHhVe0ASOQPNCA2SOz3RQvgPi7R", + "GDgRMUB6cL3IRVzcR0dC6cY=", + )) + .unwrap(); + + let public_key = STANDARD + .decode(concat!( + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArvcXfr5pCD6KhzXo7BWc", + "5Hdcbgp9U6hk0+wDYQBJ2yP8mlbd3GiN9JMFAtliE6BaTYLuxI9Mdk7XmDoKy63X", + "AuI8tUon5imL/792Wca3f3qrbZh9pOfPKWp7HkcByty1ZO8QPlEYUP24y4DzOfVd", + "LkdZfs9X5qKHiTxc+VklzTm3PSap4eORTQ/lP1GB10y0qJk5+44GRcSQSr3ku6ui", + "2re8AJ2GQhdnZz5oWaCb/kij5bQPBwBrIEBlgRdaeasVdR6wFJPJAQZxtqWo9MPK", + "eVDOkaQ3Qrryh+49S4rln3592/WeHYM5hO47DJr86ELcqcyCmksYas7xTqHfVfHS", + "XQIDAQAB", + )) + .unwrap(); + + let private_key = AsymmetricCryptoKey::from_der(&private_key).unwrap(); + let public_key = AsymmetricPublicCryptoKey::from_der(&public_key).unwrap(); let plaintext = "Hello, world!"; let encrypted = AsymmetricEncString::encrypt_rsa2048_oaep_sha1(plaintext.as_bytes(), &public_key) .unwrap(); - let decrypted: DecryptedString = encrypted.decrypt_with_key(&private_key).unwrap(); + let decrypted: String = encrypted.decrypt_with_key(&private_key).unwrap(); - assert_eq!(plaintext, decrypted.expose()); + assert_eq!(plaintext, decrypted); } } diff --git a/crates/bitwarden-crypto/src/keys/device_key.rs b/crates/bitwarden-crypto/src/keys/device_key.rs index e54dbaa88..d33e0dc32 100644 --- a/crates/bitwarden-crypto/src/keys/device_key.rs +++ b/crates/bitwarden-crypto/src/keys/device_key.rs @@ -62,11 +62,11 @@ impl DeviceKey { protected_device_private_key: EncString, protected_user_key: AsymmetricEncString, ) -> Result { - let device_private_key: DecryptedVec = - protected_device_private_key.decrypt_with_key(&self.0)?; - let device_private_key = AsymmetricCryptoKey::from_der(device_private_key)?; + let device_private_key: Vec = protected_device_private_key.decrypt_with_key(&self.0)?; + let device_private_key = AsymmetricCryptoKey::from_der(&device_private_key)?; - let dec: DecryptedVec = protected_user_key.decrypt_with_key(&device_private_key)?; + let dec: Vec = protected_user_key.decrypt_with_key(&device_private_key)?; + let dec = DecryptedVec::new(Box::new(dec)); let user_key = SymmetricCryptoKey::try_from(dec)?; Ok(user_key) diff --git a/crates/bitwarden-crypto/src/keys/master_key.rs b/crates/bitwarden-crypto/src/keys/master_key.rs index 86b4d7ec1..5a24125af 100644 --- a/crates/bitwarden-crypto/src/keys/master_key.rs +++ b/crates/bitwarden-crypto/src/keys/master_key.rs @@ -6,8 +6,7 @@ use serde::{Deserialize, Serialize}; use super::utils::{derive_kdf_key, stretch_kdf_key}; use crate::{ - util, CryptoError, DecryptedVec, EncString, KeyDecryptable, Result, SensitiveVec, - SymmetricCryptoKey, UserKey, + util, CryptoError, EncString, KeyDecryptable, Result, SensitiveVec, SymmetricCryptoKey, UserKey, }; /// Key Derivation Function for Bitwarden Account @@ -96,8 +95,8 @@ impl MasterKey { pub fn decrypt_user_key(&self, user_key: EncString) -> Result { let stretched_key = stretch_kdf_key(&self.0)?; - let dec: DecryptedVec = user_key.decrypt_with_key(&stretched_key)?; - SymmetricCryptoKey::try_from(dec) + let mut dec: Vec = user_key.decrypt_with_key(&stretched_key)?; + SymmetricCryptoKey::try_from(dec.as_mut_slice()) } pub fn encrypt_user_key(&self, user_key: &SymmetricCryptoKey) -> Result { diff --git a/crates/bitwarden-crypto/src/lib.rs b/crates/bitwarden-crypto/src/lib.rs index 0381afed5..692486d7f 100644 --- a/crates/bitwarden-crypto/src/lib.rs +++ b/crates/bitwarden-crypto/src/lib.rs @@ -12,18 +12,16 @@ //! ## Example: //! //! ```rust -//! use bitwarden_crypto::{ -//! CryptoError, DecryptedString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey, -//! }; +//! use bitwarden_crypto::{SymmetricCryptoKey, KeyEncryptable, KeyDecryptable, CryptoError}; //! //! async fn example() -> Result<(), CryptoError> { //! let key = SymmetricCryptoKey::generate(rand::thread_rng()); //! //! let data = "Hello, World!".to_owned(); //! let encrypted = data.clone().encrypt_with_key(&key)?; -//! let decrypted: DecryptedString = encrypted.decrypt_with_key(&key)?; +//! let decrypted: String = encrypted.decrypt_with_key(&key)?; //! -//! assert_eq!(&data, decrypted.expose()); +//! assert_eq!(data, decrypted); //! Ok(()) //! } //! ``` diff --git a/crates/bitwarden-crypto/src/sensitive/sensitive.rs b/crates/bitwarden-crypto/src/sensitive/sensitive.rs index d0ccb3249..5af0697bf 100644 --- a/crates/bitwarden-crypto/src/sensitive/sensitive.rs +++ b/crates/bitwarden-crypto/src/sensitive/sensitive.rs @@ -3,7 +3,6 @@ use std::{ fmt::{self, Formatter}, }; -use generic_array::{ArrayLength, GenericArray}; use schemars::JsonSchema; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use zeroize::{Zeroize, ZeroizeOnDrop}; @@ -62,18 +61,6 @@ impl From> for SensitiveVec { } } -/// Helper to convert a `&SensitiveVec` to a `Sensitive<[u8, N]>`. -impl TryFrom<&SensitiveVec> for Sensitive<[u8; N]> { - type Error = CryptoError; - - fn try_from(v: &SensitiveVec) -> Result { - Ok(Sensitive::new(Box::new( - TryInto::<[u8; N]>::try_into(v.expose().as_slice()) - .map_err(|_| CryptoError::InvalidKey)?, - ))) - } -} - /// Helper to convert a `Sensitive>` to a `Sensitive`, care is taken to ensure any /// intermediate copies are zeroed to avoid leaking sensitive data. impl TryFrom for SensitiveString { @@ -94,12 +81,6 @@ impl From for SensitiveVec { } } -impl> From>> for SensitiveVec { - fn from(val: Sensitive>) -> Self { - SensitiveVec::new(Box::new(val.value.to_vec())) - } -} - impl SensitiveString { pub fn decode_base64(self, engine: T) -> Result { // Prevent accidental copies by allocating the full size diff --git a/crates/bitwarden-exporters/Cargo.toml b/crates/bitwarden-exporters/Cargo.toml index 9ed860af6..96097c628 100644 --- a/crates/bitwarden-exporters/Cargo.toml +++ b/crates/bitwarden-exporters/Cargo.toml @@ -23,7 +23,6 @@ chrono = { version = ">=0.4.26, <0.5", features = [ "std", ], default-features = false } csv = "1.3.0" -itertools = "0.12.1" serde = { version = ">=1.0, <2.0", features = ["derive"] } serde_json = ">=1.0.96, <2.0" thiserror = ">=1.0.40, <2.0" diff --git a/crates/bitwarden-exporters/src/csv.rs b/crates/bitwarden-exporters/src/csv.rs index d4bbe5174..a0dcd1040 100644 --- a/crates/bitwarden-exporters/src/csv.rs +++ b/crates/bitwarden-exporters/src/csv.rs @@ -1,9 +1,9 @@ use std::collections::HashMap; -use bitwarden_crypto::{DecryptedString, Sensitive}; use csv::Writer; use serde::Serializer; use thiserror::Error; +use uuid::Uuid; use crate::{Cipher, CipherType, Field, Folder}; @@ -14,7 +14,7 @@ pub enum CsvError { } pub(crate) fn export_csv(folders: Vec, ciphers: Vec) -> Result { - let folders: HashMap<_, _> = folders.into_iter().map(|f| (f.id, f.name)).collect(); + let folders: HashMap = folders.into_iter().map(|f| (f.id, f.name)).collect(); let rows = ciphers .into_iter() @@ -59,30 +59,27 @@ pub(crate) fn export_csv(folders: Vec, ciphers: Vec) -> Result, + folder: Option, #[serde(serialize_with = "bool_serialize")] favorite: bool, r#type: String, - name: DecryptedString, - notes: Option, + name: String, + notes: Option, #[serde(serialize_with = "fields_serialize")] fields: Vec, reprompt: u8, #[serde(serialize_with = "vec_serialize")] - login_uri: Vec, - login_username: Option, - login_password: Option, - login_totp: Option, + login_uri: Vec, + login_username: Option, + login_password: Option, + login_totp: Option, } -fn vec_serialize(x: &[DecryptedString], s: S) -> Result +fn vec_serialize(x: &[String], s: S) -> Result where S: Serializer, { - let iter = itertools::Itertools::intersperse(x.iter().map(|s| s.expose().as_str()), ","); - let result: Sensitive = Sensitive::new(Box::new(iter.collect())); - - s.serialize_str(result.expose()) + s.serialize_str(x.join(",").as_str()) } fn bool_serialize(x: &bool, s: S) -> Result @@ -101,14 +98,8 @@ where .map(|f| { format!( "{}: {}", - f.name - .as_ref() - .map(|n| n.expose().as_str()) - .unwrap_or_default(), - f.value - .as_ref() - .map(|n| n.expose().as_str()) - .unwrap_or_default(), + f.name.to_owned().unwrap_or_default(), + f.value.to_owned().unwrap_or_default() ) }) .collect::>() @@ -127,24 +118,24 @@ mod tests { let folders = vec![ Folder { id: "d55d65d7-c161-40a4-94ca-b0d20184d91a".parse().unwrap(), - name: DecryptedString::test("Test Folder A"), + name: "Test Folder A".to_string(), }, Folder { id: "583e7665-0126-4d37-9139-b0d20184dd86".parse().unwrap(), - name: DecryptedString::test("Test Folder B"), + name: "Test Folder B".to_string(), }, ]; let ciphers = vec![ Cipher { id: "d55d65d7-c161-40a4-94ca-b0d20184d91a".parse().unwrap(), folder_id: None, - name: DecryptedString::test("test@bitwarden.com"), + name: "test@bitwarden.com".to_string(), notes: None, r#type: CipherType::Login(Box::new(Login { - username: Some(DecryptedString::test("test@bitwarden.com")), - password: Some(DecryptedString::test("Abc123")), + username: Some("test@bitwarden.com".to_string()), + password: Some("Abc123".to_string()), login_uris: vec![LoginUri { - uri: Some(DecryptedString::test("https://google.com")), + uri: Some("https://google.com".to_string()), r#match: None, }], totp: None, @@ -159,29 +150,29 @@ mod tests { Cipher { id: "7dd81bd0-cc72-4f42-96e7-b0fc014e71a3".parse().unwrap(), folder_id: Some("583e7665-0126-4d37-9139-b0d20184dd86".parse().unwrap()), - name: DecryptedString::test("Steam Account"), + name: "Steam Account".to_string(), notes: None, r#type: CipherType::Login(Box::new(Login { - username: Some(DecryptedString::test("steam")), - password: Some(DecryptedString::test("3Pvb8u7EfbV*nJ")), + username: Some("steam".to_string()), + password: Some("3Pvb8u7EfbV*nJ".to_string()), login_uris: vec![LoginUri { - uri: Some(DecryptedString::test("https://steampowered.com")), + uri: Some("https://steampowered.com".to_string()), r#match: None, }], - totp: Some(DecryptedString::test("steam://ABCD123")), + totp: Some("steam://ABCD123".to_string()), })), favorite: true, reprompt: 0, fields: vec![ Field { - name: Some(DecryptedString::test("Test")), - value: Some(DecryptedString::test("v")), + name: Some("Test".to_string()), + value: Some("v".to_string()), r#type: 0, linked_id: None, }, Field { - name: Some(DecryptedString::test("Hidden")), - value: Some(DecryptedString::test("asdfer")), + name: Some("Hidden".to_string()), + value: Some("asdfer".to_string()), r#type: 1, linked_id: None, }, @@ -209,7 +200,7 @@ mod tests { let ciphers = vec![Cipher { id: "d55d65d7-c161-40a4-94ca-b0d20184d91a".parse().unwrap(), folder_id: None, - name: DecryptedString::test("My Card"), + name: "My Card".to_string(), notes: None, r#type: CipherType::Card(Box::new(Card { cardholder_name: None, @@ -238,7 +229,7 @@ mod tests { let ciphers = vec![Cipher { id: "d55d65d7-c161-40a4-94ca-b0d20184d91a".parse().unwrap(), folder_id: None, - name: DecryptedString::test("My Identity"), + name: "My Identity".to_string(), notes: None, r#type: CipherType::Identity(Box::new(Identity { title: None, diff --git a/crates/bitwarden-exporters/src/encrypted_json.rs b/crates/bitwarden-exporters/src/encrypted_json.rs index c0d425f87..6dabc90d5 100644 --- a/crates/bitwarden-exporters/src/encrypted_json.rs +++ b/crates/bitwarden-exporters/src/encrypted_json.rs @@ -85,8 +85,6 @@ pub(crate) struct EncryptedJsonExport { mod tests { use std::num::NonZeroU32; - use bitwarden_crypto::DecryptedString; - use super::*; use crate::{ Card, Cipher, CipherType, Field, Identity, Login, LoginUri, SecureNote, SecureNoteType, @@ -97,24 +95,24 @@ mod tests { let _export = export_encrypted_json( vec![Folder { id: "942e2984-1b9a-453b-b039-b107012713b9".parse().unwrap(), - name: DecryptedString::test("Important"), + name: "Important".to_string(), }], vec![ Cipher { id: "25c8c414-b446-48e9-a1bd-b10700bbd740".parse().unwrap(), folder_id: Some("942e2984-1b9a-453b-b039-b107012713b9".parse().unwrap()), - name: DecryptedString::test("Bitwarden"), - notes: Some(DecryptedString::test("My note")), + name: "Bitwarden".to_string(), + notes: Some("My note".to_string()), r#type: CipherType::Login(Box::new(Login { - username: Some(DecryptedString::test("test@bitwarden.com")), - password: Some(DecryptedString::test("asdfasdfasdf")), + username: Some("test@bitwarden.com".to_string()), + password: Some("asdfasdfasdf".to_string()), login_uris: vec![LoginUri { - uri: Some(DecryptedString::test("https://vault.bitwarden.com")), + uri: Some("https://vault.bitwarden.com".to_string()), r#match: None, }], - totp: Some(DecryptedString::test("ABC")), + totp: Some("ABC".to_string()), })), favorite: true, @@ -122,31 +120,31 @@ mod tests { fields: vec![ Field { - name: Some(DecryptedString::test("Text")), - value: Some(DecryptedString::test("A")), + name: Some("Text".to_string()), + value: Some("A".to_string()), r#type: 0, linked_id: None, }, Field { - name: Some(DecryptedString::test("Hidden")), - value: Some(DecryptedString::test("B")), + name: Some("Hidden".to_string()), + value: Some("B".to_string()), r#type: 1, linked_id: None, }, Field { - name: Some(DecryptedString::test("Boolean (true)")), - value: Some(DecryptedString::test("true")), + name: Some("Boolean (true)".to_string()), + value: Some("true".to_string()), r#type: 2, linked_id: None, }, Field { - name: Some(DecryptedString::test("Boolean (false)")), - value: Some(DecryptedString::test("false")), + name: Some("Boolean (false)".to_string()), + value: Some("false".to_string()), r#type: 2, linked_id: None, }, Field { - name: Some(DecryptedString::test("Linked")), + name: Some("Linked".to_string()), value: None, r#type: 3, linked_id: Some(101), @@ -161,8 +159,8 @@ mod tests { id: "23f0f877-42b1-4820-a850-b10700bc41eb".parse().unwrap(), folder_id: None, - name: DecryptedString::test("My secure note"), - notes: Some(DecryptedString::test("Very secure!")), + name: "My secure note".to_string(), + notes: Some("Very secure!".to_string()), r#type: CipherType::SecureNote(Box::new(SecureNote { r#type: SecureNoteType::Generic, @@ -181,16 +179,16 @@ mod tests { id: "3ed8de45-48ee-4e26-a2dc-b10701276c53".parse().unwrap(), folder_id: None, - name: DecryptedString::test("My card"), + name: "My card".to_string(), notes: None, r#type: CipherType::Card(Box::new(Card { - cardholder_name: Some(DecryptedString::test("John Doe")), - exp_month: Some(DecryptedString::test("1")), - exp_year: Some(DecryptedString::test("2032")), - code: Some(DecryptedString::test("123")), - brand: Some(DecryptedString::test("Visa")), - number: Some(DecryptedString::test("4111111111111111")), + cardholder_name: Some("John Doe".to_string()), + exp_month: Some("1".to_string()), + exp_year: Some("2032".to_string()), + code: Some("123".to_string()), + brand: Some("Visa".to_string()), + number: Some("4111111111111111".to_string()), })), favorite: false, @@ -206,14 +204,14 @@ mod tests { id: "41cc3bc1-c3d9-4637-876c-b10701273712".parse().unwrap(), folder_id: Some("942e2984-1b9a-453b-b039-b107012713b9".parse().unwrap()), - name: DecryptedString::test("My identity"), + name: "My identity".to_string(), notes: None, r#type: CipherType::Identity(Box::new(Identity { - title: Some(DecryptedString::test("Mr")), - first_name: Some(DecryptedString::test("John")), + title: Some("Mr".to_string()), + first_name: Some("John".to_string()), middle_name: None, - last_name: Some(DecryptedString::test("Doe")), + last_name: Some("Doe".to_string()), address1: None, address2: None, address3: None, @@ -221,11 +219,11 @@ mod tests { state: None, postal_code: None, country: None, - company: Some(DecryptedString::test("Bitwarden")), + company: Some("Bitwarden".to_string()), email: None, phone: None, ssn: None, - username: Some(DecryptedString::test("JDoe")), + username: Some("JDoe".to_string()), passport_number: None, license_number: None, })), diff --git a/crates/bitwarden-exporters/src/json.rs b/crates/bitwarden-exporters/src/json.rs index f2c889f9f..3f6c72c1f 100644 --- a/crates/bitwarden-exporters/src/json.rs +++ b/crates/bitwarden-exporters/src/json.rs @@ -1,4 +1,3 @@ -use bitwarden_crypto::DecryptedString; use chrono::{DateTime, Utc}; use thiserror::Error; use uuid::Uuid; @@ -37,7 +36,7 @@ struct JsonExport { #[serde(rename_all = "camelCase")] struct JsonFolder { id: Uuid, - name: DecryptedString, + name: String, } impl From for JsonFolder { @@ -58,8 +57,8 @@ struct JsonCipher { organization_id: Option, collection_ids: Option>, - name: DecryptedString, - notes: Option, + name: String, + notes: Option, r#type: u8, #[serde(skip_serializing_if = "Option::is_none")] @@ -76,7 +75,7 @@ struct JsonCipher { #[serde(skip_serializing_if = "Vec::is_empty")] fields: Vec, - password_history: Option>, + password_history: Option>, revision_date: DateTime, creation_date: DateTime, @@ -86,11 +85,11 @@ struct JsonCipher { #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] struct JsonLogin { - username: Option, - password: Option, + username: Option, + password: Option, uris: Vec, - totp: Option, - fido2_credentials: Vec, + totp: Option, + fido2_credentials: Vec, } impl From for JsonLogin { @@ -108,7 +107,7 @@ impl From for JsonLogin { #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] struct JsonLoginUri { - uri: Option, + uri: Option, r#match: Option, } @@ -138,12 +137,12 @@ impl From for JsonSecureNote { #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] struct JsonCard { - cardholder_name: Option, - exp_month: Option, - exp_year: Option, - code: Option, - brand: Option, - number: Option, + cardholder_name: Option, + exp_month: Option, + exp_year: Option, + code: Option, + brand: Option, + number: Option, } impl From for JsonCard { @@ -162,24 +161,24 @@ impl From for JsonCard { #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] struct JsonIdentity { - title: Option, - first_name: Option, - middle_name: Option, - last_name: Option, - address1: Option, - address2: Option, - address3: Option, - city: Option, - state: Option, - postal_code: Option, - country: Option, - company: Option, - email: Option, - phone: Option, - ssn: Option, - username: Option, - passport_number: Option, - license_number: Option, + title: Option, + first_name: Option, + middle_name: Option, + last_name: Option, + address1: Option, + address2: Option, + address3: Option, + city: Option, + state: Option, + postal_code: Option, + country: Option, + company: Option, + email: Option, + phone: Option, + ssn: Option, + username: Option, + passport_number: Option, + license_number: Option, } impl From for JsonIdentity { @@ -210,8 +209,8 @@ impl From for JsonIdentity { #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] struct JsonField { - name: Option, - value: Option, + name: Option, + value: Option, r#type: u8, linked_id: Option, } @@ -279,17 +278,17 @@ mod tests { id: "25c8c414-b446-48e9-a1bd-b10700bbd740".parse().unwrap(), folder_id: Some("942e2984-1b9a-453b-b039-b107012713b9".parse().unwrap()), - name: DecryptedString::test("Bitwarden"), - notes: Some(DecryptedString::test("My note")), + name: "Bitwarden".to_string(), + notes: Some("My note".to_string()), r#type: CipherType::Login(Box::new(Login { - username: Some(DecryptedString::test("test@bitwarden.com")), - password: Some(DecryptedString::test("asdfasdfasdf")), + username: Some("test@bitwarden.com".to_string()), + password: Some("asdfasdfasdf".to_string()), login_uris: vec![LoginUri { - uri: Some(DecryptedString::test("https://vault.bitwarden.com")), + uri: Some("https://vault.bitwarden.com".to_string()), r#match: None, }], - totp: Some(DecryptedString::test("ABC")), + totp: Some("ABC".to_string()), })), favorite: true, @@ -297,31 +296,31 @@ mod tests { fields: vec![ Field { - name: Some(DecryptedString::test("Text")), - value: Some(DecryptedString::test("A")), + name: Some("Text".to_string()), + value: Some("A".to_string()), r#type: 0, linked_id: None, }, Field { - name: Some(DecryptedString::test("Hidden")), - value: Some(DecryptedString::test("B")), + name: Some("Hidden".to_string()), + value: Some("B".to_string()), r#type: 1, linked_id: None, }, Field { - name: Some(DecryptedString::test("Boolean (true)")), - value: Some(DecryptedString::test("true")), + name: Some("Boolean (true)".to_string()), + value: Some("true".to_string()), r#type: 2, linked_id: None, }, Field { - name: Some(DecryptedString::test("Boolean (false)")), - value: Some(DecryptedString::test("false")), + name: Some("Boolean (false)".to_string()), + value: Some("false".to_string()), r#type: 2, linked_id: None, }, Field { - name: Some(DecryptedString::test("Linked")), + name: Some("Linked".to_string()), value: None, r#type: 3, linked_id: Some(101), @@ -407,8 +406,8 @@ mod tests { id: "23f0f877-42b1-4820-a850-b10700bc41eb".parse().unwrap(), folder_id: None, - name: DecryptedString::test("My secure note"), - notes: Some(DecryptedString::test("Very secure!")), + name: "My secure note".to_string(), + notes: Some("Very secure!".to_string()), r#type: CipherType::SecureNote(Box::new(SecureNote { r#type: SecureNoteType::Generic, @@ -457,16 +456,16 @@ mod tests { id: "3ed8de45-48ee-4e26-a2dc-b10701276c53".parse().unwrap(), folder_id: None, - name: DecryptedString::test("My card"), + name: "My card".to_string(), notes: None, r#type: CipherType::Card(Box::new(Card { - cardholder_name: Some(DecryptedString::test("John Doe")), - exp_month: Some(DecryptedString::test("1")), - exp_year: Some(DecryptedString::test("2032")), - code: Some(DecryptedString::test("123")), - brand: Some(DecryptedString::test("Visa")), - number: Some(DecryptedString::test("4111111111111111")), + cardholder_name: Some("John Doe".to_string()), + exp_month: Some("1".to_string()), + exp_year: Some("2032".to_string()), + code: Some("123".to_string()), + brand: Some("Visa".to_string()), + number: Some("4111111111111111".to_string()), })), favorite: false, @@ -517,14 +516,14 @@ mod tests { id: "41cc3bc1-c3d9-4637-876c-b10701273712".parse().unwrap(), folder_id: Some("942e2984-1b9a-453b-b039-b107012713b9".parse().unwrap()), - name: DecryptedString::test("My identity"), + name: "My identity".to_string(), notes: None, r#type: CipherType::Identity(Box::new(Identity { - title: Some(DecryptedString::test("Mr")), - first_name: Some(DecryptedString::test("John")), + title: Some("Mr".to_string()), + first_name: Some("John".to_string()), middle_name: None, - last_name: Some(DecryptedString::test("Doe")), + last_name: Some("Doe".to_string()), address1: None, address2: None, address3: None, @@ -532,11 +531,11 @@ mod tests { state: None, postal_code: None, country: None, - company: Some(DecryptedString::test("Bitwarden")), + company: Some("Bitwarden".to_string()), email: None, phone: None, ssn: None, - username: Some(DecryptedString::test("JDoe")), + username: Some("JDoe".to_string()), passport_number: None, license_number: None, })), @@ -609,24 +608,24 @@ mod tests { let export = export_json( vec![Folder { id: "942e2984-1b9a-453b-b039-b107012713b9".parse().unwrap(), - name: DecryptedString::test("Important"), + name: "Important".to_string(), }], vec![ Cipher { id: "25c8c414-b446-48e9-a1bd-b10700bbd740".parse().unwrap(), folder_id: Some("942e2984-1b9a-453b-b039-b107012713b9".parse().unwrap()), - name: DecryptedString::test("Bitwarden"), - notes: Some(DecryptedString::test("My note")), + name: "Bitwarden".to_string(), + notes: Some("My note".to_string()), r#type: CipherType::Login(Box::new(Login { - username: Some(DecryptedString::test("test@bitwarden.com")), - password: Some(DecryptedString::test("asdfasdfasdf")), + username: Some("test@bitwarden.com".to_string()), + password: Some("asdfasdfasdf".to_string()), login_uris: vec![LoginUri { - uri: Some(DecryptedString::test("https://vault.bitwarden.com")), + uri: Some("https://vault.bitwarden.com".to_string()), r#match: None, }], - totp: Some(DecryptedString::test("ABC")), + totp: Some("ABC".to_string()), })), favorite: true, @@ -634,31 +633,31 @@ mod tests { fields: vec![ Field { - name: Some(DecryptedString::test("Text")), - value: Some(DecryptedString::test("A")), + name: Some("Text".to_string()), + value: Some("A".to_string()), r#type: 0, linked_id: None, }, Field { - name: Some(DecryptedString::test("Hidden")), - value: Some(DecryptedString::test("B")), + name: Some("Hidden".to_string()), + value: Some("B".to_string()), r#type: 1, linked_id: None, }, Field { - name: Some(DecryptedString::test("Boolean (true)")), - value: Some(DecryptedString::test("true")), + name: Some("Boolean (true)".to_string()), + value: Some("true".to_string()), r#type: 2, linked_id: None, }, Field { - name: Some(DecryptedString::test("Boolean (false)")), - value: Some(DecryptedString::test("false")), + name: Some("Boolean (false)".to_string()), + value: Some("false".to_string()), r#type: 2, linked_id: None, }, Field { - name: Some(DecryptedString::test("Linked")), + name: Some("Linked".to_string()), value: None, r#type: 3, linked_id: Some(101), @@ -673,8 +672,8 @@ mod tests { id: "23f0f877-42b1-4820-a850-b10700bc41eb".parse().unwrap(), folder_id: None, - name: DecryptedString::test("My secure note"), - notes: Some(DecryptedString::test("Very secure!")), + name: "My secure note".to_string(), + notes: Some("Very secure!".to_string()), r#type: CipherType::SecureNote(Box::new(SecureNote { r#type: SecureNoteType::Generic, @@ -693,16 +692,16 @@ mod tests { id: "3ed8de45-48ee-4e26-a2dc-b10701276c53".parse().unwrap(), folder_id: None, - name: DecryptedString::test("My card"), + name: "My card".to_string(), notes: None, r#type: CipherType::Card(Box::new(Card { - cardholder_name: Some(DecryptedString::test("John Doe")), - exp_month: Some(DecryptedString::test("1")), - exp_year: Some(DecryptedString::test("2032")), - code: Some(DecryptedString::test("123")), - brand: Some(DecryptedString::test("Visa")), - number: Some(DecryptedString::test("4111111111111111")), + cardholder_name: Some("John Doe".to_string()), + exp_month: Some("1".to_string()), + exp_year: Some("2032".to_string()), + code: Some("123".to_string()), + brand: Some("Visa".to_string()), + number: Some("4111111111111111".to_string()), })), favorite: false, @@ -718,14 +717,14 @@ mod tests { id: "41cc3bc1-c3d9-4637-876c-b10701273712".parse().unwrap(), folder_id: Some("942e2984-1b9a-453b-b039-b107012713b9".parse().unwrap()), - name: DecryptedString::test("My identity"), + name: "My identity".to_string(), notes: None, r#type: CipherType::Identity(Box::new(Identity { - title: Some(DecryptedString::test("Mr")), - first_name: Some(DecryptedString::test("John")), + title: Some("Mr".to_string()), + first_name: Some("John".to_string()), middle_name: None, - last_name: Some(DecryptedString::test("Doe")), + last_name: Some("Doe".to_string()), address1: None, address2: None, address3: None, @@ -733,11 +732,11 @@ mod tests { state: None, postal_code: None, country: None, - company: Some(DecryptedString::test("Bitwarden")), + company: Some("Bitwarden".to_string()), email: None, phone: None, ssn: None, - username: Some(DecryptedString::test("JDoe")), + username: Some("JDoe".to_string()), passport_number: None, license_number: None, })), diff --git a/crates/bitwarden-exporters/src/lib.rs b/crates/bitwarden-exporters/src/lib.rs index 343f978ea..762556388 100644 --- a/crates/bitwarden-exporters/src/lib.rs +++ b/crates/bitwarden-exporters/src/lib.rs @@ -1,6 +1,6 @@ use std::fmt; -use bitwarden_crypto::{DecryptedString, Kdf}; +use bitwarden_crypto::Kdf; use chrono::{DateTime, Utc}; use thiserror::Error; use uuid::Uuid; @@ -25,7 +25,7 @@ pub enum Format { /// that is not tied to the internal vault models. We may revisit this in the future. pub struct Folder { pub id: Uuid, - pub name: DecryptedString, + pub name: String, } /// Export representation of a Bitwarden cipher. @@ -36,8 +36,8 @@ pub struct Cipher { pub id: Uuid, pub folder_id: Option, - pub name: DecryptedString, - pub notes: Option, + pub name: String, + pub notes: Option, pub r#type: CipherType, @@ -53,8 +53,8 @@ pub struct Cipher { #[derive(Clone)] pub struct Field { - pub name: Option, - pub value: Option, + pub name: Option, + pub value: Option, pub r#type: u8, pub linked_id: Option, } @@ -78,24 +78,24 @@ impl fmt::Display for CipherType { } pub struct Login { - pub username: Option, - pub password: Option, + pub username: Option, + pub password: Option, pub login_uris: Vec, - pub totp: Option, + pub totp: Option, } pub struct LoginUri { - pub uri: Option, + pub uri: Option, pub r#match: Option, } pub struct Card { - pub cardholder_name: Option, - pub exp_month: Option, - pub exp_year: Option, - pub code: Option, - pub brand: Option, - pub number: Option, + pub cardholder_name: Option, + pub exp_month: Option, + pub exp_year: Option, + pub code: Option, + pub brand: Option, + pub number: Option, } pub struct SecureNote { @@ -107,24 +107,24 @@ pub enum SecureNoteType { } pub struct Identity { - pub title: Option, - pub first_name: Option, - pub middle_name: Option, - pub last_name: Option, - pub address1: Option, - pub address2: Option, - pub address3: Option, - pub city: Option, - pub state: Option, - pub postal_code: Option, - pub country: Option, - pub company: Option, - pub email: Option, - pub phone: Option, - pub ssn: Option, - pub username: Option, - pub passport_number: Option, - pub license_number: Option, + pub title: Option, + pub first_name: Option, + pub middle_name: Option, + pub last_name: Option, + pub address1: Option, + pub address2: Option, + pub address3: Option, + pub city: Option, + pub state: Option, + pub postal_code: Option, + pub country: Option, + pub company: Option, + pub email: Option, + pub phone: Option, + pub ssn: Option, + pub username: Option, + pub passport_number: Option, + pub license_number: Option, } #[derive(Error, Debug)] diff --git a/crates/bitwarden/src/auth/auth_request.rs b/crates/bitwarden/src/auth/auth_request.rs index bb341bf4d..8c3523d20 100644 --- a/crates/bitwarden/src/auth/auth_request.rs +++ b/crates/bitwarden/src/auth/auth_request.rs @@ -1,7 +1,6 @@ use base64::{engine::general_purpose::STANDARD, Engine}; use bitwarden_crypto::{ fingerprint, AsymmetricCryptoKey, AsymmetricEncString, AsymmetricPublicCryptoKey, - SensitiveString, }; #[cfg(feature = "mobile")] use bitwarden_crypto::{EncString, KeyDecryptable, SymmetricCryptoKey}; @@ -58,13 +57,10 @@ pub(crate) fn auth_request_decrypt_user_key( private_key: String, user_key: AsymmetricEncString, ) -> Result { - use bitwarden_crypto::DecryptedVec; + let key = AsymmetricCryptoKey::from_der(&STANDARD.decode(private_key)?)?; + let mut key: Vec = user_key.decrypt_with_key(&key)?; - let private_key = SensitiveString::new(Box::new(private_key)); - let key = AsymmetricCryptoKey::from_der(private_key.decode_base64(STANDARD)?)?; - let key: DecryptedVec = user_key.decrypt_with_key(&key)?; - - Ok(SymmetricCryptoKey::try_from(key)?) + Ok(SymmetricCryptoKey::try_from(key.as_mut_slice())?) } /// Decrypt the user key using the private key generated previously. @@ -74,12 +70,11 @@ pub(crate) fn auth_request_decrypt_master_key( master_key: AsymmetricEncString, user_key: EncString, ) -> Result { - use bitwarden_crypto::{DecryptedVec, MasterKey}; + use bitwarden_crypto::MasterKey; - let private_key = SensitiveString::new(Box::new(private_key)); - let key = AsymmetricCryptoKey::from_der(private_key.decode_base64(STANDARD)?)?; - let master_key: DecryptedVec = master_key.decrypt_with_key(&key)?; - let master_key = MasterKey::new(SymmetricCryptoKey::try_from(master_key)?); + let key = AsymmetricCryptoKey::from_der(&STANDARD.decode(private_key)?)?; + let mut master_key: Vec = master_key.decrypt_with_key(&key)?; + let master_key = MasterKey::new(SymmetricCryptoKey::try_from(master_key.as_mut_slice())?); Ok(master_key.decrypt_user_key(user_key)?) } @@ -91,8 +86,7 @@ pub(crate) fn approve_auth_request( client: &mut Client, public_key: String, ) -> Result { - let public_key = SensitiveString::new(Box::new(public_key)); - let public_key = AsymmetricPublicCryptoKey::from_der(public_key.decode_base64(STANDARD)?)?; + let public_key = AsymmetricPublicCryptoKey::from_der(&STANDARD.decode(public_key)?)?; let enc = client.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(Error::VaultLocked)?; @@ -114,9 +108,8 @@ fn test_auth_request() { 67, 35, 61, 245, 93, ]; - let private_key = SensitiveString::new(Box::new(request.private_key.clone())); let private_key = - AsymmetricCryptoKey::from_der(private_key.decode_base64(STANDARD).unwrap()).unwrap(); + AsymmetricCryptoKey::from_der(&STANDARD.decode(&request.private_key).unwrap()).unwrap(); let encrypted = AsymmetricEncString::encrypt_rsa2048_oaep_sha1(secret, &private_key).unwrap(); diff --git a/crates/bitwarden/src/auth/login/access_token.rs b/crates/bitwarden/src/auth/login/access_token.rs index f95dda52a..cca52512b 100644 --- a/crates/bitwarden/src/auth/login/access_token.rs +++ b/crates/bitwarden/src/auth/login/access_token.rs @@ -1,9 +1,7 @@ use std::path::{Path, PathBuf}; use base64::engine::general_purpose::STANDARD; -use bitwarden_crypto::{ - DecryptedVec, EncString, KeyDecryptable, SensitiveString, SymmetricCryptoKey, -}; +use bitwarden_crypto::{EncString, KeyDecryptable, SensitiveString, SymmetricCryptoKey}; use chrono::Utc; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -55,8 +53,7 @@ pub(crate) async fn login_access_token( // Extract the encrypted payload and use the access token encryption key to decrypt it let payload: EncString = r.encrypted_payload.parse()?; - let decrypted_payload: DecryptedVec = - payload.decrypt_with_key(&access_token.encryption_key)?; + let decrypted_payload: Vec = payload.decrypt_with_key(&access_token.encryption_key)?; // Once decrypted, we have to JSON decode to extract the organization encryption key #[derive(serde::Deserialize)] @@ -65,7 +62,7 @@ pub(crate) async fn login_access_token( encryption_key: SensitiveString, } - let payload: Payload = serde_json::from_slice(decrypted_payload.expose())?; + let payload: Payload = serde_json::from_slice(&decrypted_payload)?; let encryption_key = payload.encryption_key.clone().decode_base64(STANDARD)?; let encryption_key = SymmetricCryptoKey::try_from(encryption_key)?; diff --git a/crates/bitwarden/src/auth/tde.rs b/crates/bitwarden/src/auth/tde.rs index 9b21aaa18..420448f16 100644 --- a/crates/bitwarden/src/auth/tde.rs +++ b/crates/bitwarden/src/auth/tde.rs @@ -1,7 +1,7 @@ -use base64::engine::general_purpose::STANDARD; +use base64::{engine::general_purpose::STANDARD, Engine}; use bitwarden_crypto::{ - AsymmetricEncString, AsymmetricPublicCryptoKey, DeviceKey, EncString, Kdf, SensitiveString, - SymmetricCryptoKey, TrustDeviceResponse, UserKey, + AsymmetricEncString, AsymmetricPublicCryptoKey, DeviceKey, EncString, Kdf, SymmetricCryptoKey, + TrustDeviceResponse, UserKey, }; use crate::{error::Result, Client}; @@ -15,9 +15,7 @@ pub(super) fn make_register_tde_keys( org_public_key: String, remember_device: bool, ) -> Result { - let public_key = AsymmetricPublicCryptoKey::from_der( - SensitiveString::new(Box::new(org_public_key)).decode_base64(STANDARD)?, - )?; + let public_key = AsymmetricPublicCryptoKey::from_der(&STANDARD.decode(org_public_key)?)?; let mut rng = rand::thread_rng(); diff --git a/crates/bitwarden/src/client/encryption_settings.rs b/crates/bitwarden/src/client/encryption_settings.rs index 463c67815..025b3cec7 100644 --- a/crates/bitwarden/src/client/encryption_settings.rs +++ b/crates/bitwarden/src/client/encryption_settings.rs @@ -42,11 +42,11 @@ impl EncryptionSettings { user_key: SymmetricCryptoKey, private_key: EncString, ) -> Result { - use bitwarden_crypto::{DecryptedVec, KeyDecryptable}; + use bitwarden_crypto::KeyDecryptable; let private_key = { - let dec: DecryptedVec = private_key.decrypt_with_key(&user_key)?; - Some(AsymmetricCryptoKey::from_der(dec)?) + let dec: Vec = private_key.decrypt_with_key(&user_key)?; + Some(AsymmetricCryptoKey::from_der(&dec)?) }; Ok(EncryptionSettings { @@ -71,7 +71,7 @@ impl EncryptionSettings { &mut self, org_enc_keys: Vec<(Uuid, AsymmetricEncString)>, ) -> Result<&mut Self> { - use bitwarden_crypto::{DecryptedVec, KeyDecryptable}; + use bitwarden_crypto::KeyDecryptable; use crate::error::Error; @@ -83,9 +83,9 @@ impl EncryptionSettings { // Decrypt the org keys with the private key for (org_id, org_enc_key) in org_enc_keys { - let dec: DecryptedVec = org_enc_key.decrypt_with_key(private_key)?; + let mut dec: Vec = org_enc_key.decrypt_with_key(private_key)?; - let org_key = SymmetricCryptoKey::try_from(dec)?; + let org_key = SymmetricCryptoKey::try_from(dec.as_mut_slice())?; self.org_keys.insert(org_id, org_key); } diff --git a/crates/bitwarden/src/mobile/crypto.rs b/crates/bitwarden/src/mobile/crypto.rs index 32961249b..4027302df 100644 --- a/crates/bitwarden/src/mobile/crypto.rs +++ b/crates/bitwarden/src/mobile/crypto.rs @@ -267,14 +267,15 @@ pub fn derive_pin_key(client: &mut Client, pin: SensitiveString) -> Result Result { - use bitwarden_crypto::DecryptedString; + use bitwarden_crypto::Sensitive; let user_key = client .get_encryption_settings()? .get_key(&None) .ok_or(Error::VaultLocked)?; - let pin: DecryptedString = encrypted_pin.decrypt_with_key(user_key)?; + let pin: String = encrypted_pin.decrypt_with_key(user_key)?; + let pin = Sensitive::new(Box::new(pin)); let login_method = client .login_method @@ -306,11 +307,10 @@ pub(super) fn enroll_admin_password_reset( client: &mut Client, public_key: String, ) -> Result { - use base64::engine::general_purpose::STANDARD; + use base64::{engine::general_purpose::STANDARD, Engine}; use bitwarden_crypto::AsymmetricPublicCryptoKey; - let public_key = SensitiveString::new(Box::new(public_key)); - let public_key = AsymmetricPublicCryptoKey::from_der(public_key.decode_base64(STANDARD)?)?; + let public_key = AsymmetricPublicCryptoKey::from_der(&STANDARD.decode(public_key)?)?; let enc = client.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(Error::VaultLocked)?; @@ -502,8 +502,8 @@ mod tests { fn test_enroll_admin_password_reset() { use std::num::NonZeroU32; - use base64::engine::general_purpose::STANDARD; - use bitwarden_crypto::{AsymmetricCryptoKey, DecryptedString, DecryptedVec, SensitiveVec}; + use base64::{engine::general_purpose::STANDARD, Engine}; + use bitwarden_crypto::{AsymmetricCryptoKey, SensitiveVec}; let mut client = Client::new(None); @@ -527,16 +527,15 @@ mod tests { let encrypted = enroll_admin_password_reset(&mut client, public_key.to_owned()).unwrap(); let private_key = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzLtEUdxfcLxDj84yaGFsVF5hZ8Hjlb08NMQDy1RnBma06I3ZESshLYzVz4r/gegMn9OOltfV/Yxlyvida8oW6qdlfJ7AVz6Oa8pV7BiL40C7b76+oqraQpyYw2HChANB1AhXL9SqWngKmLZwjA7qiCrmcc0kZHeOb4KnKtp9iVvPVs+8veFvKgYO4ba2AAOHKFdR0W55/agXfAy+fWUAkC8mc9ikyJdQWaPV6OZvC2XFkOseBQm9Rynudh3BQpoWiL6w620efe7t5k+02/EyOFJL9f/XEEjM/+Yo0t3LAfkuhHGeKiRST59Xc9hTEmyJTeVXROtz+0fjqOp3xkaObAgMBAAECggEACs4xhnO0HaZhh1/iH7zORMIRXKeyxP2LQiTR8xwN5JJ9wRWmGAR9VasS7EZFTDidIGVME2u/h4s5EqXnhxfO+0gGksVvgNXJ/qw87E8K2216g6ZNo6vSGA7H1GH2voWwejJ4/k/cJug6dz2S402rRAKh2Wong1arYHSkVlQp3diiMa5FHAOSE+Cy09O2ZsaF9IXQYUtlW6AVXFrBEPYH2kvkaPXchh8VETMijo6tbvoKLnUHe+wTaDMls7hy8exjtVyI59r3DNzjy1lNGaGb5QSnFMXR+eHhPZc844Wv02MxC15zKABADrl58gpJyjTl6XpDdHCYGsmGpVGH3X9TQQKBgQDz/9beFjzq59ve6rGwn+EtnQfSsyYT+jr7GN8lNEXb3YOFXBgPhfFIcHRh2R00Vm9w2ApfAx2cd8xm2I6HuvQ1Os7g26LWazvuWY0Qzb+KaCLQTEGH1RnTq6CCG+BTRq/a3J8M4t38GV5TWlzv8wr9U4dl6FR4efjb65HXs1GQ4QKBgQC7/uHfrOTEHrLeIeqEuSl0vWNqEotFKdKLV6xpOvNuxDGbgW4/r/zaxDqt0YBOXmRbQYSEhmO3oy9J6XfE1SUln0gbavZeW0HESCAmUIC88bDnspUwS9RxauqT5aF8ODKN/bNCWCnBM1xyonPOs1oT1nyparJVdQoG//Y7vkB3+wKBgBqLqPq8fKAp3XfhHLfUjREDVoiLyQa/YI9U42IOz9LdxKNLo6p8rgVthpvmnRDGnpUuS+KOWjhdqDVANjF6G3t3DG7WNl8Rh5Gk2H4NhFswfSkgQrjebFLlBy9gjQVCWXt8KSmjvPbiY6q52Aaa8IUjA0YJAregvXxfopxO+/7BAoGARicvEtDp7WWnSc1OPoj6N14VIxgYcI7SyrzE0d/1x3ffKzB5e7qomNpxKzvqrVP8DzG7ydh8jaKPmv1MfF8tpYRy3AhmN3/GYwCnPqT75YYrhcrWcVdax5gmQVqHkFtIQkRSCIftzPLlpMGKha/YBV8c1fvC4LD0NPh/Ynv0gtECgYEAyOZg95/kte0jpgUEgwuMrzkhY/AaUJULFuR5MkyvReEbtSBQwV5tx60+T95PHNiFooWWVXiLMsAgyI2IbkxVR1Pzdri3gWK5CTfqb7kLuaj/B7SGvBa2Sxo478KS5K8tBBBWkITqo+wLC0mn3uZi1dyMWO1zopTA+KtEGF2dtGQ="; - let private_key = DecryptedString::test(private_key); let private_key = - AsymmetricCryptoKey::from_der(private_key.decode_base64(STANDARD).unwrap()).unwrap(); - let decrypted: DecryptedVec = encrypted.decrypt_with_key(&private_key).unwrap(); + AsymmetricCryptoKey::from_der(&STANDARD.decode(private_key).unwrap()).unwrap(); + let decrypted: Vec = encrypted.decrypt_with_key(&private_key).unwrap(); let expected = client .get_encryption_settings() .unwrap() .get_key(&None) .unwrap(); - assert_eq!(decrypted.expose(), expected.to_vec().expose()); + assert_eq!(&decrypted, expected.to_vec().expose()); } } diff --git a/crates/bitwarden/src/mobile/vault/client_attachments.rs b/crates/bitwarden/src/mobile/vault/client_attachments.rs index cfe23d414..e40721b04 100644 --- a/crates/bitwarden/src/mobile/vault/client_attachments.rs +++ b/crates/bitwarden/src/mobile/vault/client_attachments.rs @@ -65,7 +65,6 @@ impl<'a> ClientAttachments<'a> { } .decrypt_with_key(key) .map_err(Error::Crypto) - .map(|s| s.expose().to_owned()) } pub async fn decrypt_file( &self, diff --git a/crates/bitwarden/src/mobile/vault/client_sends.rs b/crates/bitwarden/src/mobile/vault/client_sends.rs index bc0d08e88..47d3b666f 100644 --- a/crates/bitwarden/src/mobile/vault/client_sends.rs +++ b/crates/bitwarden/src/mobile/vault/client_sends.rs @@ -1,6 +1,6 @@ use std::path::Path; -use bitwarden_crypto::{DecryptedVec, EncString, KeyDecryptable, KeyEncryptable}; +use bitwarden_crypto::{EncString, KeyDecryptable, KeyEncryptable}; use super::client_vault::ClientVault; use crate::{ @@ -50,8 +50,7 @@ impl<'a> ClientSends<'a> { let key = Send::get_key(&send.key, key)?; let buf = EncString::from_buffer(encrypted_buffer)?; - let dec: DecryptedVec = buf.decrypt_with_key(&key)?; - Ok(dec.expose().to_owned()) + Ok(buf.decrypt_with_key(&key)?) } pub async fn encrypt(&self, send_view: SendView) -> Result { diff --git a/crates/bitwarden/src/platform/fido2/authenticator.rs b/crates/bitwarden/src/platform/fido2/authenticator.rs index 9f35a682d..6231f86bf 100644 --- a/crates/bitwarden/src/platform/fido2/authenticator.rs +++ b/crates/bitwarden/src/platform/fido2/authenticator.rs @@ -125,8 +125,8 @@ impl<'a> Fido2Authenticator<'a> { folder_id: None, collection_ids: vec![], key: None, - name: SensitiveString::new(Box::new("".to_string())), - notes: Some(SensitiveString::new(Box::new("".to_string()))), + name: "".to_string(), + notes: Some("".to_string()), r#type: crate::vault::CipherType::Login, login: Some(LoginView { username: None, diff --git a/crates/bitwarden/src/platform/fido2/client.rs b/crates/bitwarden/src/platform/fido2/client.rs index a175e17bb..618d1a9fb 100644 --- a/crates/bitwarden/src/platform/fido2/client.rs +++ b/crates/bitwarden/src/platform/fido2/client.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; -use bitwarden_crypto::{KeyEncryptable, SensitiveString}; +use bitwarden_crypto::KeyEncryptable; use passkey::{authenticator::Authenticator, types::ctap2::Aaguid}; use reqwest::Url; use serde::Serialize; @@ -84,8 +84,8 @@ impl<'a> Fido2Client<'a> { folder_id: None, collection_ids: vec![], key: None, - name: SensitiveString::new(Box::new("".to_string())), - notes: Some(SensitiveString::new(Box::new("".to_string()))), + name: "".to_string(), + notes: Some("".to_string()), r#type: crate::vault::CipherType::Login, login: Some(LoginView { username: None, @@ -192,8 +192,8 @@ impl<'a> Fido2Client<'a> { folder_id: None, collection_ids: vec![], key: None, - name: SensitiveString::new(Box::new("".to_string())), - notes: Some(SensitiveString::new(Box::new("".to_string()))), + name: "".to_string(), + notes: Some("".to_string()), r#type: crate::vault::CipherType::Login, login: Some(LoginView { username: None, diff --git a/crates/bitwarden/src/secrets_manager/projects/project_response.rs b/crates/bitwarden/src/secrets_manager/projects/project_response.rs index bf56f2006..82e98dff0 100644 --- a/crates/bitwarden/src/secrets_manager/projects/project_response.rs +++ b/crates/bitwarden/src/secrets_manager/projects/project_response.rs @@ -1,5 +1,5 @@ use bitwarden_api_api::models::ProjectResponseModel; -use bitwarden_crypto::{CryptoError, DecryptedString, EncString, KeyDecryptable}; +use bitwarden_crypto::{CryptoError, EncString, KeyDecryptable}; use chrono::{DateTime, Utc}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -30,14 +30,14 @@ impl ProjectResponse { .get_key(&Some(organization_id)) .ok_or(CryptoError::MissingKey)?; - let name: DecryptedString = require!(response.name) + let name = require!(response.name) .parse::()? .decrypt_with_key(enc_key)?; Ok(ProjectResponse { id: require!(response.id), organization_id, - name: name.expose().to_owned(), + name, creation_date: require!(response.creation_date).parse()?, revision_date: require!(response.revision_date).parse()?, diff --git a/crates/bitwarden/src/secrets_manager/secrets/list.rs b/crates/bitwarden/src/secrets_manager/secrets/list.rs index b2473dd88..6cfa85516 100644 --- a/crates/bitwarden/src/secrets_manager/secrets/list.rs +++ b/crates/bitwarden/src/secrets_manager/secrets/list.rs @@ -1,7 +1,7 @@ use bitwarden_api_api::models::{ SecretWithProjectsListResponseModel, SecretsWithProjectsInnerSecret, }; -use bitwarden_crypto::{CryptoError, DecryptedString, EncString, KeyDecryptable}; +use bitwarden_crypto::{CryptoError, EncString, KeyDecryptable}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -98,14 +98,14 @@ impl SecretIdentifierResponse { .get_key(&Some(organization_id)) .ok_or(CryptoError::MissingKey)?; - let key: DecryptedString = require!(response.key) + let key = require!(response.key) .parse::()? .decrypt_with_key(enc_key)?; Ok(SecretIdentifierResponse { id: require!(response.id), organization_id, - key: key.expose().to_owned(), + key, }) } } diff --git a/crates/bitwarden/src/secrets_manager/secrets/secret_response.rs b/crates/bitwarden/src/secrets_manager/secrets/secret_response.rs index 6f7446362..3b89629a4 100644 --- a/crates/bitwarden/src/secrets_manager/secrets/secret_response.rs +++ b/crates/bitwarden/src/secrets_manager/secrets/secret_response.rs @@ -1,7 +1,7 @@ use bitwarden_api_api::models::{ BaseSecretResponseModel, BaseSecretResponseModelListResponseModel, SecretResponseModel, }; -use bitwarden_crypto::{CryptoError, DecryptedString, EncString, KeyDecryptable}; +use bitwarden_crypto::{CryptoError, EncString, KeyDecryptable}; use chrono::{DateTime, Utc}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -52,13 +52,13 @@ impl SecretResponse { let org_id = response.organization_id; let enc_key = enc.get_key(&org_id).ok_or(CryptoError::MissingKey)?; - let key: DecryptedString = require!(response.key) + let key = require!(response.key) .parse::()? .decrypt_with_key(enc_key)?; - let value: DecryptedString = require!(response.value) + let value = require!(response.value) .parse::()? .decrypt_with_key(enc_key)?; - let note: DecryptedString = require!(response.note) + let note = require!(response.note) .parse::()? .decrypt_with_key(enc_key)?; @@ -71,9 +71,9 @@ impl SecretResponse { id: require!(response.id), organization_id: require!(org_id), project_id: project, - key: key.expose().to_owned(), - value: value.expose().to_owned(), - note: note.expose().to_owned(), + key, + value, + note, creation_date: require!(response.creation_date).parse()?, revision_date: require!(response.revision_date).parse()?, diff --git a/crates/bitwarden/src/secrets_manager/state.rs b/crates/bitwarden/src/secrets_manager/state.rs index aadea564d..c677ab7e9 100644 --- a/crates/bitwarden/src/secrets_manager/state.rs +++ b/crates/bitwarden/src/secrets_manager/state.rs @@ -1,8 +1,6 @@ use std::{fmt::Debug, path::Path}; -use bitwarden_crypto::{ - DecryptedString, EncString, KeyDecryptable, KeyEncryptable, SensitiveString, -}; +use bitwarden_crypto::{EncString, KeyDecryptable, KeyEncryptable, SensitiveString}; use serde::{Deserialize, Serialize}; use crate::{ @@ -34,9 +32,8 @@ pub fn get(state_file: &Path, access_token: &AccessToken) -> Result let file_content = std::fs::read_to_string(state_file)?; let encrypted_state: EncString = file_content.parse()?; - let decrypted_state: DecryptedString = - encrypted_state.decrypt_with_key(&access_token.encryption_key)?; - let client_state: ClientState = serde_json::from_str(decrypted_state.expose())?; + let decrypted_state: String = encrypted_state.decrypt_with_key(&access_token.encryption_key)?; + let client_state: ClientState = serde_json::from_str(&decrypted_state)?; if client_state.version != STATE_VERSION { return Err(Error::InvalidStateFileVersion); diff --git a/crates/bitwarden/src/tool/exporters/mod.rs b/crates/bitwarden/src/tool/exporters/mod.rs index 9a28209b0..120ecd8ec 100644 --- a/crates/bitwarden/src/tool/exporters/mod.rs +++ b/crates/bitwarden/src/tool/exporters/mod.rs @@ -207,7 +207,7 @@ impl From for bitwarden_exporters::SecureNoteType { mod tests { use std::num::NonZeroU32; - use bitwarden_crypto::{DecryptedString, Kdf}; + use bitwarden_crypto::Kdf; use chrono::{DateTime, Utc}; use super::*; @@ -217,7 +217,7 @@ mod tests { fn test_try_from_folder_view() { let view = FolderView { id: Some("fd411a1a-fec8-4070-985d-0e6560860e69".parse().unwrap()), - name: DecryptedString::test("test_name"), + name: "test_name".to_string(), revision_date: "2024-01-30T17:55:36.150Z".parse().unwrap(), }; @@ -227,7 +227,7 @@ mod tests { f.id, "fd411a1a-fec8-4070-985d-0e6560860e69".parse().unwrap() ); - assert_eq!(f.name.expose(), "test_name"); + assert_eq!(f.name, "test_name".to_string()); } #[test] @@ -235,8 +235,8 @@ mod tests { let cipher_view = CipherView { r#type: CipherType::Login, login: Some(LoginView { - username: Some(DecryptedString::test("test_username")), - password: Some(DecryptedString::test("test_password")), + username: Some("test_username".to_string()), + password: Some("test_password".to_string()), password_revision_date: None, uris: None, totp: None, @@ -248,7 +248,7 @@ mod tests { folder_id: None, collection_ids: vec![], key: None, - name: DecryptedString::test("My login"), + name: "My login".to_string(), notes: None, identity: None, card: None, @@ -274,7 +274,7 @@ mod tests { "fd411a1a-fec8-4070-985d-0e6560860e69".parse().unwrap() ); assert_eq!(cipher.folder_id, None); - assert_eq!(cipher.name.expose(), "My login"); + assert_eq!(cipher.name, "My login".to_string()); assert_eq!(cipher.notes, None); assert!(!cipher.favorite); assert_eq!(cipher.reprompt, 0); @@ -290,8 +290,8 @@ mod tests { assert_eq!(cipher.deleted_date, None); if let bitwarden_exporters::CipherType::Login(l) = cipher.r#type { - assert_eq!(l.username.unwrap().expose(), "test_username"); - assert_eq!(l.password.unwrap().expose(), "test_password"); + assert_eq!(l.username, Some("test_username".to_string())); + assert_eq!(l.password, Some("test_password".to_string())); assert!(l.login_uris.is_empty()); assert_eq!(l.totp, None); } else { diff --git a/crates/bitwarden/src/vault/cipher/attachment.rs b/crates/bitwarden/src/vault/cipher/attachment.rs index 796ce84bd..d314b8603 100644 --- a/crates/bitwarden/src/vault/cipher/attachment.rs +++ b/crates/bitwarden/src/vault/cipher/attachment.rs @@ -1,6 +1,5 @@ use bitwarden_crypto::{ - CryptoError, DecryptedString, DecryptedVec, EncString, KeyDecryptable, KeyEncryptable, - SymmetricCryptoKey, + CryptoError, EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -29,7 +28,7 @@ pub struct AttachmentView { pub url: Option, pub size: Option, pub size_name: Option, - pub file_name: Option, + pub file_name: Option, pub key: Option, } @@ -81,18 +80,18 @@ impl<'a> KeyEncryptable for Attachm } } -impl KeyDecryptable for AttachmentFile { - fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { +impl KeyDecryptable> for AttachmentFile { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result, CryptoError> { let ciphers_key = Cipher::get_cipher_key(key, &self.cipher.key)?; let ciphers_key = ciphers_key.as_ref().unwrap_or(key); - let attachment_key: DecryptedVec = self + let mut attachment_key: Vec = self .attachment .key .as_ref() .ok_or(CryptoError::MissingKey)? .decrypt_with_key(ciphers_key)?; - let attachment_key = SymmetricCryptoKey::try_from(attachment_key)?; + let attachment_key = SymmetricCryptoKey::try_from(attachment_key.as_mut_slice())?; self.contents.decrypt_with_key(&attachment_key) } @@ -200,6 +199,6 @@ mod tests { .decrypt_with_key(&user_key) .unwrap(); - assert_eq!(dec.expose(), &original); + assert_eq!(dec, original); } } diff --git a/crates/bitwarden/src/vault/cipher/card.rs b/crates/bitwarden/src/vault/cipher/card.rs index 3635cb2ec..19844ed81 100644 --- a/crates/bitwarden/src/vault/cipher/card.rs +++ b/crates/bitwarden/src/vault/cipher/card.rs @@ -1,6 +1,6 @@ use bitwarden_api_api::models::CipherCardModel; use bitwarden_crypto::{ - CryptoError, DecryptedString, EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey, + CryptoError, EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -23,12 +23,12 @@ pub struct Card { #[serde(rename_all = "camelCase", deny_unknown_fields)] #[cfg_attr(feature = "mobile", derive(uniffi::Record))] pub struct CardView { - pub cardholder_name: Option, - pub exp_month: Option, - pub exp_year: Option, - pub code: Option, - pub brand: Option, - pub number: Option, + pub cardholder_name: Option, + pub exp_month: Option, + pub exp_year: Option, + pub code: Option, + pub brand: Option, + pub number: Option, } impl KeyEncryptable for CardView { diff --git a/crates/bitwarden/src/vault/cipher/cipher.rs b/crates/bitwarden/src/vault/cipher/cipher.rs index 46cf06136..caab4c1e3 100644 --- a/crates/bitwarden/src/vault/cipher/cipher.rs +++ b/crates/bitwarden/src/vault/cipher/cipher.rs @@ -1,7 +1,7 @@ use bitwarden_api_api::models::CipherDetailsResponseModel; use bitwarden_crypto::{ - CryptoError, DecryptedString, DecryptedVec, EncString, KeyContainer, KeyDecryptable, - KeyEncryptable, LocateKey, SensitiveString, SymmetricCryptoKey, + CryptoError, EncString, KeyContainer, KeyDecryptable, KeyEncryptable, LocateKey, SensitiveVec, + SymmetricCryptoKey, }; use chrono::{DateTime, Utc}; use schemars::JsonSchema; @@ -86,8 +86,8 @@ pub struct CipherView { pub key: Option, - pub name: DecryptedString, - pub notes: Option, + pub name: String, + pub notes: Option, pub r#type: CipherType, pub login: Option, @@ -120,8 +120,8 @@ pub struct CipherListView { pub folder_id: Option, pub collection_ids: Vec, - pub name: DecryptedString, - pub sub_title: DecryptedString, + pub name: String, + pub sub_title: String, pub r#type: CipherType, @@ -230,135 +230,77 @@ impl Cipher { ciphers_key .as_ref() .map(|k| { - let key: DecryptedVec = k.decrypt_with_key(key)?; - SymmetricCryptoKey::try_from(key) + let mut key: Vec = k.decrypt_with_key(key)?; + SymmetricCryptoKey::try_from(key.as_mut_slice()) }) .transpose() } - fn get_decrypted_subtitle( - &self, - key: &SymmetricCryptoKey, - ) -> Result { + fn get_decrypted_subtitle(&self, key: &SymmetricCryptoKey) -> Result { Ok(match self.r#type { CipherType::Login => { let Some(login) = &self.login else { - return Ok(SensitiveString::default()); + return Ok(String::new()); }; login.username.decrypt_with_key(key)?.unwrap_or_default() } - CipherType::SecureNote => SensitiveString::default(), + CipherType::SecureNote => String::new(), CipherType::Card => { let Some(card) = &self.card else { - return Ok(SensitiveString::default()); + return Ok(String::new()); }; - - build_subtitle_card( - card.brand - .as_ref() - .map(|b| b.decrypt_with_key(key)) - .transpose()?, - card.number - .as_ref() - .map(|n| n.decrypt_with_key(key)) - .transpose()?, - ) + let mut sub_title = String::new(); + + if let Some(brand) = &card.brand { + let brand: String = brand.decrypt_with_key(key)?; + sub_title.push_str(&brand); + } + + if let Some(number) = &card.number { + let number: String = number.decrypt_with_key(key)?; + let number_len = number.len(); + if number_len > 4 { + if !sub_title.is_empty() { + sub_title.push_str(", "); + } + + // On AMEX cards we show 5 digits instead of 4 + let digit_count = match &number[0..2] { + "34" | "37" => 5, + _ => 4, + }; + + sub_title.push_str(&number[(number_len - digit_count)..]); + } + } + + sub_title } CipherType::Identity => { let Some(identity) = &self.identity else { - return Ok(SensitiveString::default()); + return Ok(String::new()); }; - - build_subtitle_identity( - identity - .first_name - .as_ref() - .map(|f| f.decrypt_with_key(key)) - .transpose()?, - identity - .last_name - .as_ref() - .map(|l| l.decrypt_with_key(key)) - .transpose()?, - ) + let mut sub_title = String::new(); + + if let Some(first_name) = &identity.first_name { + let first_name: String = first_name.decrypt_with_key(key)?; + sub_title.push_str(&first_name); + } + + if let Some(last_name) = &identity.last_name { + if !sub_title.is_empty() { + sub_title.push(' '); + } + let last_name: String = last_name.decrypt_with_key(key)?; + sub_title.push_str(&last_name); + } + + sub_title } }) } } -/// Builds the subtitle for a card cipher -/// -/// Care is taken to avoid leaking sensitive data by allocating the full size of the subtitle -fn build_subtitle_card( - brand: Option, - number: Option, -) -> SensitiveString { - let brand: Option = brand.filter(|b: &SensitiveString| !b.expose().is_empty()); - - // We only want to expose the last 4 or 5 digits of the card number - let number: Option = number - .filter(|b: &SensitiveString| b.expose().len() > 4) - .map(|n| { - // For AMEX cards show 5 digits instead of 4 - let desired_len = match &n.expose()[0..2] { - "34" | "37" => 5, - _ => 4, - }; - let start = n.expose().len() - desired_len; - - let mut str = SensitiveString::new(Box::new(String::with_capacity(desired_len + 1))); - str.expose_mut().push('*'); - str.expose_mut().push_str(&n.expose()[start..]); - - str - }); - - match (brand, number) { - (Some(brand), Some(number)) => { - let length = brand.expose().len() + 2 + number.expose().len(); - - let mut str = SensitiveString::new(Box::new(String::with_capacity(length))); - str.expose_mut().push_str(brand.expose()); - str.expose_mut().push_str(", "); - str.expose_mut().push_str(number.expose()); - - str - } - (Some(brand), None) => brand, - (None, Some(number)) => number, - _ => SensitiveString::new(Box::new("".to_owned())), - } -} - -/// Builds the subtitle for a card cipher -/// -/// Care is taken to avoid leaking sensitive data by allocating the full size of the subtitle -fn build_subtitle_identity( - first_name: Option, - last_name: Option, -) -> SensitiveString { - let first_name: Option = - first_name.filter(|f: &SensitiveString| !f.expose().is_empty()); - let last_name: Option = - last_name.filter(|l: &SensitiveString| !l.expose().is_empty()); - - match (first_name, last_name) { - (Some(first_name), Some(last_name)) => { - let length = first_name.expose().len() + 1 + last_name.expose().len(); - - let mut str = SensitiveString::new(Box::new(String::with_capacity(length))); - str.expose_mut().push_str(first_name.expose()); - str.expose_mut().push(' '); - str.expose_mut().push_str(last_name.expose()); - - str - } - (Some(first_name), None) => first_name, - (None, Some(last_name)) => last_name, - _ => SensitiveString::new(Box::new("".to_owned())), - } -} - impl CipherView { pub fn generate_cipher_key(&mut self, key: &SymmetricCryptoKey) -> Result<()> { let ciphers_key = Cipher::get_cipher_key(key, &self.key)?; @@ -399,7 +341,7 @@ impl CipherView { .get_key(&Some(organization_id)) .ok_or(Error::VaultLocked)?; - let dec_cipher_key: DecryptedVec = cipher_key.decrypt_with_key(old_key)?; + let dec_cipher_key = SensitiveVec::new(Box::new(cipher_key.decrypt_with_key(old_key)?)); *cipher_key = dec_cipher_key.expose().encrypt_with_key(new_key)?; } @@ -532,8 +474,8 @@ mod tests { CipherView { r#type: CipherType::Login, login: Some(login::LoginView { - username: Some(DecryptedString::test("test_username")), - password: Some(DecryptedString::test("test_password")), + username: Some("test_username".to_string()), + password: Some("test_password".to_string()), password_revision_date: None, uris: None, totp: None, @@ -545,7 +487,7 @@ mod tests { folder_id: None, collection_ids: vec![], key: None, - name: DecryptedString::test("My test login"), + name: "My test login".to_string(), notes: None, identity: None, card: None, @@ -618,7 +560,7 @@ mod tests { let cipher_enc = cipher.encrypt_with_key(org_key).unwrap(); let cipher_dec: CipherView = cipher_enc.decrypt_with_key(org_key).unwrap(); - assert_eq!(cipher_dec.name.expose(), "My test login"); + assert_eq!(cipher_dec.name, "My test login"); } #[test] @@ -643,94 +585,4 @@ mod tests { let org_key = enc.get_key(&Some(org)).unwrap(); assert!(cipher.encrypt_with_key(org_key).is_err()); } - - #[test] - fn test_build_subtitle_card_visa() { - let brand = Some(DecryptedString::test("Visa")); - let number = Some(DecryptedString::test("4111111111111111")); - - let subtitle = build_subtitle_card(brand, number); - assert_eq!(subtitle.expose(), "Visa, *1111"); - } - - #[test] - fn test_build_subtitle_card_mastercard() { - let brand = Some(DecryptedString::test("Mastercard")); - let number = Some(DecryptedString::test("5555555555554444")); - - let subtitle = build_subtitle_card(brand, number); - assert_eq!(subtitle.expose(), "Mastercard, *4444"); - } - - #[test] - fn test_build_subtitle_card_amex() { - let brand = Some(DecryptedString::test("Amex")); - let number = Some(DecryptedString::test("378282246310005")); - - let subtitle = build_subtitle_card(brand, number); - assert_eq!(subtitle.expose(), "Amex, *10005"); - } - - #[test] - fn test_build_subtitle_card_underflow() { - let brand = Some(DecryptedString::test("Mastercard")); - let number = Some(DecryptedString::test("4")); - - let subtitle = build_subtitle_card(brand, number); - assert_eq!(subtitle.expose(), "Mastercard"); - } - - #[test] - fn test_build_subtitle_card_only_brand() { - let brand = Some(DecryptedString::test("Mastercard")); - let number = None; - - let subtitle = build_subtitle_card(brand, number); - assert_eq!(subtitle.expose(), "Mastercard"); - } - - #[test] - fn test_build_subtitle_card_only_card() { - let brand = None; - let number = Some(DecryptedString::test("5555555555554444")); - - let subtitle = build_subtitle_card(brand, number); - assert_eq!(subtitle.expose(), "*4444"); - } - - #[test] - fn test_build_subtitle_identity() { - let first_name = Some(DecryptedString::test("John")); - let last_name = Some(DecryptedString::test("Doe")); - - let subtitle = build_subtitle_identity(first_name, last_name); - assert_eq!(subtitle.expose(), "John Doe"); - } - - #[test] - fn test_build_subtitle_identity_only_first() { - let first_name = Some(DecryptedString::test("John")); - let last_name = None; - - let subtitle = build_subtitle_identity(first_name, last_name); - assert_eq!(subtitle.expose(), "John"); - } - - #[test] - fn test_build_subtitle_identity_only_last() { - let first_name = None; - let last_name = Some(DecryptedString::test("Doe")); - - let subtitle = build_subtitle_identity(first_name, last_name); - assert_eq!(subtitle.expose(), "Doe"); - } - - #[test] - fn test_build_subtitle_identity_none() { - let first_name = None; - let last_name = None; - - let subtitle = build_subtitle_identity(first_name, last_name); - assert_eq!(subtitle.expose(), ""); - } } diff --git a/crates/bitwarden/src/vault/cipher/field.rs b/crates/bitwarden/src/vault/cipher/field.rs index 04837bf9e..431a3409e 100644 --- a/crates/bitwarden/src/vault/cipher/field.rs +++ b/crates/bitwarden/src/vault/cipher/field.rs @@ -1,6 +1,6 @@ use bitwarden_api_api::models::CipherFieldModel; use bitwarden_crypto::{ - CryptoError, DecryptedString, EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey, + CryptoError, EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -34,8 +34,8 @@ pub struct Field { #[serde(rename_all = "camelCase", deny_unknown_fields)] #[cfg_attr(feature = "mobile", derive(uniffi::Record))] pub struct FieldView { - pub(crate) name: Option, - pub(crate) value: Option, + pub(crate) name: Option, + pub(crate) value: Option, pub(crate) r#type: FieldType, pub(crate) linked_id: Option, diff --git a/crates/bitwarden/src/vault/cipher/identity.rs b/crates/bitwarden/src/vault/cipher/identity.rs index f131fd597..865bf0850 100644 --- a/crates/bitwarden/src/vault/cipher/identity.rs +++ b/crates/bitwarden/src/vault/cipher/identity.rs @@ -1,6 +1,6 @@ use bitwarden_api_api::models::CipherIdentityModel; use bitwarden_crypto::{ - CryptoError, DecryptedString, EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey, + CryptoError, EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -35,24 +35,24 @@ pub struct Identity { #[serde(rename_all = "camelCase", deny_unknown_fields)] #[cfg_attr(feature = "mobile", derive(uniffi::Record))] pub struct IdentityView { - pub title: Option, - pub first_name: Option, - pub middle_name: Option, - pub last_name: Option, - pub address1: Option, - pub address2: Option, - pub address3: Option, - pub city: Option, - pub state: Option, - pub postal_code: Option, - pub country: Option, - pub company: Option, - pub email: Option, - pub phone: Option, - pub ssn: Option, - pub username: Option, - pub passport_number: Option, - pub license_number: Option, + pub title: Option, + pub first_name: Option, + pub middle_name: Option, + pub last_name: Option, + pub address1: Option, + pub address2: Option, + pub address3: Option, + pub city: Option, + pub state: Option, + pub postal_code: Option, + pub country: Option, + pub company: Option, + pub email: Option, + pub phone: Option, + pub ssn: Option, + pub username: Option, + pub passport_number: Option, + pub license_number: Option, } impl KeyEncryptable for IdentityView { diff --git a/crates/bitwarden/src/vault/cipher/login.rs b/crates/bitwarden/src/vault/cipher/login.rs index c40e24de3..54b4dc27f 100644 --- a/crates/bitwarden/src/vault/cipher/login.rs +++ b/crates/bitwarden/src/vault/cipher/login.rs @@ -1,15 +1,12 @@ -use base64::engine::general_purpose::STANDARD; +use base64::{engine::general_purpose::STANDARD, Engine}; use bitwarden_api_api::models::{CipherLoginModel, CipherLoginUriModel}; use bitwarden_crypto::{ - CryptoError, DecryptedString, EncString, KeyDecryptable, KeyEncryptable, Sensitive, - SensitiveString, SensitiveVec, SymmetricCryptoKey, + CryptoError, EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey, }; use chrono::{DateTime, Utc}; -use hmac::digest::generic_array::GenericArray; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; -use sha2::Digest; use crate::error::{require, Error, Result}; @@ -39,9 +36,9 @@ pub struct LoginUri { #[serde(rename_all = "camelCase", deny_unknown_fields)] #[cfg_attr(feature = "mobile", derive(uniffi::Record))] pub struct LoginUriView { - pub uri: Option, + pub uri: Option, pub r#match: Option, - pub uri_checksum: Option, + pub uri_checksum: Option, } impl LoginUriView { @@ -52,28 +49,22 @@ impl LoginUriView { let Some(cs) = &self.uri_checksum else { return false; }; - let Ok(cs) = cs.clone().decode_base64(STANDARD) else { + let Ok(cs) = STANDARD.decode(cs) else { return false; }; - let uri_hash: Sensitive> = Sensitive::new(Box::new( - sha2::Sha256::new() - .chain_update(uri.expose().as_bytes()) - .finalize(), - )); + use sha2::Digest; + let uri_hash = sha2::Sha256::new().chain_update(uri.as_bytes()).finalize(); - uri_hash.expose().as_slice() == cs.expose() + uri_hash.as_slice() == cs } pub(crate) fn generate_checksum(&mut self) { if let Some(uri) = &self.uri { - let uri_hash: SensitiveVec = Sensitive::new(Box::new( - sha2::Sha256::new() - .chain_update(uri.expose().as_bytes()) - .finalize(), - )) - .into(); - self.uri_checksum = Some(uri_hash.encode_base64(STANDARD)) + use sha2::Digest; + let uri_hash = sha2::Sha256::new().chain_update(uri.as_bytes()).finalize(); + let uri_hash = STANDARD.encode(uri_hash.as_slice()); + self.uri_checksum = Some(uri_hash); } } } @@ -101,18 +92,18 @@ pub struct Fido2Credential { #[serde(rename_all = "camelCase", deny_unknown_fields)] #[cfg_attr(feature = "mobile", derive(uniffi::Record))] pub struct Fido2CredentialView { - pub credential_id: SensitiveString, - pub key_type: SensitiveString, - pub key_algorithm: SensitiveString, - pub key_curve: SensitiveString, - pub key_value: SensitiveString, - pub rp_id: SensitiveString, - pub user_handle: Option, - pub user_name: Option, - pub counter: SensitiveString, - pub rp_name: Option, - pub user_display_name: Option, - pub discoverable: SensitiveString, + pub credential_id: String, + pub key_type: String, + pub key_algorithm: String, + pub key_curve: String, + pub key_value: String, + pub rp_id: String, + pub user_handle: Option, + pub user_name: Option, + pub counter: String, + pub rp_name: Option, + pub user_display_name: Option, + pub discoverable: String, pub creation_date: DateTime, } @@ -135,12 +126,12 @@ pub struct Login { #[serde(rename_all = "camelCase", deny_unknown_fields)] #[cfg_attr(feature = "mobile", derive(uniffi::Record))] pub struct LoginView { - pub username: Option, - pub password: Option, + pub username: Option, + pub password: Option, pub password_revision_date: Option>, pub uris: Option>, - pub totp: Option, + pub totp: Option, pub autofill_on_page_load: Option, // TODO: Remove this once the SDK supports state @@ -316,16 +307,12 @@ impl TryFrom for Fido2Cre #[cfg(test)] mod tests { - use bitwarden_crypto::SensitiveString; - #[test] fn test_valid_checksum() { let uri = super::LoginUriView { - uri: Some(SensitiveString::test("https://example.com")), + uri: Some("https://example.com".to_string()), r#match: Some(super::UriMatchType::Domain), - uri_checksum: Some(SensitiveString::test( - "EAaArVRs5qV39C9S3zO0z9ynVoWeZkuNfeMpsVDQnOk=", - )), + uri_checksum: Some("EAaArVRs5qV39C9S3zO0z9ynVoWeZkuNfeMpsVDQnOk=".to_string()), }; assert!(uri.is_checksum_valid()); } @@ -333,11 +320,9 @@ mod tests { #[test] fn test_invalid_checksum() { let uri = super::LoginUriView { - uri: Some(SensitiveString::test("https://example.com")), + uri: Some("https://example.com".to_string()), r#match: Some(super::UriMatchType::Domain), - uri_checksum: Some(SensitiveString::test( - "UtSgIv8LYfEdOu7yqjF7qXWhmouYGYC8RSr7/ryZg5Q=", - )), + uri_checksum: Some("UtSgIv8LYfEdOu7yqjF7qXWhmouYGYC8RSr7/ryZg5Q=".to_string()), }; assert!(!uri.is_checksum_valid()); } @@ -345,7 +330,7 @@ mod tests { #[test] fn test_missing_checksum() { let uri = super::LoginUriView { - uri: Some(SensitiveString::test("https://example.com")), + uri: Some("https://example.com".to_string()), r#match: Some(super::UriMatchType::Domain), uri_checksum: None, }; @@ -355,7 +340,7 @@ mod tests { #[test] fn test_generate_checksum() { let mut uri = super::LoginUriView { - uri: Some(SensitiveString::test("https://test.com")), + uri: Some("https://test.com".to_string()), r#match: Some(super::UriMatchType::Domain), uri_checksum: None, }; @@ -363,7 +348,7 @@ mod tests { uri.generate_checksum(); assert_eq!( - uri.uri_checksum.unwrap().expose(), + uri.uri_checksum.unwrap().as_str(), "OWk2vQvwYD1nhLZdA+ltrpBWbDa2JmHyjUEWxRZSS8w=" ); } diff --git a/crates/bitwarden/src/vault/collection.rs b/crates/bitwarden/src/vault/collection.rs index eed60aa1c..ce881cb98 100644 --- a/crates/bitwarden/src/vault/collection.rs +++ b/crates/bitwarden/src/vault/collection.rs @@ -1,7 +1,6 @@ use bitwarden_api_api::models::CollectionDetailsResponseModel; use bitwarden_crypto::{ - CryptoError, DecryptedString, EncString, KeyContainer, KeyDecryptable, LocateKey, - SymmetricCryptoKey, + CryptoError, EncString, KeyContainer, KeyDecryptable, LocateKey, SymmetricCryptoKey, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -30,7 +29,7 @@ pub struct CollectionView { id: Option, organization_id: Uuid, - name: DecryptedString, + name: String, external_id: Option, hide_passwords: bool, diff --git a/crates/bitwarden/src/vault/folder.rs b/crates/bitwarden/src/vault/folder.rs index 315abeca3..65b18e54b 100644 --- a/crates/bitwarden/src/vault/folder.rs +++ b/crates/bitwarden/src/vault/folder.rs @@ -1,7 +1,6 @@ use bitwarden_api_api::models::FolderResponseModel; use bitwarden_crypto::{ - CryptoError, DecryptedString, EncString, KeyDecryptable, KeyEncryptable, LocateKey, - SymmetricCryptoKey, + CryptoError, EncString, KeyDecryptable, KeyEncryptable, LocateKey, SymmetricCryptoKey, }; use chrono::{DateTime, Utc}; use schemars::JsonSchema; @@ -24,7 +23,7 @@ pub struct Folder { #[cfg_attr(feature = "mobile", derive(uniffi::Record))] pub struct FolderView { pub id: Option, - pub name: DecryptedString, + pub name: String, pub revision_date: DateTime, } diff --git a/crates/bitwarden/src/vault/password_history.rs b/crates/bitwarden/src/vault/password_history.rs index f862bf2c5..396410636 100644 --- a/crates/bitwarden/src/vault/password_history.rs +++ b/crates/bitwarden/src/vault/password_history.rs @@ -1,7 +1,6 @@ use bitwarden_api_api::models::CipherPasswordHistoryModel; use bitwarden_crypto::{ - CryptoError, DecryptedString, EncString, KeyDecryptable, KeyEncryptable, LocateKey, - SymmetricCryptoKey, + CryptoError, EncString, KeyDecryptable, KeyEncryptable, LocateKey, SymmetricCryptoKey, }; use chrono::{DateTime, Utc}; use schemars::JsonSchema; @@ -21,7 +20,7 @@ pub struct PasswordHistory { #[serde(rename_all = "camelCase", deny_unknown_fields)] #[cfg_attr(feature = "mobile", derive(uniffi::Record))] pub struct PasswordHistoryView { - password: DecryptedString, + password: String, last_used_date: DateTime, } diff --git a/crates/bitwarden/src/vault/send.rs b/crates/bitwarden/src/vault/send.rs index 79fc16f85..e681e5468 100644 --- a/crates/bitwarden/src/vault/send.rs +++ b/crates/bitwarden/src/vault/send.rs @@ -4,9 +4,8 @@ use base64::{ }; use bitwarden_api_api::models::{SendFileModel, SendResponseModel, SendTextModel}; use bitwarden_crypto::{ - derive_shareable_key, generate_random_bytes, CryptoError, DecryptedString, DecryptedVec, - EncString, KeyDecryptable, KeyEncryptable, LocateKey, Sensitive, SensitiveVec, - SymmetricCryptoKey, + derive_shareable_key, generate_random_bytes, CryptoError, EncString, KeyDecryptable, + KeyEncryptable, LocateKey, Sensitive, SensitiveVec, SymmetricCryptoKey, }; use chrono::{DateTime, Utc}; use schemars::JsonSchema; @@ -34,7 +33,7 @@ pub struct SendFile { #[cfg_attr(feature = "mobile", derive(uniffi::Record))] pub struct SendFileView { pub id: Option, - pub file_name: DecryptedString, + pub file_name: String, pub size: Option, /// Readable size, ex: "4.2 KB" or "1.43 GB" pub size_name: Option, @@ -52,7 +51,7 @@ pub struct SendText { #[serde(rename_all = "camelCase", deny_unknown_fields)] #[cfg_attr(feature = "mobile", derive(uniffi::Record))] pub struct SendTextView { - pub text: Option, + pub text: Option, pub hidden: bool, } @@ -97,10 +96,10 @@ pub struct SendView { pub id: Option, pub access_id: Option, - pub name: DecryptedString, - pub notes: Option, + pub name: String, + pub notes: Option, /// Base64 encoded key - pub key: Option, + pub key: Option, /// Replace or add a password to an existing send. The SDK will always return None when /// decrypting a [Send] /// TODO: We should revisit this, one variant is to have `[Create, Update]SendView` DTOs. @@ -123,14 +122,14 @@ pub struct SendView { pub expiration_date: Option>, } -#[derive(Serialize, Deserialize, JsonSchema)] +#[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] #[cfg_attr(feature = "mobile", derive(uniffi::Record))] pub struct SendListView { pub id: Option, pub access_id: Option, - pub name: DecryptedString, + pub name: String, pub r#type: SendType, pub disabled: bool, @@ -145,12 +144,14 @@ impl Send { send_key: &EncString, enc_key: &SymmetricCryptoKey, ) -> Result { - let key: DecryptedVec = send_key.decrypt_with_key(enc_key)?; + let key: Vec = send_key.decrypt_with_key(enc_key)?; Self::derive_shareable_key(&key) } - fn derive_shareable_key(key: &SensitiveVec) -> Result { - let key = key.try_into()?; + fn derive_shareable_key(key: &[u8]) -> Result { + let key = Sensitive::new(Box::new( + key.try_into().map_err(|_| CryptoError::InvalidKeyLen)?, + )); Ok(derive_shareable_key(key, "send", Some("send"))) } } @@ -201,7 +202,7 @@ impl KeyDecryptable for Send { // For sends, we first decrypt the send key with the user key, and stretch it to it's full // size For the rest of the fields, we ignore the provided SymmetricCryptoKey and // the stretched key - let k: DecryptedVec = self.key.decrypt_with_key(key)?; + let k: Vec = self.key.decrypt_with_key(key)?; let key = Send::derive_shareable_key(&k)?; Ok(SendView { @@ -210,7 +211,7 @@ impl KeyDecryptable for Send { name: self.name.decrypt_with_key(&key).ok().unwrap_or_default(), notes: self.notes.decrypt_with_key(&key).ok().flatten(), - key: Some(k.encode_base64(URL_SAFE_NO_PAD)), + key: Some(URL_SAFE_NO_PAD.encode(k)), new_password: None, has_password: self.password.is_some(), @@ -261,13 +262,13 @@ impl KeyEncryptable for SendView { // the stretched key let k = match (self.key, self.id) { // Existing send, decrypt key - (Some(k), _) => k - .decode_base64(URL_SAFE_NO_PAD) + (Some(k), _) => URL_SAFE_NO_PAD + .decode(k) .map_err(|_| CryptoError::InvalidKey)?, // New send, generate random key (None, None) => { let key: Sensitive<[u8; 16]> = generate_random_bytes(); - key.into() + SensitiveVec::from(key).expose().to_owned() } // Existing send without key _ => return Err(CryptoError::InvalidKey), @@ -280,10 +281,9 @@ impl KeyEncryptable for SendView { name: self.name.encrypt_with_key(&send_key)?, notes: self.notes.encrypt_with_key(&send_key)?, - key: k.expose().encrypt_with_key(key)?, + key: k.encrypt_with_key(key)?, password: self.new_password.map(|password| { - let password = - bitwarden_crypto::pbkdf2(password.as_bytes(), k.expose(), SEND_ITERATIONS); + let password = bitwarden_crypto::pbkdf2(password.as_bytes(), &k, SEND_ITERATIONS); STANDARD.encode(password) }), @@ -363,9 +363,7 @@ impl TryFrom for SendText { #[cfg(test)] mod tests { - use bitwarden_crypto::{ - KeyDecryptable, KeyEncryptable, MasterKey, SensitiveString, SensitiveVec, - }; + use bitwarden_crypto::{KeyDecryptable, KeyEncryptable, MasterKey, SensitiveVec}; use super::{Send, SendText, SendTextView, SendType}; use crate::{ @@ -452,15 +450,15 @@ mod tests { let expected = SendView { id: "3d80dd72-2d14-4f26-812c-b0f0018aa144".parse().ok(), access_id: Some("ct2APRQtJk-BLLDwAYqhRA".to_owned()), - name: SensitiveString::test("Test"), + name: "Test".to_string(), notes: None, - key: Some(SensitiveString::test("Pgui0FK85cNhBGWHAlBHBw")), + key: Some("Pgui0FK85cNhBGWHAlBHBw".to_owned()), new_password: None, has_password: false, r#type: SendType::Text, file: None, text: Some(SendTextView { - text: Some(SensitiveString::test("This is a test")), + text: Some("This is a test".to_owned()), hidden: false, }), max_access_count: None, @@ -483,15 +481,15 @@ mod tests { let view = SendView { id: "3d80dd72-2d14-4f26-812c-b0f0018aa144".parse().ok(), access_id: Some("ct2APRQtJk-BLLDwAYqhRA".to_owned()), - name: SensitiveString::test("Test"), + name: "Test".to_string(), notes: None, - key: Some(SensitiveString::test("Pgui0FK85cNhBGWHAlBHBw")), + key: Some("Pgui0FK85cNhBGWHAlBHBw".to_owned()), new_password: None, has_password: false, r#type: SendType::Text, file: None, text: Some(SendTextView { - text: Some(SensitiveString::test("This is a test")), + text: Some("This is a test".to_owned()), hidden: false, }), max_access_count: None, @@ -521,7 +519,7 @@ mod tests { let view = SendView { id: None, access_id: Some("ct2APRQtJk-BLLDwAYqhRA".to_owned()), - name: SensitiveString::test("Test"), + name: "Test".to_string(), notes: None, key: None, new_password: None, @@ -529,7 +527,7 @@ mod tests { r#type: SendType::Text, file: None, text: Some(SendTextView { - text: Some(SensitiveString::test("This is a test")), + text: Some("This is a test".to_owned()), hidden: false, }), max_access_count: None, @@ -562,15 +560,15 @@ mod tests { let view = SendView { id: None, access_id: Some("ct2APRQtJk-BLLDwAYqhRA".to_owned()), - name: SensitiveString::test("Test"), + name: "Test".to_owned(), notes: None, - key: Some(SensitiveString::test("Pgui0FK85cNhBGWHAlBHBw")), + key: Some("Pgui0FK85cNhBGWHAlBHBw".to_owned()), new_password: Some("abc123".to_owned()), has_password: false, r#type: SendType::Text, file: None, text: Some(SendTextView { - text: Some(SensitiveString::test("This is a test")), + text: Some("This is a test".to_owned()), hidden: false, }), max_access_count: None,