From 5ee464a5b4ef12aa24ed6dfa1dccb01b999c848c Mon Sep 17 00:00:00 2001 From: nazeh Date: Sat, 3 Aug 2024 15:46:20 +0300 Subject: [PATCH] feat(pubky-common): add encrypt/decrypt with secret_box --- Cargo.lock | 118 +++++++++++++++++++++++++++++++++++++ pubky-common/Cargo.toml | 1 + pubky-common/src/crypto.rs | 43 ++++++++++++++ 3 files changed, 162 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 85d39a1..040fe82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,16 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -81,6 +91,18 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + [[package]] name = "arrayref" version = "0.3.7" @@ -269,6 +291,15 @@ dependencies = [ "serde", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "blake3" version = "1.5.2" @@ -321,6 +352,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + [[package]] name = "clap" version = "4.5.11" @@ -465,9 +507,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core", "typenum", ] +[[package]] +name = "crypto_secretbox" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d6cf87adf719ddf43a805e92c6870a531aedda35ff640442cbaf8674e141e1" +dependencies = [ + "aead", + "cipher", + "generic-array", + "poly1305", + "salsa20", + "subtle", + "zeroize", +] + [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -522,6 +580,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -730,6 +789,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -960,6 +1020,15 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "ipnet" version = "2.9.0" @@ -1165,6 +1234,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "overload" version = "0.1.1" @@ -1204,6 +1279,17 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1320,6 +1406,17 @@ dependencies = [ "spki", ] +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "postcard" version = "1.0.8" @@ -1363,6 +1460,7 @@ checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" name = "pubky" version = "0.1.0" dependencies = [ + "argon2", "bytes", "js-sys", "pkarr", @@ -1382,6 +1480,7 @@ version = "0.1.0" dependencies = [ "base32", "blake3", + "crypto_secretbox", "ed25519-dalek", "js-sys", "once_cell", @@ -1594,6 +1693,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -2124,6 +2232,16 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "url" version = "2.5.2" diff --git a/pubky-common/Cargo.toml b/pubky-common/Cargo.toml index 6855f97..042474c 100644 --- a/pubky-common/Cargo.toml +++ b/pubky-common/Cargo.toml @@ -15,6 +15,7 @@ rand = "0.8.5" thiserror = "1.0.60" postcard = { version = "1.0.8", features = ["alloc"] } serde = { version = "1.0.204", features = ["derive"] } +crypto_secretbox = "0.1.1" [target.'cfg(target_arch = "wasm32")'.dependencies] js-sys = "0.3.69" diff --git a/pubky-common/src/crypto.rs b/pubky-common/src/crypto.rs index ec8f58a..5e57f51 100644 --- a/pubky-common/src/crypto.rs +++ b/pubky-common/src/crypto.rs @@ -1,3 +1,7 @@ +use crypto_secretbox::{ + aead::{Aead, AeadCore, KeyInit, OsRng}, + XSalsa20Poly1305, +}; use rand::prelude::Rng; pub use pkarr::{Keypair, PublicKey}; @@ -25,3 +29,42 @@ pub fn random_bytes() -> [u8; N] { } arr } + +pub fn encrypt( + plain_text: &[u8], + encryption_key: &[u8; 32], +) -> Result, crypto_secretbox::Error> { + let cipher = XSalsa20Poly1305::new(encryption_key.into()); + let nonce = XSalsa20Poly1305::generate_nonce(&mut OsRng); // unique per message + let ciphertext = cipher.encrypt(&nonce, plain_text)?; + + let mut out: Vec = Vec::with_capacity(nonce.len() + ciphertext.len()); + out.extend_from_slice(nonce.as_slice()); + out.extend_from_slice(&ciphertext); + + Ok(out) +} + +pub fn decrypt( + bytes: &[u8], + encryption_key: &[u8; 32], +) -> Result, crypto_secretbox::Error> { + let cipher = XSalsa20Poly1305::new(encryption_key.into()); + cipher.decrypt(bytes[..24].into(), &bytes[24..]) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn encrypt_decrypt() { + let plain_text = "Plain text!"; + let encryption_key = [0; 32]; + + let encrypted = encrypt(plain_text.as_bytes(), &encryption_key).unwrap(); + let decrypted = decrypt(&encrypted, &encryption_key).unwrap(); + + assert_eq!(decrypted, plain_text.as_bytes()) + } +}