Compare commits

...

20 Commits

Author SHA1 Message Date
Karolin Varner
99ac3c0902 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
2024-07-03 21:46:40 +02:00
dependabot[bot]
010c14dadf build(deps): bump zerocopy from 0.7.34 to 0.7.35 (#361)
Bumps [zerocopy](https://github.com/google/zerocopy) from 0.7.34 to 0.7.35.
- [Release notes](https://github.com/google/zerocopy/releases)
- [Changelog](https://github.com/google/zerocopy/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/zerocopy/commits)

---
updated-dependencies:
- dependency-name: zerocopy
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-03 11:08:42 +02:00
dependabot[bot]
45b6132312 build(deps): bump clap from 4.5.7 to 4.5.8 (#360)
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.7 to 4.5.8.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.7...v4.5.8)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-29 20:18:42 +02:00
dependabot[bot]
77f9fd38f3 build(deps): bump log from 0.4.21 to 0.4.22 (#359)
Bumps [log](https://github.com/rust-lang/log) from 0.4.21 to 0.4.22.
- [Release notes](https://github.com/rust-lang/log/releases)
- [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/log/compare/0.4.21...0.4.22)

---
updated-dependencies:
- dependency-name: log
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-29 20:17:25 +02:00
Karolin Varner
775ed86adc Merge pull request #356 from pqcfox/hotfix/fix-kyber-encaps-fuzz-test
Fix Kyber encapsulation fuzz test shared key length to make test pass
2024-06-28 16:59:05 +02:00
Katherine Watson
40377dce1f fix: Fix shared_secret length in Kyber encaps fuzz test 2024-06-27 09:17:05 -07:00
Karolin Varner
19293471e8 Merge pull request #357 from rosenpass/dev/cve/new_name
meta: Use my new name
2024-06-27 11:15:52 +02:00
Clara Engler
cc5877dd83 meta: Use my new name 2024-06-27 10:30:34 +02:00
Karolin Varner
ebb591aa6f Merge pull request #354 from pqcfox/hotfix/fix-static-kem-branch-errors
Fix CI after merge of branch introducing PublicBox
2024-06-25 08:57:50 +02:00
Katherine Watson
07146d9914 fix: update handle_msg.rs fuzz test and handshake.rs bench to use PublicBox 2024-06-21 18:21:33 -07:00
Karolin Varner
cd04dbc4eb Move static KEM public key to new PublicBox struct 2024-06-21 13:06:05 +02:00
Katherine Watson
cc22165dc4 chore: Ensure punctuation is consistent in doc comments 2024-06-17 20:53:19 -07:00
Katherine Watson
8496571765 test: Modify existing tests to cover load/store for PublicBox as well 2024-06-17 20:49:40 -07:00
Katherine Watson
ee3a1f580e Refactor PublicBox to reuse Public code and minimize stack overhead 2024-06-17 20:49:40 -07:00
Katherine Watson
89584645c3 Migrate PublicBox to above tests 2024-06-17 20:49:40 -07:00
Katherine Watson
3286e49370 Replace &* incantations with .deref() 2024-06-17 20:49:40 -07:00
Karolin Varner
100d7b6e1c chore: Simplify some dereferencing incantations in PublicBox 2024-06-17 20:49:40 -07:00
Katherine Watson
921b2bfc39 Fix comments in PublicBox impl to refer to PublicBox 2024-06-17 20:49:40 -07:00
Katherine Watson
a18658847c Move static KEM public key to new PublicBox struct 2024-06-17 20:49:40 -07:00
Alice Michaela Bowman
bdad414c90 Add cargo-test runner for macos x86-64 (#348)
* added cargo-test runner for macos 86-64
---------

Co-authored-by: Prabhpreet Dua <615318+prabhpreet@users.noreply.github.com>
2024-06-17 15:48:19 +02:00
26 changed files with 458 additions and 123 deletions

View File

@@ -110,7 +110,12 @@ jobs:
- run: RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items
cargo-test:
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-13]
# - ubuntu is x86-64
# - macos-13 is also x86-64 architecture
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3

1
.mailmap Normal file
View File

@@ -0,0 +1 @@
Clara Engler <cve@cve.cx> <me@emilengler.com>

87
Cargo.lock generated
View File

@@ -387,9 +387,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.7"
version = "4.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d"
dependencies = [
"clap_builder",
"clap_derive",
@@ -397,9 +397,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.7"
version = "4.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708"
dependencies = [
"anstream",
"anstyle",
@@ -409,9 +409,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.5"
version = "4.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085"
dependencies = [
"heck",
"proc-macro2",
@@ -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]]
@@ -1066,6 +1068,12 @@ version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "home"
version = "0.5.9"
@@ -1222,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"
@@ -1233,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"
@@ -1261,9 +1311,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.21"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "memchr"
@@ -1885,7 +1935,7 @@ name = "rosenpass"
version = "0.2.1"
dependencies = [
"anyhow",
"clap 4.5.7",
"clap 4.5.8",
"criterion",
"derive_builder 0.20.0",
"env_logger",
@@ -1924,6 +1974,7 @@ dependencies = [
"anyhow",
"blake2",
"chacha20poly1305",
"libcrux",
"rosenpass-constant-time",
"rosenpass-oqs",
"rosenpass-secret-memory",
@@ -2008,7 +2059,7 @@ name = "rosenpass-wireguard-broker"
version = "0.1.0"
dependencies = [
"anyhow",
"clap 4.5.7",
"clap 4.5.8",
"derive_builder 0.20.0",
"env_logger",
"log",
@@ -2325,6 +2376,12 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "take-until"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4e17d8598067a8c134af59cd33c1c263470e089924a11ab61cf61690919fe3b"
[[package]]
name = "tempfile"
version = "3.10.1"
@@ -2857,8 +2914,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ba4e9811befc20af3b6efb15924a7238ee5e8e8706a196576462a00b9f1af1"
dependencies = [
"derive_builder 0.10.2",
"hex",
"libc",
"neli",
"take-until",
"thiserror",
]
@@ -2886,9 +2945,9 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.7.34"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive",
@@ -2896,9 +2955,9 @@ dependencies = [
[[package]]
name = "zerocopy-derive"
version = "0.7.34"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",

View File

@@ -44,8 +44,8 @@ allocator-api2 = "0.2.14"
memsec = { git="https://github.com/rosenpass/memsec.git" ,rev="aceb9baee8aec6844125bd6612f92e9a281373df", features = [ "alloc_ext", ] }
rand = "0.8.5"
typenum = "1.17.0"
log = { version = "0.4.21" }
clap = { version = "4.5.7", features = ["derive"] }
log = { version = "0.4.22" }
clap = { version = "4.5.8", features = ["derive"] }
serde = { version = "1.0.203", features = ["derive"] }
arbitrary = { version = "1.3.2", features = ["derive"] }
anyhow = { version = "1.0.86", features = ["backtrace", "std"] }
@@ -59,11 +59,12 @@ chacha20poly1305 = { version = "0.10.1", default-features = false, features = [
"std",
"heapless",
] }
zerocopy = { version = "0.7.34", features = ["derive"] }
zerocopy = { version = "0.7.35", features = ["derive"] }
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"
@@ -77,6 +78,6 @@ procspawn = {version = "1.0.0", features= ["test-support"]}
#Broker dependencies (might need cleanup or changes)
wireguard-uapi = "3.0.0"
wireguard-uapi = { version = "3.0.0", features = ["xplatform"] }
command-fds = "0.2.3"
rustix = { version = "0.38.27", features = ["net"] }

View File

@@ -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 }

View File

@@ -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};
}

View File

@@ -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(())
}

View File

@@ -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;

View File

@@ -108,7 +108,7 @@ Rosenpass was created by Karolin Varner, Benjamin Lipp, Wanja Zaeske,
Marei Peischl, Stephan Ajuvo, and Lisa Schmidt.
.Pp
This manual page was written by
.An Emil Engler
.An Clara Engler
.Sh BUGS
The bugs are tracked at
.Lk https://github.com/rosenpass/rosenpass/issues .

View File

@@ -113,7 +113,7 @@ Rosenpass was created by Karolin Varner, Benjamin Lipp, Wanja Zaeske,
Marei Peischl, Stephan Ajuvo, and Lisa Schmidt.
.Pp
This manual page was written by
.An Emil Engler
.An Clara Engler
.Sh BUGS
The bugs are tracked at
.Lk https://github.com/rosenpass/rosenpass/issues .

View File

@@ -4,6 +4,9 @@ version = "0.0.1"
publish = false
edition = "2021"
[features]
experiment_libcrux = ["rosenpass-ciphers/experiment_libcrux"]
[package.metadata]
cargo-fuzz = true

View File

@@ -7,14 +7,14 @@ use rosenpass::protocol::CryptoServer;
use rosenpass_cipher_traits::Kem;
use rosenpass_ciphers::kem::StaticKem;
use rosenpass_secret_memory::policy::*;
use rosenpass_secret_memory::Secret;
use rosenpass_secret_memory::{PublicBox, Secret};
use std::sync::Once;
static ONCE: Once = Once::new();
fuzz_target!(|rx_buf: &[u8]| {
ONCE.call_once(secret_policy_use_only_malloc_secrets);
let sk = Secret::from_slice(&[0; StaticKem::SK_LEN]);
let pk = Secret::from_slice(&[0; StaticKem::PK_LEN]);
let pk = PublicBox::from_slice(&[0; StaticKem::PK_LEN]);
let mut cs = CryptoServer::new(sk, pk);
let mut tx_buf = [0; 10240];

View File

@@ -14,7 +14,7 @@ pub struct Input {
fuzz_target!(|input: Input| {
let mut ciphertext = [0u8; EphemeralKem::CT_LEN];
let mut shared_secret = [0u8; EphemeralKem::SK_LEN];
let mut shared_secret = [0u8; EphemeralKem::SHK_LEN];
EphemeralKem::encaps(&mut shared_secret, &mut ciphertext, &input.pk).unwrap();
});

View File

@@ -54,3 +54,4 @@ procspawn = {workspace = true}
[features]
enable_broker_api = ["rosenpass-wireguard-broker/enable_broker_api"]
enable_memfd_alloc = []
experiment_libcrux = ["rosenpass-ciphers/experiment_libcrux"]

View File

@@ -1,5 +1,6 @@
use anyhow::Result;
use rosenpass::protocol::{CryptoServer, HandleMsgResult, MsgBuf, PeerPtr, SPk, SSk, SymKey};
use std::ops::DerefMut;
use rosenpass_cipher_traits::Kem;
use rosenpass_ciphers::kem::StaticKem;
@@ -40,7 +41,7 @@ fn hs(ini: &mut CryptoServer, res: &mut CryptoServer) -> Result<()> {
fn keygen() -> Result<(SSk, SPk)> {
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
StaticKem::keygen(sk.secret_mut(), pk.secret_mut())?;
StaticKem::keygen(sk.secret_mut(), pk.deref_mut())?;
Ok((sk, pk))
}

View File

@@ -6,10 +6,11 @@ use rosenpass_secret_memory::file::StoreSecret;
use rosenpass_secret_memory::{
secret_policy_try_use_memfd_secrets, secret_policy_use_only_malloc_secrets,
};
use rosenpass_util::file::{LoadValue, LoadValueB64};
use rosenpass_util::file::{LoadValue, LoadValueB64, StoreValue};
use rosenpass_wireguard_broker::brokers::native_unix::{
NativeUnixBroker, NativeUnixBrokerConfigBaseBuilder, NativeUnixBrokerConfigBaseBuilderError,
};
use std::ops::DerefMut;
use std::path::PathBuf;
use crate::app_server::AppServerTest;
@@ -370,7 +371,7 @@ impl CliCommand {
fn generate_and_save_keypair(secret_key: PathBuf, public_key: PathBuf) -> anyhow::Result<()> {
let mut ssk = crate::protocol::SSk::random();
let mut spk = crate::protocol::SPk::random();
StaticKem::keygen(ssk.secret_mut(), spk.secret_mut())?;
StaticKem::keygen(ssk.secret_mut(), spk.deref_mut())?;
ssk.store_secret(secret_key)?;
spk.store(public_key)
}

View File

@@ -19,6 +19,7 @@
//! [CryptoServer].
//!
//! ```
//! use std::ops::DerefMut;
//! use rosenpass_secret_memory::policy::*;
//! use rosenpass_cipher_traits::Kem;
//! use rosenpass_ciphers::kem::StaticKem;
@@ -32,11 +33,11 @@
//!
//! // initialize secret and public key for peer a ...
//! let (mut peer_a_sk, mut peer_a_pk) = (SSk::zero(), SPk::zero());
//! StaticKem::keygen(peer_a_sk.secret_mut(), peer_a_pk.secret_mut())?;
//! StaticKem::keygen(peer_a_sk.secret_mut(), peer_a_pk.deref_mut())?;
//!
//! // ... and for peer b
//! let (mut peer_b_sk, mut peer_b_pk) = (SSk::zero(), SPk::zero());
//! StaticKem::keygen(peer_b_sk.secret_mut(), peer_b_pk.secret_mut())?;
//! StaticKem::keygen(peer_b_sk.secret_mut(), peer_b_pk.deref_mut())?;
//!
//! // initialize server and a pre-shared key
//! let psk = SymKey::random();
@@ -71,6 +72,7 @@
use std::convert::Infallible;
use std::mem::size_of;
use std::ops::Deref;
use std::{
collections::hash_map::{
Entry::{Occupied, Vacant},
@@ -88,7 +90,7 @@ use rosenpass_ciphers::hash_domain::{SecretHashDomain, SecretHashDomainNamespace
use rosenpass_ciphers::kem::{EphemeralKem, StaticKem};
use rosenpass_ciphers::{aead, xaead, KEY_LEN};
use rosenpass_constant_time as constant_time;
use rosenpass_secret_memory::{Public, Secret};
use rosenpass_secret_memory::{Public, PublicBox, Secret};
use rosenpass_util::{cat, mem::cpy_min, ord::max_usize, time::Timebase};
use zerocopy::{AsBytes, FromBytes, Ref};
@@ -163,7 +165,7 @@ pub fn has_happened(ev: Timing, now: Timing) -> bool {
// DATA STRUCTURES & BASIC TRAITS & ACCESSORS ////
pub type SPk = Secret<{ StaticKem::PK_LEN }>; // Just Secret<> instead of Public<> so it gets allocated on the heap
pub type SPk = PublicBox<{ StaticKem::PK_LEN }>;
pub type SSk = Secret<{ StaticKem::SK_LEN }>;
pub type EPk = Public<{ EphemeralKem::PK_LEN }>;
pub type ESk = Secret<{ EphemeralKem::SK_LEN }>;
@@ -548,7 +550,7 @@ impl CryptoServer {
pub fn pidm(&self) -> Result<PeerId> {
Ok(Public::new(
hash_domains::peerid()?
.mix(self.spkm.secret())?
.mix(self.spkm.deref())?
.into_value()))
}
@@ -708,7 +710,7 @@ impl Peer {
pub fn pidt(&self) -> Result<PeerId> {
Ok(Public::new(
hash_domains::peerid()?
.mix(self.spkt.secret())?
.mix(self.spkt.deref())?
.into_value()))
}
}
@@ -1017,7 +1019,7 @@ impl CryptoServer {
let cookie_value = active_cookie_value.unwrap();
let cookie_key = hash_domains::cookie_key()?
.mix(self.spkm.secret())?
.mix(self.spkm.deref())?
.into_value();
let mut msg_out = truncating_cast_into::<CookieReply>(tx_buf)?;
@@ -1509,7 +1511,7 @@ where
/// Calculate the message authentication code (`mac`) and also append cookie value
pub fn seal(&mut self, peer: PeerPtr, srv: &CryptoServer) -> Result<()> {
let mac = hash_domains::mac()?
.mix(peer.get(srv).spkt.secret())?
.mix(peer.get(srv).spkt.deref())?
.mix(&self.as_bytes()[span_of!(Self, msg_type..mac)])?;
self.mac.copy_from_slice(mac.into_value()[..16].as_ref());
self.seal_cookie(peer, srv)?;
@@ -1536,7 +1538,7 @@ where
/// Check the message authentication code
pub fn check_seal(&self, srv: &CryptoServer) -> Result<bool> {
let expected = hash_domains::mac()?
.mix(srv.spkm.secret())?
.mix(srv.spkm.deref())?
.mix(&self.as_bytes()[span_of!(Self, msg_type..mac)])?;
Ok(constant_time::memcmp(
&self.mac,
@@ -1641,7 +1643,7 @@ impl HandshakeState {
// calculate ad contents
let ad = hash_domains::biscuit_ad()?
.mix(srv.spkm.secret())?
.mix(srv.spkm.deref())?
.mix(self.sidi.as_slice())?
.mix(self.sidr.as_slice())?
.into_value();
@@ -1676,7 +1678,7 @@ impl HandshakeState {
// Calculate additional data fields
let ad = hash_domains::biscuit_ad()?
.mix(srv.spkm.secret())?
.mix(srv.spkm.deref())?
.mix(sidi.as_slice())?
.mix(sidr.as_slice())?
.into_value();
@@ -1763,7 +1765,7 @@ impl CryptoServer {
let mut hs = InitiatorHandshake::zero_with_timestamp(self);
// IHI1
hs.core.init(peer.get(self).spkt.secret())?;
hs.core.init(peer.get(self).spkt.deref())?;
// IHI2
hs.core.sidi.randomize();
@@ -1780,7 +1782,7 @@ impl CryptoServer {
hs.core
.encaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
ih.sctr.as_mut_slice(),
peer.get(self).spkt.secret(),
peer.get(self).spkt.deref(),
)?;
// IHI6
@@ -1789,7 +1791,7 @@ impl CryptoServer {
// IHI7
hs.core
.mix(self.spkm.secret())?
.mix(self.spkm.deref())?
.mix(peer.get(self).psk.secret())?;
// IHI8
@@ -1807,7 +1809,7 @@ impl CryptoServer {
core.sidi = SessionId::from_slice(&ih.sidi);
// IHR1
core.init(self.spkm.secret())?;
core.init(self.spkm.deref())?;
// IHR4
core.mix(&ih.sidi)?.mix(&ih.epki)?;
@@ -1815,7 +1817,7 @@ impl CryptoServer {
// IHR5
core.decaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
self.sskm.secret(),
self.spkm.secret(),
self.spkm.deref(),
&ih.sctr,
)?;
@@ -1828,7 +1830,7 @@ impl CryptoServer {
};
// IHR7
core.mix(peer.get(self).spkt.secret())?
core.mix(peer.get(self).spkt.deref())?
.mix(peer.get(self).psk.secret())?;
// IHR8
@@ -1848,7 +1850,7 @@ impl CryptoServer {
// RHR5
core.encaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
&mut rh.scti,
peer.get(self).spkt.secret(),
peer.get(self).spkt.deref(),
)?;
// RHR6
@@ -1909,14 +1911,14 @@ impl CryptoServer {
// RHI4
core.decaps_and_mix::<EphemeralKem, { EphemeralKem::SHK_LEN }>(
hs!().eski.secret(),
&*hs!().epki,
hs!().epki.deref(),
&rh.ecti,
)?;
// RHI5
core.decaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
self.sskm.secret(),
self.spkm.secret(),
self.spkm.deref(),
&rh.scti,
)?;
@@ -2113,7 +2115,7 @@ impl CryptoServer {
),
}?;
let spkt = peer.get(self).spkt.secret();
let spkt = peer.get(self).spkt.deref();
let cookie_key = hash_domains::cookie_key()?.mix(spkt)?.into_value();
let cookie_value = peer.cv().update_mut(self).unwrap();
@@ -2146,7 +2148,7 @@ fn truncating_cast_into_nomut<T: FromBytes>(buf: &[u8]) -> Result<Ref<&[u8], T>,
#[cfg(test)]
mod test {
use std::{net::SocketAddrV4, thread::sleep, time::Duration};
use std::{net::SocketAddrV4, ops::DerefMut, thread::sleep, time::Duration};
use super::*;
use serial_test::serial;
@@ -2255,7 +2257,7 @@ mod test {
fn keygen() -> Result<(SSk, SPk)> {
// TODO: Copied from the benchmark; deduplicate
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
StaticKem::keygen(sk.secret_mut(), pk.secret_mut())?;
StaticKem::keygen(sk.secret_mut(), pk.deref_mut())?;
Ok((sk, pk))
}

View File

@@ -40,3 +40,4 @@ stacker = {workspace = true}
[features]
enable_memfd_alloc = []
experiment_libcrux = ["rosenpass-ciphers/experiment_libcrux"]

View File

@@ -1,11 +1,12 @@
use std::{
fs::{self, DirBuilder},
ops::DerefMut,
os::unix::fs::{DirBuilderExt, PermissionsExt},
path::Path,
};
use anyhow::{anyhow, Result};
use rosenpass_util::file::{LoadValueB64, StoreValueB64};
use rosenpass_util::file::{LoadValueB64, StoreValue, StoreValueB64};
use zeroize::Zeroize;
use rosenpass::protocol::{SPk, SSk};
@@ -56,8 +57,8 @@ pub fn genkey(private_keys_dir: &Path) -> Result<()> {
if !pqsk_path.exists() && !pqpk_path.exists() {
let mut pqsk = SSk::random();
let mut pqpk = SPk::random();
StaticKem::keygen(pqsk.secret_mut(), pqpk.secret_mut())?;
pqpk.store_secret(pqpk_path)?;
StaticKem::keygen(pqsk.secret_mut(), pqpk.deref_mut())?;
pqpk.store(pqpk_path)?;
pqsk.store_secret(pqsk_path)?;
} else {
eprintln!(

View File

@@ -6,6 +6,7 @@ pub mod alloc;
mod public;
pub use crate::public::Public;
pub use crate::public::PublicBox;
mod secret;
pub use crate::secret::Secret;

View File

@@ -172,12 +172,153 @@ impl<const N: usize> StoreValueB64Writer for Public<N> {
}
}
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct PublicBox<const N: usize> {
pub inner: Box<Public<N>>,
}
impl<const N: usize> PublicBox<N> {
/// Create a new [PublicBox] from a byte slice
pub fn from_slice(value: &[u8]) -> Self {
Self {
inner: Box::new(Public::from_slice(value)),
}
}
/// Create a new [PublicBox] from a byte array
pub fn new(value: [u8; N]) -> Self {
Self {
inner: Box::new(Public::new(value)),
}
}
/// Create a zero initialized [PublicBox]
pub fn zero() -> Self {
Self {
inner: Box::new(Public::zero()),
}
}
/// Create a random initialized [PublicBox]
pub fn random() -> Self {
Self {
inner: Box::new(Public::random()),
}
}
/// Randomize all bytes in an existing [PublicBox]
pub fn randomize(&mut self) {
self.inner.randomize()
}
}
impl<const N: usize> Randomize for PublicBox<N> {
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), rand::Error> {
self.inner.try_fill(rng)
}
}
impl<const N: usize> fmt::Debug for PublicBox<N> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
debug_crypto_array(&**self, fmt)
}
}
impl<const N: usize> Deref for PublicBox<N> {
type Target = [u8; N];
fn deref(&self) -> &[u8; N] {
self.inner.deref()
}
}
impl<const N: usize> DerefMut for PublicBox<N> {
fn deref_mut(&mut self) -> &mut [u8; N] {
self.inner.deref_mut()
}
}
impl<const N: usize> Borrow<[u8]> for PublicBox<N> {
fn borrow(&self) -> &[u8] {
self.deref()
}
}
impl<const N: usize> BorrowMut<[u8]> for PublicBox<N> {
fn borrow_mut(&mut self) -> &mut [u8] {
self.deref_mut()
}
}
impl<const N: usize> LoadValue for PublicBox<N> {
type Error = anyhow::Error;
// This is implemented separately from Public to avoid allocating too much stack memory
fn load<P: AsRef<Path>>(path: P) -> anyhow::Result<Self> {
let mut p = Self::random();
fopen_r(path)?.read_exact_to_end(p.deref_mut())?;
Ok(p)
}
}
impl<const N: usize> StoreValue for PublicBox<N> {
type Error = anyhow::Error;
fn store<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> {
self.inner.store(path)
}
}
impl<const N: usize> LoadValueB64 for PublicBox<N> {
type Error = anyhow::Error;
// This is implemented separately from Public to avoid allocating too much stack memory
fn load_b64<const F: usize, P: AsRef<Path>>(path: P) -> Result<Self, Self::Error>
where
Self: Sized,
{
// A vector is used here to ensure heap allocation without copy from stack
let mut f = vec![0u8; F];
let mut v = PublicBox::zero();
let p = path.as_ref();
let len = fopen_r(p)?
.read_slice_to_end(&mut f)
.with_context(|| format!("Could not load file {p:?}"))?;
b64_decode(&f[0..len], v.deref_mut())
.with_context(|| format!("Could not decode base64 file {p:?}"))?;
Ok(v)
}
}
impl<const N: usize> StoreValueB64 for PublicBox<N> {
type Error = anyhow::Error;
fn store_b64<const F: usize, P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> {
self.inner.store_b64::<F, P>(path)
}
}
impl<const N: usize> StoreValueB64Writer for PublicBox<N> {
type Error = anyhow::Error;
fn store_b64_writer<const F: usize, W: std::io::Write>(
&self,
writer: W,
) -> Result<(), Self::Error> {
self.inner.store_b64_writer::<F, W>(writer)
}
}
#[cfg(test)]
mod tests {
#[cfg(test)]
mod tests {
use crate::Public;
use crate::{Public, PublicBox};
use rosenpass_util::{
b64::b64_encode,
file::{
@@ -185,32 +326,35 @@ mod tests {
Visibility,
},
};
use std::{fs, os::unix::fs::PermissionsExt};
use std::{fs, ops::Deref, os::unix::fs::PermissionsExt};
use tempfile::tempdir;
/// test loading a public from an example file, and then storing it again in a different file
#[test]
fn test_public_load_store() {
/// Number of bytes in payload for load and store tests
const N: usize = 100;
/// Convenience function for running a load/store test
fn run_load_store_test<
T: LoadValue<Error = anyhow::Error>
+ StoreValue<Error = anyhow::Error>
+ Deref<Target = [u8; N]>,
>() {
// Generate original random bytes
let original_bytes: [u8; N] = [rand::random(); N];
// Create a temporary directory
let temp_dir = tempdir().unwrap();
// Store the original public to an example file in the temporary directory
// Store the original bytes to an example file in the temporary directory
let example_file = temp_dir.path().join("example_file");
std::fs::write(example_file.clone(), &original_bytes).unwrap();
// Load the public from the example file
// Load the value from the example file into our generic type
let loaded_public = T::load(&example_file).unwrap();
let loaded_public = Public::load(&example_file).unwrap();
// Check that the loaded value matches the original bytes
assert_eq!(loaded_public.deref(), &original_bytes);
// Check that the loaded public matches the original bytes
assert_eq!(&loaded_public.value, &original_bytes);
// Store the loaded public to a different file in the temporary directory
// Store the loaded value to a different file in the temporary directory
let new_file = temp_dir.path().join("new_file");
loaded_public.store(&new_file).unwrap();
@@ -224,10 +368,13 @@ mod tests {
assert_eq!(new_file_contents, original_file_contents);
}
/// test loading a base64 encoded public from an example file, and then storing it again in a different file
#[test]
fn test_public_load_store_base64() {
const N: usize = 100;
/// Convenience function for running a base64 load/store test
fn run_base64_load_store_test<
T: LoadValueB64<Error = anyhow::Error>
+ StoreValueB64<Error = anyhow::Error>
+ StoreValueB64Writer<Error = anyhow::Error>
+ Deref<Target = [u8; N]>,
>() {
// Generate original random bytes
let original_bytes: [u8; N] = [rand::random(); N];
// Create a temporary directory
@@ -238,9 +385,9 @@ mod tests {
std::fs::write(&example_file, encoded_public).unwrap();
// Load the public from the example file
let loaded_public = Public::load_b64::<{ N * 2 }, _>(&example_file).unwrap();
let loaded_public = T::load_b64::<{ N * 2 }, _>(&example_file).unwrap();
// Check that the loaded public matches the original bytes
assert_eq!(&loaded_public.value, &original_bytes);
assert_eq!(loaded_public.deref(), &original_bytes);
// Store the loaded public to a different file in the temporary directory
let new_file = temp_dir.path().join("new_file");
@@ -275,5 +422,31 @@ mod tests {
let metadata = fs::metadata(&new_file).unwrap();
assert_eq!(metadata.permissions().mode() & 0o000777, 0o644);
}
/// Test loading a [Public] from an example file, and then storing it again in a new file
#[test]
fn test_public_load_store() {
run_load_store_test::<Public<N>>();
}
/// Test loading a [PublicBox] from an example file, and then storing it again in a new file
#[test]
fn test_public_box_load_store() {
run_load_store_test::<PublicBox<N>>();
}
/// Test loading a base64-encoded [Public] from an example file, and then storing it again
/// in a different file
#[test]
fn test_public_load_store_base64() {
run_base64_load_store_test::<Public<N>>();
}
/// Test loading a base64-encoded [PublicBox] from an example file, and then storing it
/// again in a different file
#[test]
fn test_public_box_load_store_base64() {
run_base64_load_store_test::<PublicBox<N>>();
}
}
}

View File

@@ -44,6 +44,7 @@ path = "src/bin/priviledged.rs"
test = false
doc = false
required-features=["enable_broker_api"]
cfg = { target_os = "linux" }
[[bin]]
name = "rosenpass-wireguard-broker-socket-handler"
@@ -51,3 +52,4 @@ test = false
path = "src/bin/socket_handler.rs"
doc = false
required-features=["enable_broker_api"]
cfg = { target_os = "linux" }

View File

@@ -1,3 +1,13 @@
fn main() {
#[cfg(target_os = "linux")]
linux::main().unwrap();
#[cfg(not(target_os = "linux"))]
panic!("This binary is only supported on Linux");
}
#[cfg(target_os = "linux")]
pub mod linux {
use std::io::{stdin, stdout, Read, Write};
use std::result::Result;
@@ -17,7 +27,7 @@ pub enum BrokerAppError {
OversizedMessage(u64),
}
fn main() -> Result<(), BrokerAppError> {
pub fn main() -> Result<(), BrokerAppError> {
let mut broker = BrokerServer::new(wg::NetlinkWireGuardBroker::new()?);
let mut stdin = stdin().lock();
@@ -54,3 +64,4 @@ fn main() -> Result<(), BrokerAppError> {
stdout.flush()?;
}
}
}

View File

@@ -1,6 +1,6 @@
#[cfg(feature = "enable_broker_api")]
pub mod mio_client;
#[cfg(feature = "enable_broker_api")]
#[cfg(all(feature = "enable_broker_api", target_os = "linux"))]
pub mod netlink;
pub mod native_unix;

View File

@@ -1,3 +1,5 @@
#![cfg(target_os = "linux")]
use std::fmt::Debug;
use wireguard_uapi::linux as wg;