Skip to content

Commit

Permalink
[PM-6107] Use rayon to multithread encryption/decryption (#215)
Browse files Browse the repository at this point in the history
## Type of change
```
- [ ] Bug fix
- [x] New feature development
- [ ] Tech debt (refactoring, code cleanup, dependency upgrades, etc)
- [ ] Build/deploy pipeline (DevOps)
- [ ] Other
```

## Objective
Use rayon to multithread the encryption and decryption of ciphers. Note
that this will have no benefit for WASM, as in that case it falls back
to a single thread model.

In my Mac I get 8-9x speedups when decrypting a big number of
EncStrings.
  • Loading branch information
dani-garcia authored Feb 8, 2024
1 parent f57262c commit 9399346
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 23 deletions.
40 changes: 40 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/bitwarden-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ num-bigint = ">=0.4, <0.5"
num-traits = ">=0.2.15, <0.3"
pbkdf2 = { version = ">=0.12.1, <0.13", default-features = false }
rand = ">=0.8.5, <0.9"
rayon = ">=1.8.1, <2.0"
rsa = ">=0.9.2, <0.10"
schemars = { version = ">=0.8, <0.9", features = ["uuid1"] }
serde = { version = ">=1.0, <2.0", features = ["derive"] }
Expand Down
34 changes: 23 additions & 11 deletions crates/bitwarden-crypto/src/encryptable.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use std::{collections::HashMap, hash::Hash};

use rayon::prelude::*;
use uuid::Uuid;

use crate::{CryptoError, KeyDecryptable, KeyEncryptable, Result, SymmetricCryptoKey};

pub trait KeyContainer {
pub trait KeyContainer: Send + Sync {
fn get_key(&self, org_id: &Option<Uuid>) -> Option<&SymmetricCryptoKey>;
}

Expand Down Expand Up @@ -46,37 +47,48 @@ impl<T: KeyDecryptable<SymmetricCryptoKey, Output> + LocateKey, Output> Decrypta
}
}

impl<T: Encryptable<Output>, Output> Encryptable<Vec<Output>> for Vec<T> {
impl<T: Encryptable<Output> + Send + Sync, Output: Send + Sync> Encryptable<Vec<Output>>
for Vec<T>
{
fn encrypt(self, enc: &dyn KeyContainer, org_id: &Option<Uuid>) -> Result<Vec<Output>> {
self.into_iter().map(|e| e.encrypt(enc, org_id)).collect()
self.into_par_iter()
.map(|e| e.encrypt(enc, org_id))
.collect()
}
}

impl<T: Decryptable<Output>, Output> Decryptable<Vec<Output>> for Vec<T> {
impl<T: Decryptable<Output> + Send + Sync, Output: Send + Sync> Decryptable<Vec<Output>>
for Vec<T>
{
fn decrypt(&self, enc: &dyn KeyContainer, org_id: &Option<Uuid>) -> Result<Vec<Output>> {
self.iter().map(|e| e.decrypt(enc, org_id)).collect()
self.into_par_iter()
.map(|e| e.decrypt(enc, org_id))
.collect()
}
}

impl<T: Encryptable<Output>, Output, Id: Hash + Eq> Encryptable<HashMap<Id, Output>>
for HashMap<Id, T>
impl<T: Encryptable<Output> + Send + Sync, Output: Send + Sync, Id: Hash + Eq + Send + Sync>
Encryptable<HashMap<Id, Output>> for HashMap<Id, T>
{
fn encrypt(self, enc: &dyn KeyContainer, org_id: &Option<Uuid>) -> Result<HashMap<Id, Output>> {
self.into_iter()
self.into_par_iter()
.map(|(id, e)| Ok((id, e.encrypt(enc, org_id)?)))
.collect()
}
}

impl<T: Decryptable<Output>, Output, Id: Hash + Eq + Copy> Decryptable<HashMap<Id, Output>>
for HashMap<Id, T>
impl<
T: Decryptable<Output> + Send + Sync,
Output: Send + Sync,
Id: Hash + Eq + Copy + Send + Sync,
> Decryptable<HashMap<Id, Output>> for HashMap<Id, T>
{
fn decrypt(
&self,
enc: &dyn KeyContainer,
org_id: &Option<Uuid>,
) -> Result<HashMap<Id, Output>> {
self.iter()
self.into_par_iter()
.map(|(id, e)| Ok((*id, e.decrypt(enc, org_id)?)))
.collect()
}
Expand Down
44 changes: 32 additions & 12 deletions crates/bitwarden-crypto/src/keys/key_encryptable.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::{collections::HashMap, hash::Hash};

use rayon::prelude::*;

use crate::error::Result;

pub trait CryptoKey {}
Expand Down Expand Up @@ -44,37 +46,55 @@ impl<T: KeyDecryptable<Key, Output>, Key: CryptoKey, Output> KeyDecryptable<Key,
}
}

impl<T: KeyEncryptable<Key, Output>, Key: CryptoKey, Output> KeyEncryptable<Key, Vec<Output>>
for Vec<T>
impl<
T: KeyEncryptable<Key, Output> + Send + Sync,
Key: CryptoKey + Send + Sync,
Output: Send + Sync,
> KeyEncryptable<Key, Vec<Output>> for Vec<T>
{
fn encrypt_with_key(self, key: &Key) -> Result<Vec<Output>> {
self.into_iter().map(|e| e.encrypt_with_key(key)).collect()
self.into_par_iter()
.map(|e| e.encrypt_with_key(key))
.collect()
}
}

impl<T: KeyDecryptable<Key, Output>, Key: CryptoKey, Output> KeyDecryptable<Key, Vec<Output>>
for Vec<T>
impl<
T: KeyDecryptable<Key, Output> + Send + Sync,
Key: CryptoKey + Send + Sync,
Output: Send + Sync,
> KeyDecryptable<Key, Vec<Output>> for Vec<T>
{
fn decrypt_with_key(&self, key: &Key) -> Result<Vec<Output>> {
self.iter().map(|e| e.decrypt_with_key(key)).collect()
self.into_par_iter()
.map(|e| e.decrypt_with_key(key))
.collect()
}
}

impl<T: KeyEncryptable<Key, Output>, Key: CryptoKey, Output, Id: Hash + Eq>
KeyEncryptable<Key, HashMap<Id, Output>> for HashMap<Id, T>
impl<
T: KeyEncryptable<Key, Output> + Send + Sync,
Key: CryptoKey + Send + Sync,
Output: Send + Sync,
Id: Hash + Eq + Send + Sync,
> KeyEncryptable<Key, HashMap<Id, Output>> for HashMap<Id, T>
{
fn encrypt_with_key(self, key: &Key) -> Result<HashMap<Id, Output>> {
self.into_iter()
self.into_par_iter()
.map(|(id, e)| Ok((id, e.encrypt_with_key(key)?)))
.collect()
}
}

impl<T: KeyDecryptable<Key, Output>, Key: CryptoKey, Output, Id: Hash + Eq + Copy>
KeyDecryptable<Key, HashMap<Id, Output>> for HashMap<Id, T>
impl<
T: KeyDecryptable<Key, Output> + Send + Sync,
Key: CryptoKey + Send + Sync,
Output: Send + Sync,
Id: Hash + Eq + Copy + Send + Sync,
> KeyDecryptable<Key, HashMap<Id, Output>> for HashMap<Id, T>
{
fn decrypt_with_key(&self, key: &Key) -> Result<HashMap<Id, Output>> {
self.iter()
self.into_par_iter()
.map(|(id, e)| Ok((*id, e.decrypt_with_key(key)?)))
.collect()
}
Expand Down

0 comments on commit 9399346

Please sign in to comment.