feat(xchacha): spawn gen_key, encrypt & decrypt blocking

This commit is contained in:
2021-03-09 21:09:14 +01:00
parent e3f8f4b732
commit 01e30713ad
4 changed files with 65 additions and 50 deletions

View File

@@ -13,6 +13,7 @@ rmp-serde = "0.15"
serde_bytes = "0.11" serde_bytes = "0.11"
uuid = "0.8" uuid = "0.8"
async-trait = "0.1" async-trait = "0.1"
agnostik = {git = "https://github.com/chpio/agnostik.git", branch = "tokio1"}
[dependencies.crdt-enc] [dependencies.crdt-enc]
path = "../crdt-enc" path = "../crdt-enc"

View File

@@ -1,3 +1,4 @@
use ::agnostik::spawn_blocking;
use ::anyhow::{Context, Error, Result}; use ::anyhow::{Context, Error, Result};
use ::async_trait::async_trait; use ::async_trait::async_trait;
use ::chacha20poly1305::{ use ::chacha20poly1305::{
@@ -29,64 +30,77 @@ impl EncHandler {
#[async_trait] #[async_trait]
impl crdt_enc::cryptor::Cryptor for EncHandler { impl crdt_enc::cryptor::Cryptor for EncHandler {
async fn gen_key(&self) -> Result<VersionBytes> { async fn gen_key(&self) -> Result<VersionBytes> {
let mut key = [0u8; KEY_LEN]; spawn_blocking(|| {
thread_rng() let mut key = [0u8; KEY_LEN];
.try_fill_bytes(&mut key) thread_rng()
.context("Unable to get random data for secret key")?; .try_fill_bytes(&mut key)
Ok(VersionBytes::new(KEY_VERSION, key.into())) .context("Unable to get random data for secret key")?;
Ok(VersionBytes::new(KEY_VERSION, key.into()))
})
.await
} }
async fn encrypt(&self, key: VersionBytesRef<'_>, clear_text: &[u8]) -> Result<Vec<u8>> { async fn encrypt(&self, key: VersionBytesRef<'_>, clear_text: Vec<u8>) -> Result<Vec<u8>> {
key.ensure_version(KEY_VERSION) key.ensure_version(KEY_VERSION)
.context("not matching key version")?; .context("not matching key version")?;
if key.as_ref().len() != KEY_LEN { if key.as_ref().len() != KEY_LEN {
return Err(Error::msg("Invalid key length")); return Err(Error::msg("Invalid key length"));
} }
let key = Key::from_slice(key.as_ref()); let key = key.as_ref().to_vec();
let aead = XChaCha20Poly1305::new(key);
let mut nonce = [0u8; NONCE_LEN]; spawn_blocking(move || {
thread_rng() let key = Key::from_slice(&key);
.try_fill_bytes(&mut nonce) let aead = XChaCha20Poly1305::new(key);
.context("Unable to get random data for nonce")?; let mut nonce = [0u8; NONCE_LEN];
let xnonce = XNonce::from_slice(&nonce); thread_rng()
let enc_data = aead .try_fill_bytes(&mut nonce)
.encrypt(xnonce, clear_text) .context("Unable to get random data for nonce")?;
.context("Encryption failed")?; let xnonce = XNonce::from_slice(&nonce);
let enc_box = EncBox { let enc_data = aead
nonce: Cow::Borrowed(nonce.as_ref()), .encrypt(xnonce, clear_text.as_ref())
enc_data: Cow::Owned(enc_data), .context("Encryption failed")?;
}; let enc_box = EncBox {
let enc_box_bytes = nonce: Cow::Borrowed(nonce.as_ref()),
rmp_serde::to_vec_named(&enc_box).context("failed to encode encryption box")?; enc_data: Cow::Owned(enc_data),
let version_box = VersionBytesRef::new(DATA_VERSION, enc_box_bytes.as_ref()); };
let version_box_bytes = let enc_box_bytes =
rmp_serde::to_vec_named(&version_box).context("failed to encode version box")?; rmp_serde::to_vec_named(&enc_box).context("failed to encode encryption box")?;
Ok(version_box_bytes) let version_box = VersionBytesRef::new(DATA_VERSION, enc_box_bytes.as_ref());
let version_box_bytes =
rmp_serde::to_vec_named(&version_box).context("failed to encode version box")?;
Ok(version_box_bytes)
})
.await
} }
async fn decrypt(&self, key: VersionBytesRef<'_>, enc_data: &[u8]) -> Result<Vec<u8>> { async fn decrypt(&self, key: VersionBytesRef<'_>, enc_data: Vec<u8>) -> Result<Vec<u8>> {
key.ensure_version(KEY_VERSION) key.ensure_version(KEY_VERSION)
.context("not matching key version")?; .context("not matching key version")?;
if key.as_ref().len() != KEY_LEN { if key.as_ref().len() != KEY_LEN {
return Err(Error::msg("Invalid key length")); return Err(Error::msg("Invalid key length"));
} }
let version_box: VersionBytesRef = let key = key.as_ref().to_vec();
rmp_serde::from_read_ref(enc_data).context("failed to parse version box")?;
version_box spawn_blocking(move || {
.ensure_version(DATA_VERSION) let version_box: VersionBytesRef =
.context("not matching version of encryption box")?; rmp_serde::from_read_ref(&enc_data).context("failed to parse version box")?;
let enc_box: EncBox = rmp_serde::from_read_ref(version_box.as_ref()) version_box
.context("failed to parse encryption box")?; .ensure_version(DATA_VERSION)
if enc_box.nonce.as_ref().len() != NONCE_LEN { .context("not matching version of encryption box")?;
return Err(Error::msg("Invalid nonce length")); let enc_box: EncBox = rmp_serde::from_read_ref(version_box.as_ref())
} .context("failed to parse encryption box")?;
let key = Key::from_slice(key.as_ref()); if enc_box.nonce.as_ref().len() != NONCE_LEN {
let aead = XChaCha20Poly1305::new(key); return Err(Error::msg("Invalid nonce length"));
let xnonce = XNonce::from_slice(&enc_box.nonce); }
let clear_text = aead let key = Key::from_slice(key.as_ref());
.decrypt(&xnonce, enc_box.enc_data.as_ref()) let aead = XChaCha20Poly1305::new(key);
.context("Decryption failed")?; let xnonce = XNonce::from_slice(&enc_box.nonce);
Ok(clear_text) let clear_text = aead
.decrypt(&xnonce, enc_box.enc_data.as_ref())
.context("Decryption failed")?;
Ok(clear_text)
})
.await
} }
} }

View File

@@ -22,6 +22,6 @@ where
} }
async fn gen_key(&self) -> Result<VersionBytes>; async fn gen_key(&self) -> Result<VersionBytes>;
async fn encrypt(&self, key: VersionBytesRef<'_>, clear_text: &[u8]) -> Result<Vec<u8>>; async fn encrypt(&self, key: VersionBytesRef<'_>, clear_text: Vec<u8>) -> Result<Vec<u8>>;
async fn decrypt(&self, key: VersionBytesRef<'_>, enc_data: &[u8]) -> Result<Vec<u8>>; async fn decrypt(&self, key: VersionBytesRef<'_>, enc_data: Vec<u8>) -> Result<Vec<u8>>;
} }

View File

@@ -355,7 +355,7 @@ where
Ok((clear_text, states_to_remove, ops_to_remove, key)) Ok((clear_text, states_to_remove, ops_to_remove, key))
})?; })?;
let data_enc = self.cryptor.encrypt(key.key(), &clear_text).await.unwrap(); let data_enc = self.cryptor.encrypt(key.key(), clear_text).await.unwrap();
let enc_data = VersionBytes::new(self.current_data_version, data_enc); let enc_data = VersionBytes::new(self.current_data_version, data_enc);
@@ -436,7 +436,7 @@ where
let clear_text = self let clear_text = self
.cryptor .cryptor
.decrypt(key.key(), state.as_ref()) .decrypt(key.key(), state.into_inner())
.await .await
.with_context(|| format!("failed decrypting remote state {}", name))?; .with_context(|| format!("failed decrypting remote state {}", name))?;
@@ -500,7 +500,7 @@ where
data.ensure_versions(SUPPORTED_VERSIONS)?; data.ensure_versions(SUPPORTED_VERSIONS)?;
let clear_text = self let clear_text = self
.cryptor .cryptor
.decrypt(key.key(), data.as_ref()) .decrypt(key.key(), data.into_inner())
.await .await
.unwrap(); .unwrap();
@@ -684,7 +684,7 @@ where
let data_enc = self let data_enc = self
.cryptor .cryptor
.encrypt(key.key(), &clear_text.serialize()) .encrypt(key.key(), clear_text.serialize())
.await .await
.unwrap(); .unwrap();