1use bitwarden_encoding::B64;
2use rsa::{
3 Oaep,
4 pkcs8::{EncodePrivateKey, EncodePublicKey},
5};
6use sha1::Sha1;
7
8use crate::{
9 CryptoError, EncString, SymmetricCryptoKey,
10 error::{Result, RsaError, UnsupportedOperationError},
11 slow_crypto_span::{SlowCryptoOp, SlowCryptoSpan, measure},
12};
13
14#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
18pub struct RsaKeyPair {
19 pub public: B64,
21 pub private: EncString,
23}
24
25pub(crate) fn make_key_pair(key: &SymmetricCryptoKey) -> Result<RsaKeyPair> {
27 let mut rng = bitwarden_random::rng();
28 let bits = 2048;
29 let priv_key = measure(SlowCryptoOp::RsaKeyGeneration, || {
30 rsa::PrivateKey::new(&mut rng, bits).expect("failed to generate a key")
31 });
32 let pub_key = rsa::PublicKey::from(&priv_key);
33
34 let spki = pub_key
35 .to_public_key_der()
36 .map_err(|_| RsaError::CreatePublicKey)?;
37
38 let pkcs = priv_key
39 .to_pkcs8_der()
40 .map_err(|_| RsaError::CreatePrivateKey)?;
41
42 let protected = match key {
43 SymmetricCryptoKey::Aes256CbcHmacKey(key) => {
44 EncString::encrypt_aes256_hmac(pkcs.as_bytes(), key)
45 }
46 SymmetricCryptoKey::XChaCha20Poly1305Key(_) => Err(CryptoError::OperationNotSupported(
47 UnsupportedOperationError::EncryptionNotImplementedForKey,
48 )),
49 SymmetricCryptoKey::Aes256CbcKey(_) => Err(CryptoError::OperationNotSupported(
50 UnsupportedOperationError::EncryptionNotImplementedForKey,
51 )),
52 SymmetricCryptoKey::Aes256GcmKey(_) => Err(CryptoError::OperationNotSupported(
53 UnsupportedOperationError::EncryptionNotImplementedForKey,
54 )),
55 SymmetricCryptoKey::XAes256GcmKey(_) => Err(CryptoError::OperationNotSupported(
56 UnsupportedOperationError::EncryptionNotImplementedForKey,
57 )),
58 }?;
59
60 Ok(RsaKeyPair {
61 public: spki.as_ref().into(),
62 private: protected,
63 })
64}
65
66pub(super) fn encrypt_rsa2048_oaep_sha1(
68 public_key: &rsa::PublicKey,
69 data: &[u8],
70) -> Result<Vec<u8>> {
71 let _span = SlowCryptoSpan::start(SlowCryptoOp::RsaEncrypt);
72 let mut rng = bitwarden_random::rng();
73
74 let padding = Oaep::<Sha1>::new();
75 public_key
76 .encrypt(&mut rng, padding, data)
77 .map_err(|e| CryptoError::Rsa(e.into()))
78}