Skip to content

Commit

Permalink
Add some missing implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
dani-garcia committed Oct 3, 2024
1 parent eb81684 commit d279626
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 3 deletions.
16 changes: 16 additions & 0 deletions crates/bitwarden-crypto/src/service/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,22 @@ impl<'a, SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKeyRef>
)
}

#[deprecated(note = "This function should never be used outside this crate")]
pub fn dangerous_get_symmetric_key(
&self,
key_ref: SymmKeyRef,
) -> Result<&SymmetricCryptoKey, crate::CryptoError> {
self.get_symmetric_key(key_ref)
}

#[deprecated(note = "This function should never be used outside this crate")]
pub fn dangerous_get_asymmetric_key(
&self,
key_ref: AsymmKeyRef,
) -> Result<&AsymmetricCryptoKey, crate::CryptoError> {
self.get_asymmetric_key(key_ref)
}

fn get_symmetric_key(
&self,
key_ref: SymmKeyRef,
Expand Down
68 changes: 65 additions & 3 deletions crates/bitwarden-crypto/src/service/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub mod key_ref;
mod key_store;

pub use context::CryptoServiceContext;
pub use encryptable::{Decryptable, Encryptable, UsingKey, UsingKeyExt, UsesKey};
pub use encryptable::{Decryptable, Encryptable, UsesKey, UsingKey, UsingKeyExt};
use key_ref::{AsymmetricKeyRef, KeyRef, SymmetricKeyRef};
pub use key_store::create_key_store;
use key_store::KeyStore;
Expand All @@ -20,6 +20,14 @@ pub struct CryptoService<SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKey
key_stores: Arc<RwLock<RustCryptoServiceKeys<SymmKeyRef, AsymmKeyRef>>>,
}

impl<SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKeyRef> std::fmt::Debug
for CryptoService<SymmKeyRef, AsymmKeyRef>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CryptoService").finish()
}
}

// This is just a wrapper around the keys so we only deal with one RwLock
pub(crate) struct RustCryptoServiceKeys<SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKeyRef>
{
Expand All @@ -46,6 +54,22 @@ impl<SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKeyRef>
keys.asymmetric_keys.clear();
}

pub fn retain_symmetric_keys(&self, f: fn(SymmKeyRef) -> bool) {
self.key_stores
.write()
.expect("RwLock is poisoned")
.symmetric_keys
.retain(f);
}

pub fn retain_asymmetric_keys(&self, f: fn(AsymmKeyRef) -> bool) {
self.key_stores
.write()
.expect("RwLock is poisoned")
.asymmetric_keys
.retain(f);
}

#[deprecated(note = "We should be generating/decrypting the keys into the service directly")]
pub fn insert_symmetric_key(&self, key_ref: SymmKeyRef, key: SymmetricCryptoKey) {
self.key_stores
Expand All @@ -64,8 +88,9 @@ impl<SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKeyRef>
.insert(key_ref, key);
}

// TODO: Do we want this to be public?
pub(crate) fn context(&'_ self) -> CryptoServiceContext<'_, SymmKeyRef, AsymmKeyRef> {
/// Initiate an encryption/decryption context. This is an advanced API, use with care.
/// Prefer to instead use `encrypt`/`decrypt`/`encrypt_list`/`decrypt_list` methods.
pub fn context(&'_ self) -> CryptoServiceContext<'_, SymmKeyRef, AsymmKeyRef> {
CryptoServiceContext {
global_keys: self.key_stores.read().expect("RwLock is poisoned"),
local_symmetric_keys: create_key_store(),
Expand Down Expand Up @@ -98,6 +123,43 @@ impl<SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKeyRef>
data.encrypt(&mut self.context(), key)
}

pub fn decrypt_list<
Key: KeyRef,
Data: Decryptable<SymmKeyRef, AsymmKeyRef, Key, Output> + UsesKey<Key> + Send + Sync,
Output: Send + Sync,
>(
&self,
data: &[Data],
) -> Result<Vec<Output>, crate::CryptoError> {
use rayon::prelude::*;

// We want to split all the data between available threads, but at the
// same time we don't want to split it too much if the amount of data is small.

// In this case, the minimum chunk size is 50.
let chunk_size = usize::max(1 + data.len() / rayon::current_num_threads(), 50);

let res: Result<Vec<_>, _> = data
.par_chunks(chunk_size)
.map(|chunk| {
let mut context = self.context();

let mut result = Vec::with_capacity(chunk.len());

for item in chunk {
let key = item.uses_key();
result.push(item.decrypt(&mut context, key));
context.clear();
}

result
})
.flatten()
.collect();

res
}

pub fn encrypt_list<
Key: KeyRef,
Data: Encryptable<SymmKeyRef, AsymmKeyRef, Key, Output> + UsesKey<Key> + Send + Sync,
Expand Down

0 comments on commit d279626

Please sign in to comment.