This commit is contained in:
2025-08-16 15:10:55 +02:00
parent 200d0c928d
commit 84611dd245
24 changed files with 550 additions and 416 deletions

View File

@@ -4,13 +4,7 @@ version = "0.1.0"
edition = "2021"
[dependencies]
chacha20poly1305 = "0.10"
chacha20poly1305 = { workspace = true }
rand = { workspace = true }
sha2 = { workspace = true }
thiserror = { workspace = true }
# Add this dependency for the From<CryptoError> for DBError
libdbstorage = { path = "../libdbstorage", optional = true }
[features]
storage_compat = ["dep:libdbstorage"]
thiserror = { workspace = true }

View File

@@ -1,14 +1,72 @@
pub fn add(left: u64, right: u64) -> u64 {
left + right
// In crates/libcrypto/src/lib.rs
use chacha20poly1305::{
aead::{Aead, KeyInit, OsRng},
XChaCha20Poly1305, XNonce,
};
use rand::RngCore;
use sha2::{Digest, Sha256};
use thiserror::Error;
const VERSION: u8 = 1;
const NONCE_LEN: usize = 24;
const TAG_LEN: usize = 16;
#[derive(Error, Debug)]
pub enum CryptoError {
#[error("invalid format: data too short")]
Format,
#[error("unknown version: {0}")]
Version(u8),
#[error("decryption failed: wrong key or corrupted data")]
Decrypt,
}
#[cfg(test)]
mod tests {
use super::*;
/// Super-simple factory: new(secret) + encrypt(bytes) + decrypt(bytes)
pub struct CryptoFactory {
key: chacha20poly1305::Key,
}
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
impl CryptoFactory {
/// Accepts any secret bytes; turns them into a 32-byte key (SHA-256).
pub fn new<S: AsRef<[u8]>>(secret: S) -> Self {
let mut h = Sha256::new();
h.update(b"xchacha20poly1305-factory:v1"); // domain separation
h.update(secret.as_ref());
let digest = h.finalize(); // 32 bytes
let key = chacha20poly1305::Key::from_slice(&digest).to_owned();
Self { key }
}
}
/// Output layout: [version:1][nonce:24][ciphertext||tag]
pub fn encrypt(&self, plaintext: &[u8]) -> Vec<u8> {
let cipher = XChaCha20Poly1305::new(&self.key);
let mut nonce_bytes = [0u8; NONCE_LEN];
OsRng.fill_bytes(&mut nonce_bytes);
let nonce = XNonce::from_slice(&nonce_bytes);
let mut out = Vec::with_capacity(1 + NONCE_LEN + plaintext.len() + TAG_LEN);
out.push(VERSION);
out.extend_from_slice(&nonce_bytes);
let ct = cipher.encrypt(nonce, plaintext).expect("encrypt");
out.extend_from_slice(&ct);
out
}
pub fn decrypt(&self, blob: &[u8]) -> Result<Vec<u8>, CryptoError> {
if blob.len() < 1 + NONCE_LEN + TAG_LEN {
return Err(CryptoError::Format);
}
let ver = blob[0];
if ver != VERSION {
return Err(CryptoError::Version(ver));
}
let nonce = XNonce::from_slice(&blob[1..1 + NONCE_LEN]);
let ct = &blob[1 + NONCE_LEN..];
let cipher = XChaCha20Poly1305::new(&self.key);
cipher.decrypt(nonce, ct).map_err(|_| CryptoError::Decrypt)
}
}