feat: replace sodium secretbox cryptor with xchacha20poly1305
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
members = [
|
members = [
|
||||||
"crdt-enc",
|
"crdt-enc",
|
||||||
"crdt-enc-gpgme",
|
"crdt-enc-gpgme",
|
||||||
"crdt-enc-sodium",
|
"crdt-enc-xchacha20poly1305",
|
||||||
"crdt-enc-tokio",
|
"crdt-enc-tokio",
|
||||||
"examples/*",
|
"examples/*",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "crdt-enc-sodium"
|
name = "crdt-enc-xchacha20poly1305"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Thomas Heck <t@b128.net>"]
|
authors = ["Thomas Heck <t@b128.net>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crdts = "6.2"
|
crdts = "6.2"
|
||||||
sodiumoxide = "0.2"
|
rand = "0.8"
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
serde = "1"
|
serde = "1"
|
||||||
rmp-serde = "0.15"
|
rmp-serde = "0.15"
|
||||||
@@ -16,3 +16,7 @@ async-trait = "0.1"
|
|||||||
|
|
||||||
[dependencies.crdt-enc]
|
[dependencies.crdt-enc]
|
||||||
path = "../crdt-enc"
|
path = "../crdt-enc"
|
||||||
|
|
||||||
|
[dependencies.chacha20poly1305]
|
||||||
|
version = "0.7"
|
||||||
|
features = ["std"]
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
use ::anyhow::{Context, Error, Result};
|
use ::anyhow::{Context, Error, Result};
|
||||||
use ::async_trait::async_trait;
|
use ::async_trait::async_trait;
|
||||||
|
use ::chacha20poly1305::{
|
||||||
|
aead::{Aead, NewAead},
|
||||||
|
Key, XChaCha20Poly1305, XNonce,
|
||||||
|
};
|
||||||
use ::crdt_enc::utils::{VersionBytes, VersionBytesRef};
|
use ::crdt_enc::utils::{VersionBytes, VersionBytesRef};
|
||||||
|
use ::rand::{thread_rng, RngCore};
|
||||||
use ::serde::{Deserialize, Serialize};
|
use ::serde::{Deserialize, Serialize};
|
||||||
use ::sodiumoxide::crypto::secretbox;
|
|
||||||
use ::std::{borrow::Cow, fmt::Debug};
|
use ::std::{borrow::Cow, fmt::Debug};
|
||||||
use ::uuid::Uuid;
|
use ::uuid::Uuid;
|
||||||
|
|
||||||
@@ -10,9 +14,8 @@ const DATA_VERSION: Uuid = Uuid::from_u128(0xc7f269be_0ff5_4a77_99c3_7c23c96d5cb
|
|||||||
|
|
||||||
const KEY_VERSION: Uuid = Uuid::from_u128(0x5df28591_439a_4cef_8ca6_8433276cc9ed);
|
const KEY_VERSION: Uuid = Uuid::from_u128(0x5df28591_439a_4cef_8ca6_8433276cc9ed);
|
||||||
|
|
||||||
pub fn init() {
|
const KEY_LEN: usize = 32;
|
||||||
sodiumoxide::init().expect("sodium init failed");
|
const NONCE_LEN: usize = 24;
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EncHandler;
|
pub struct EncHandler;
|
||||||
@@ -26,20 +29,32 @@ 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 key = secretbox::gen_key();
|
let mut key = [0u8; KEY_LEN];
|
||||||
Ok(VersionBytes::new(KEY_VERSION, key.as_ref().into()))
|
thread_rng()
|
||||||
|
.try_fill_bytes(&mut key)
|
||||||
|
.context("Unable to get random data for secret key")?;
|
||||||
|
Ok(VersionBytes::new(KEY_VERSION, key.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn encrypt(&self, key: VersionBytesRef<'_>, clear_text: &[u8]) -> Result<Vec<u8>> {
|
async fn encrypt(&self, key: VersionBytesRef<'_>, clear_text: &[u8]) -> Result<Vec<u8>> {
|
||||||
key.ensure_version(KEY_VERSION)
|
key.ensure_version(KEY_VERSION)
|
||||||
.context("not matching key version")?;
|
.context("not matching key version")?;
|
||||||
let key = secretbox::Key::from_slice(key.as_ref()).context("invalid key length")?;
|
if key.as_ref().len() != KEY_LEN {
|
||||||
|
return Err(Error::msg("Invalid key length"));
|
||||||
let nonce = secretbox::gen_nonce();
|
}
|
||||||
let enc_data = secretbox::seal(clear_text, &nonce, &key);
|
let key = Key::from_slice(key.as_ref());
|
||||||
|
let aead = XChaCha20Poly1305::new(key);
|
||||||
|
let mut nonce = [0u8; NONCE_LEN];
|
||||||
|
thread_rng()
|
||||||
|
.try_fill_bytes(&mut nonce)
|
||||||
|
.context("Unable to get random data for nonce")?;
|
||||||
|
let xnonce = XNonce::from_slice(&nonce);
|
||||||
|
let enc_data = aead
|
||||||
|
.encrypt(xnonce, clear_text)
|
||||||
|
.context("Encryption failed")?;
|
||||||
let enc_box = EncBox {
|
let enc_box = EncBox {
|
||||||
nonce,
|
nonce: Cow::Borrowed(nonce.as_ref()),
|
||||||
enc_data: enc_data.into(),
|
enc_data: Cow::Owned(enc_data),
|
||||||
};
|
};
|
||||||
let enc_box_bytes =
|
let enc_box_bytes =
|
||||||
rmp_serde::to_vec_named(&enc_box).context("failed to encode encryption box")?;
|
rmp_serde::to_vec_named(&enc_box).context("failed to encode encryption box")?;
|
||||||
@@ -52,25 +67,34 @@ impl crdt_enc::cryptor::Cryptor for EncHandler {
|
|||||||
async fn decrypt(&self, key: VersionBytesRef<'_>, enc_data: &[u8]) -> Result<Vec<u8>> {
|
async fn decrypt(&self, key: VersionBytesRef<'_>, enc_data: &[u8]) -> Result<Vec<u8>> {
|
||||||
key.ensure_version(KEY_VERSION)
|
key.ensure_version(KEY_VERSION)
|
||||||
.context("not matching key version")?;
|
.context("not matching key version")?;
|
||||||
let key = secretbox::Key::from_slice(key.as_ref()).context("invalid key length")?;
|
if key.as_ref().len() != KEY_LEN {
|
||||||
|
return Err(Error::msg("Invalid key length"));
|
||||||
|
}
|
||||||
let version_box: VersionBytesRef =
|
let version_box: VersionBytesRef =
|
||||||
rmp_serde::from_read_ref(enc_data).context("failed to parse version box")?;
|
rmp_serde::from_read_ref(enc_data).context("failed to parse version box")?;
|
||||||
version_box
|
version_box
|
||||||
.ensure_version(DATA_VERSION)
|
.ensure_version(DATA_VERSION)
|
||||||
.context("not matching version of encryption box")?;
|
.context("not matching version of encryption box")?;
|
||||||
|
|
||||||
let enc_box: EncBox = rmp_serde::from_read_ref(version_box.as_ref())
|
let enc_box: EncBox = rmp_serde::from_read_ref(version_box.as_ref())
|
||||||
.context("failed to parse encryption box")?;
|
.context("failed to parse encryption box")?;
|
||||||
let clear_text = secretbox::open(&enc_box.enc_data, &enc_box.nonce, &key)
|
if enc_box.nonce.as_ref().len() != NONCE_LEN {
|
||||||
.map_err(|_| Error::msg("failed decrypting data"))?;
|
return Err(Error::msg("Invalid nonce length"));
|
||||||
|
}
|
||||||
|
let key = Key::from_slice(key.as_ref());
|
||||||
|
let aead = XChaCha20Poly1305::new(key);
|
||||||
|
let xnonce = XNonce::from_slice(&enc_box.nonce);
|
||||||
|
let clear_text = aead
|
||||||
|
.decrypt(&xnonce, enc_box.enc_data.as_ref())
|
||||||
|
.context("Decryption failed")?;
|
||||||
Ok(clear_text)
|
Ok(clear_text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
struct EncBox<'a> {
|
struct EncBox<'a> {
|
||||||
nonce: secretbox::Nonce,
|
#[serde(borrow)]
|
||||||
|
#[serde(with = "serde_bytes")]
|
||||||
|
nonce: Cow<'a, [u8]>,
|
||||||
|
|
||||||
#[serde(borrow)]
|
#[serde(borrow)]
|
||||||
#[serde(with = "serde_bytes")]
|
#[serde(with = "serde_bytes")]
|
||||||
@@ -7,7 +7,7 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
crdt-enc = {path="../../crdt-enc"}
|
crdt-enc = {path="../../crdt-enc"}
|
||||||
crdt-enc-tokio = {path="../../crdt-enc-tokio"}
|
crdt-enc-tokio = {path="../../crdt-enc-tokio"}
|
||||||
crdt-enc-sodium = {path="../../crdt-enc-sodium"}
|
crdt-enc-xchacha20poly1305 = {path="../../crdt-enc-xchacha20poly1305"}
|
||||||
crdt-enc-gpgme = {path="../../crdt-enc-gpgme"}
|
crdt-enc-gpgme = {path="../../crdt-enc-gpgme"}
|
||||||
uuid = {version = "0.8", features = ["serde", "v4"]}
|
uuid = {version = "0.8", features = ["serde", "v4"]}
|
||||||
crdts = "6.2"
|
crdts = "6.2"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use ::anyhow::Result;
|
use ::anyhow::Result;
|
||||||
use ::crdt_enc_gpgme::KeyHandler;
|
use ::crdt_enc_gpgme::KeyHandler;
|
||||||
use ::crdt_enc_sodium::EncHandler;
|
|
||||||
use ::crdt_enc_tokio::Storage;
|
use ::crdt_enc_tokio::Storage;
|
||||||
|
use ::crdt_enc_xchacha20poly1305::EncHandler;
|
||||||
use ::futures::task;
|
use ::futures::task;
|
||||||
use ::uuid::Uuid;
|
use ::uuid::Uuid;
|
||||||
|
|
||||||
@@ -23,8 +23,6 @@ impl task::Spawn for TokioSpawn {
|
|||||||
|
|
||||||
#[tokio::main(flavor = "current_thread")]
|
#[tokio::main(flavor = "current_thread")]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
crdt_enc_sodium::init();
|
|
||||||
|
|
||||||
let data_dir = std::fs::canonicalize("./").unwrap().join("data");
|
let data_dir = std::fs::canonicalize("./").unwrap().join("data");
|
||||||
|
|
||||||
let storage = Storage::new(data_dir.join("local"), data_dir.join("remote"))?;
|
let storage = Storage::new(data_dir.join("local"), data_dir.join("remote"))?;
|
||||||
|
|||||||
Reference in New Issue
Block a user