From 99ac3c0902485a6879b6aa0e5f13712819f6ef5b Mon Sep 17 00:00:00 2001 From: Karolin Varner Date: Wed, 3 Jul 2024 20:51:16 +0200 Subject: [PATCH] feat: Experimental support for encryption using libcrux Libcrux is a library for formally verified implementations of cryptographic primitives. It uses multiple back ends; one of which is libjade. A cryptographic library written in the jasmin assembly language for high assurance cryptographic implementations. To use compile with the experiment_libcrux feature enabled: cargo build --features experiment_libcrux --- Cargo.lock | 45 ++++++++++++++ Cargo.toml | 1 + ciphers/Cargo.toml | 4 ++ ciphers/src/lib.rs | 3 + .../subtle/chacha20poly1305_ietf_libcrux.rs | 60 +++++++++++++++++++ ciphers/src/subtle/mod.rs | 3 + fuzz/Cargo.toml | 5 +- rosenpass/Cargo.toml | 3 +- rp/Cargo.toml | 1 + 9 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 ciphers/src/subtle/chacha20poly1305_ietf_libcrux.rs diff --git a/Cargo.lock b/Cargo.lock index fc62813..4133bb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -984,8 +984,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if 1.0.0", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1228,6 +1230,38 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "libcrux" +version = "0.0.2-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31d9dcd435758db03438089760c55a45e6bcab7e4e299ee261f75225ab29d482" +dependencies = [ + "getrandom 0.2.15", + "libcrux-hacl", + "libcrux-platform", + "libjade-sys", + "rand 0.8.5", +] + +[[package]] +name = "libcrux-hacl" +version = "0.0.2-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52b2581ce493c5c22700077b5552b47be69b67b8176716572b02856218db0b68" +dependencies = [ + "cc", + "libcrux-platform", +] + +[[package]] +name = "libcrux-platform" +version = "0.0.2-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "647e39666194b11df17c19451d1154b9be79df98b9821532560c2ecad0cf3410" +dependencies = [ + "libc", +] + [[package]] name = "libfuzzer-sys" version = "0.4.7" @@ -1239,6 +1273,16 @@ dependencies = [ "once_cell", ] +[[package]] +name = "libjade-sys" +version = "0.0.2-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec4d22bba476bf8f5aebe36ccfd0e56dba8707e0c3b5c76996576028f48ffb8e" +dependencies = [ + "cc", + "libcrux-platform", +] + [[package]] name = "libloading" version = "0.8.3" @@ -1930,6 +1974,7 @@ dependencies = [ "anyhow", "blake2", "chacha20poly1305", + "libcrux", "rosenpass-constant-time", "rosenpass-oqs", "rosenpass-secret-memory", diff --git a/Cargo.toml b/Cargo.toml index ee6afd3..018532f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,6 +64,7 @@ home = "0.5.9" derive_builder = "0.20.0" tokio = { version = "1.38", features = ["macros", "rt-multi-thread"] } postcard= {version = "1.0.8", features = ["alloc"]} +libcrux = { version = "0.0.2-pre.2" } #Dev dependencies serial_test = "3.1.1" diff --git a/ciphers/Cargo.toml b/ciphers/Cargo.toml index 5475042..7249ca7 100644 --- a/ciphers/Cargo.toml +++ b/ciphers/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://rosenpass.eu/" repository = "https://github.com/rosenpass/rosenpass" readme = "readme.md" +[features] +experiment_libcrux = ["dep:libcrux"] + [dependencies] anyhow = { workspace = true } rosenpass-to = { workspace = true } @@ -20,3 +23,4 @@ static_assertions = { workspace = true } zeroize = { workspace = true } chacha20poly1305 = { workspace = true } blake2 = { workspace = true } +libcrux = { workspace = true, optional = true } diff --git a/ciphers/src/lib.rs b/ciphers/src/lib.rs index d57bd00..25c9cb2 100644 --- a/ciphers/src/lib.rs +++ b/ciphers/src/lib.rs @@ -9,6 +9,9 @@ const_assert!(KEY_LEN == hash_domain::KEY_LEN); /// Authenticated encryption with associated data pub mod aead { + #[cfg(not(feature = "libcrux"))] + pub use crate::subtle::chacha20poly1305_ietf::{decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN}; + #[cfg(feature = "libcrux")] pub use crate::subtle::chacha20poly1305_ietf::{decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN}; } diff --git a/ciphers/src/subtle/chacha20poly1305_ietf_libcrux.rs b/ciphers/src/subtle/chacha20poly1305_ietf_libcrux.rs new file mode 100644 index 0000000..76bd024 --- /dev/null +++ b/ciphers/src/subtle/chacha20poly1305_ietf_libcrux.rs @@ -0,0 +1,60 @@ +use rosenpass_to::ops::copy_slice; +use rosenpass_to::To; + +use zeroize::Zeroize; + +pub const KEY_LEN: usize = 32; // Grrrr! Libcrux, please provide me these constants. +pub const TAG_LEN: usize = 16; +pub const NONCE_LEN: usize = 12; + +#[inline] +pub fn encrypt( + ciphertext: &mut [u8], + key: &[u8], + nonce: &[u8], + ad: &[u8], + plaintext: &[u8], +) -> anyhow::Result<()> { + let (ciphertext, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN); + + use libcrux::aead as C; + let crux_key = C::Key::Chacha20Poly1305(C::Chacha20Key(key.try_into().unwrap())); + let crux_iv = C::Iv(nonce.try_into().unwrap()); + + copy_slice(plaintext).to(ciphertext); + let crux_tag = libcrux::aead::encrypt(&crux_key, ciphertext, crux_iv, ad).unwrap(); + copy_slice(crux_tag.as_ref()).to(mac); + + match crux_key { + C::Key::Chacha20Poly1305(mut k) => k.0.zeroize(), + _ => panic!(), + } + + Ok(()) +} + +#[inline] +pub fn decrypt( + plaintext: &mut [u8], + key: &[u8], + nonce: &[u8], + ad: &[u8], + ciphertext: &[u8], +) -> anyhow::Result<()> { + let (ciphertext, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN); + + use libcrux::aead as C; + let crux_key = C::Key::Chacha20Poly1305(C::Chacha20Key(key.try_into().unwrap())); + let crux_iv = C::Iv(nonce.try_into().unwrap()); + let crux_tag = C::Tag::from_slice(mac).unwrap(); + + copy_slice(ciphertext).to(plaintext); + libcrux::aead::decrypt(&crux_key, plaintext, crux_iv, ad, &crux_tag).unwrap(); + + match crux_key { + C::Key::Chacha20Poly1305(mut k) => k.0.zeroize(), + _ => panic!(), + } + + Ok(()) +} diff --git a/ciphers/src/subtle/mod.rs b/ciphers/src/subtle/mod.rs index d9c9ecf..fc82773 100644 --- a/ciphers/src/subtle/mod.rs +++ b/ciphers/src/subtle/mod.rs @@ -1,4 +1,7 @@ pub mod blake2b; +#[cfg(not(feature = "libcrux"))] pub mod chacha20poly1305_ietf; +#[cfg(feature = "libcrux")] +pub mod chacha20poly1305_ietf_libcrux; pub mod incorrect_hmac_blake2b; pub mod xchacha20poly1305_ietf; diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index b214b95..f8ac42f 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -4,6 +4,9 @@ version = "0.0.1" publish = false edition = "2021" +[features] +experiment_libcrux = ["rosenpass-ciphers/experiment_libcrux"] + [package.metadata] cargo-fuzz = true @@ -81,4 +84,4 @@ doc = false name = "fuzz_vec_secret_alloc_memfdsec_mallocfb" path = "fuzz_targets/vec_secret_alloc_memfdsec_mallocfb.rs" test = false -doc = false \ No newline at end of file +doc = false diff --git a/rosenpass/Cargo.toml b/rosenpass/Cargo.toml index 5824af3..a90c458 100644 --- a/rosenpass/Cargo.toml +++ b/rosenpass/Cargo.toml @@ -53,4 +53,5 @@ procspawn = {workspace = true} [features] enable_broker_api = ["rosenpass-wireguard-broker/enable_broker_api"] -enable_memfd_alloc = [] \ No newline at end of file +enable_memfd_alloc = [] +experiment_libcrux = ["rosenpass-ciphers/experiment_libcrux"] diff --git a/rp/Cargo.toml b/rp/Cargo.toml index 9fc4b53..95e3bab 100644 --- a/rp/Cargo.toml +++ b/rp/Cargo.toml @@ -40,3 +40,4 @@ stacker = {workspace = true} [features] enable_memfd_alloc = [] +experiment_libcrux = ["rosenpass-ciphers/experiment_libcrux"]