mirror of
https://github.com/rosenpass/rosenpass.git
synced 2025-12-12 15:49:22 -08:00
chore: Move kems out of rosenpass crate
This commit is contained in:
committed by
Karolin Varner
parent
101c9bf4b3
commit
972e82b35f
2
.github/workflows/qc.yaml
vendored
2
.github/workflows/qc.yaml
vendored
@@ -144,5 +144,5 @@ jobs:
|
|||||||
cargo fuzz run fuzz_aead_enc_into -- -max_total_time=5
|
cargo fuzz run fuzz_aead_enc_into -- -max_total_time=5
|
||||||
cargo fuzz run fuzz_blake2b -- -max_total_time=5
|
cargo fuzz run fuzz_blake2b -- -max_total_time=5
|
||||||
cargo fuzz run fuzz_handle_msg -- -max_total_time=5
|
cargo fuzz run fuzz_handle_msg -- -max_total_time=5
|
||||||
cargo fuzz run fuzz_kyber_encaps -- -max_total_time=5
|
ulimit -s 8192000 && RUST_MIN_STACK=33554432000 && cargo fuzz run fuzz_kyber_encaps -- -max_total_time=5
|
||||||
cargo fuzz run fuzz_mceliece_encaps -- -max_total_time=5
|
cargo fuzz run fuzz_mceliece_encaps -- -max_total_time=5
|
||||||
|
|||||||
18
Cargo.lock
generated
18
Cargo.lock
generated
@@ -1110,9 +1110,9 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"memoffset",
|
"memoffset",
|
||||||
"mio",
|
"mio",
|
||||||
"oqs-sys",
|
|
||||||
"paste",
|
"paste",
|
||||||
"rand",
|
"rand",
|
||||||
|
"rosenpass-cipher-traits",
|
||||||
"rosenpass-ciphers",
|
"rosenpass-ciphers",
|
||||||
"rosenpass-constant-time",
|
"rosenpass-constant-time",
|
||||||
"rosenpass-secret-memory",
|
"rosenpass-secret-memory",
|
||||||
@@ -1127,12 +1127,17 @@ dependencies = [
|
|||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rosenpass-cipher-traits"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rosenpass-ciphers"
|
name = "rosenpass-ciphers"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"rosenpass-constant-time",
|
"rosenpass-constant-time",
|
||||||
|
"rosenpass-oqs",
|
||||||
"rosenpass-secret-memory",
|
"rosenpass-secret-memory",
|
||||||
"rosenpass-sodium",
|
"rosenpass-sodium",
|
||||||
"rosenpass-to",
|
"rosenpass-to",
|
||||||
@@ -1154,6 +1159,7 @@ dependencies = [
|
|||||||
"arbitrary",
|
"arbitrary",
|
||||||
"libfuzzer-sys",
|
"libfuzzer-sys",
|
||||||
"rosenpass",
|
"rosenpass",
|
||||||
|
"rosenpass-cipher-traits",
|
||||||
"rosenpass-ciphers",
|
"rosenpass-ciphers",
|
||||||
"rosenpass-secret-memory",
|
"rosenpass-secret-memory",
|
||||||
"rosenpass-sodium",
|
"rosenpass-sodium",
|
||||||
@@ -1161,6 +1167,16 @@ dependencies = [
|
|||||||
"stacker",
|
"stacker",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rosenpass-oqs"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"oqs-sys",
|
||||||
|
"paste",
|
||||||
|
"rosenpass-cipher-traits",
|
||||||
|
"rosenpass-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rosenpass-secret-memory"
|
name = "rosenpass-secret-memory"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ resolver = "2"
|
|||||||
|
|
||||||
members = [
|
members = [
|
||||||
"rosenpass",
|
"rosenpass",
|
||||||
|
"cipher-traits",
|
||||||
"ciphers",
|
"ciphers",
|
||||||
"util",
|
"util",
|
||||||
"constant-time",
|
"constant-time",
|
||||||
"sodium",
|
"sodium",
|
||||||
|
"oqs",
|
||||||
"to",
|
"to",
|
||||||
"fuzz",
|
"fuzz",
|
||||||
"secret-memory",
|
"secret-memory",
|
||||||
@@ -25,9 +27,11 @@ rosenpass = { path = "rosenpass" }
|
|||||||
rosenpass-util = { path = "util" }
|
rosenpass-util = { path = "util" }
|
||||||
rosenpass-constant-time = { path = "constant-time" }
|
rosenpass-constant-time = { path = "constant-time" }
|
||||||
rosenpass-sodium = { path = "sodium" }
|
rosenpass-sodium = { path = "sodium" }
|
||||||
|
rosenpass-cipher-traits = { path = "cipher-traits" }
|
||||||
rosenpass-ciphers = { path = "ciphers" }
|
rosenpass-ciphers = { path = "ciphers" }
|
||||||
rosenpass-to = { path = "to" }
|
rosenpass-to = { path = "to" }
|
||||||
rosenpass-secret-memory = { path = "secret-memory" }
|
rosenpass-secret-memory = { path = "secret-memory" }
|
||||||
|
rosenpass-oqs = { path = "oqs" }
|
||||||
criterion = "0.4.0"
|
criterion = "0.4.0"
|
||||||
test_bin = "0.4.0"
|
test_bin = "0.4.0"
|
||||||
libfuzzer-sys = "0.4"
|
libfuzzer-sys = "0.4"
|
||||||
@@ -48,7 +52,7 @@ log = { version = "0.4.20" }
|
|||||||
clap = { version = "4.4.10", features = ["derive"] }
|
clap = { version = "4.4.10", features = ["derive"] }
|
||||||
serde = { version = "1.0.193", features = ["derive"] }
|
serde = { version = "1.0.193", features = ["derive"] }
|
||||||
arbitrary = { version = "1.3.2", features = ["derive"] }
|
arbitrary = { version = "1.3.2", features = ["derive"] }
|
||||||
anyhow = { version = "1.0.75", features = ["backtrace"] }
|
anyhow = { version = "1.0.75", features = ["backtrace", "std"] }
|
||||||
mio = { version = "0.8.9", features = ["net", "os-poll"] }
|
mio = { version = "0.8.9", features = ["net", "os-poll"] }
|
||||||
libsodium-sys-stable= { version = "1.20.4", features = ["use-pkg-config"] }
|
libsodium-sys-stable= { version = "1.20.4", features = ["use-pkg-config"] }
|
||||||
oqs-sys = { version = "0.8", default-features = false, features = ['classic_mceliece', 'kyber'] }
|
oqs-sys = { version = "0.8", default-features = false, features = ['classic_mceliece', 'kyber'] }
|
||||||
|
|||||||
12
cipher-traits/Cargo.toml
Normal file
12
cipher-traits/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "rosenpass-cipher-traits"
|
||||||
|
authors = ["Karolin Varner <karo@cupdev.net>", "wucke13 <wucke13@gmail.com>"]
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
description = "Rosenpass internal traits for cryptographic primitives"
|
||||||
|
homepage = "https://rosenpass.eu/"
|
||||||
|
repository = "https://github.com/rosenpass/rosenpass"
|
||||||
|
readme = "readme.md"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
5
cipher-traits/readme.md
Normal file
5
cipher-traits/readme.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Rosenpass internal libsodium bindings
|
||||||
|
|
||||||
|
Rosenpass internal library providing traits for cryptographic primitives.
|
||||||
|
|
||||||
|
This is an internal library; not guarantee is made about its API at this point in time.
|
||||||
47
cipher-traits/src/kem.rs
Normal file
47
cipher-traits/src/kem.rs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
//! Traits and implementations for Key Encapsulation Mechanisms (KEMs)
|
||||||
|
//!
|
||||||
|
//! KEMs are the interface provided by almost all post-quantum
|
||||||
|
//! secure key exchange mechanisms.
|
||||||
|
//!
|
||||||
|
//! Conceptually KEMs are akin to public-key encryption, but instead of encrypting
|
||||||
|
//! arbitrary data, KEMs are limited to the transmission of keys, randomly chosen during
|
||||||
|
//!
|
||||||
|
//! encapsulation.
|
||||||
|
//! The [KEM] Trait describes the basic API offered by a Key Encapsulation
|
||||||
|
//! Mechanism. Two implementations for it are provided, [StaticKEM] and [EphemeralKEM].
|
||||||
|
|
||||||
|
use std::result::Result;
|
||||||
|
|
||||||
|
/// Key Encapsulation Mechanism
|
||||||
|
///
|
||||||
|
/// The KEM interface defines three operations: Key generation, key encapsulation and key
|
||||||
|
/// decapsulation.
|
||||||
|
pub trait Kem {
|
||||||
|
type Error;
|
||||||
|
|
||||||
|
/// Secrete Key length
|
||||||
|
const SK_LEN: usize;
|
||||||
|
/// Public Key length
|
||||||
|
const PK_LEN: usize;
|
||||||
|
/// Ciphertext length
|
||||||
|
const CT_LEN: usize;
|
||||||
|
/// Shared Secret length
|
||||||
|
const SHK_LEN: usize;
|
||||||
|
|
||||||
|
/// Generate a keypair consisting of secret key (`sk`) and public key (`pk`)
|
||||||
|
///
|
||||||
|
/// `keygen() -> sk, pk`
|
||||||
|
fn keygen(sk: &mut [u8], pk: &mut [u8]) -> Result<(), Self::Error>;
|
||||||
|
|
||||||
|
/// From a public key (`pk`), generate a shared key (`shk`, for local use)
|
||||||
|
/// and a cipher text (`ct`, to be sent to the owner of the `pk`).
|
||||||
|
///
|
||||||
|
/// `encaps(pk) -> shk, ct`
|
||||||
|
fn encaps(shk: &mut [u8], ct: &mut [u8], pk: &[u8]) -> Result<(), Self::Error>;
|
||||||
|
|
||||||
|
/// From a secret key (`sk`) and a cipher text (`ct`) derive a shared key
|
||||||
|
/// (`shk`)
|
||||||
|
///
|
||||||
|
/// `decaps(sk, ct) -> shk`
|
||||||
|
fn decaps(shk: &mut [u8], sk: &[u8], ct: &[u8]) -> Result<(), Self::Error>;
|
||||||
|
}
|
||||||
2
cipher-traits/src/lib.rs
Normal file
2
cipher-traits/src/lib.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
mod kem;
|
||||||
|
pub use kem::Kem;
|
||||||
@@ -15,5 +15,6 @@ rosenpass-sodium = { workspace = true }
|
|||||||
rosenpass-to = { workspace = true }
|
rosenpass-to = { workspace = true }
|
||||||
rosenpass-constant-time = { workspace = true }
|
rosenpass-constant-time = { workspace = true }
|
||||||
rosenpass-secret-memory = { workspace = true }
|
rosenpass-secret-memory = { workspace = true }
|
||||||
|
rosenpass-oqs = { workspace = true }
|
||||||
static_assertions = { workspace = true }
|
static_assertions = { workspace = true }
|
||||||
zeroize = { workspace = true }
|
zeroize = { workspace = true }
|
||||||
|
|||||||
@@ -22,3 +22,8 @@ pub mod xaead {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod hash_domain;
|
pub mod hash_domain;
|
||||||
|
|
||||||
|
pub mod kem {
|
||||||
|
pub use rosenpass_oqs::ClassicMceliece460896 as StaticKem;
|
||||||
|
pub use rosenpass_oqs::Kyber512 as EphemeralKem;
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ stacker = { workspace = true }
|
|||||||
rosenpass-secret-memory = { workspace = true }
|
rosenpass-secret-memory = { workspace = true }
|
||||||
rosenpass-sodium = { workspace = true }
|
rosenpass-sodium = { workspace = true }
|
||||||
rosenpass-ciphers = { workspace = true }
|
rosenpass-ciphers = { workspace = true }
|
||||||
|
rosenpass-cipher-traits = { workspace = true }
|
||||||
rosenpass-to = { workspace = true }
|
rosenpass-to = { workspace = true }
|
||||||
rosenpass = { workspace = true }
|
rosenpass = { workspace = true }
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ extern crate rosenpass;
|
|||||||
|
|
||||||
use libfuzzer_sys::fuzz_target;
|
use libfuzzer_sys::fuzz_target;
|
||||||
|
|
||||||
use rosenpass::pqkem::{EphemeralKEM, KEM};
|
use rosenpass_cipher_traits::Kem;
|
||||||
|
use rosenpass_ciphers::kem::EphemeralKem;
|
||||||
|
|
||||||
#[derive(arbitrary::Arbitrary, Debug)]
|
#[derive(arbitrary::Arbitrary, Debug)]
|
||||||
pub struct Input {
|
pub struct Input {
|
||||||
@@ -15,5 +16,5 @@ fuzz_target!(|input: Input| {
|
|||||||
let mut ciphertext = [0u8; 768];
|
let mut ciphertext = [0u8; 768];
|
||||||
let mut shared_secret = [0u8; 32];
|
let mut shared_secret = [0u8; 32];
|
||||||
|
|
||||||
EphemeralKEM::encaps(&mut shared_secret, &mut ciphertext, &input.pk).unwrap();
|
EphemeralKem::encaps(&mut shared_secret, &mut ciphertext, &input.pk).unwrap();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,12 +3,13 @@ extern crate rosenpass;
|
|||||||
|
|
||||||
use libfuzzer_sys::fuzz_target;
|
use libfuzzer_sys::fuzz_target;
|
||||||
|
|
||||||
use rosenpass::pqkem::{StaticKEM, KEM};
|
use rosenpass_cipher_traits::Kem;
|
||||||
|
use rosenpass_ciphers::kem::StaticKem;
|
||||||
|
|
||||||
fuzz_target!(|input: &[u8]| {
|
fuzz_target!(|input: [u8; StaticKem::PK_LEN]| {
|
||||||
let mut ciphertext = [0u8; 188];
|
let mut ciphertext = [0u8; 188];
|
||||||
let mut shared_secret = [0u8; 32];
|
let mut shared_secret = [0u8; 32];
|
||||||
|
|
||||||
// We expect errors while fuzzing therefore we do not check the result.
|
// We expect errors while fuzzing therefore we do not check the result.
|
||||||
let _ = StaticKEM::encaps(&mut shared_secret, &mut ciphertext, input);
|
let _ = StaticKem::encaps(&mut shared_secret, &mut ciphertext, &input);
|
||||||
});
|
});
|
||||||
|
|||||||
16
oqs/Cargo.toml
Normal file
16
oqs/Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
name = "rosenpass-oqs"
|
||||||
|
authors = ["Karolin Varner <karo@cupdev.net>", "wucke13 <wucke13@gmail.com>"]
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
description = "Rosenpass internal bindings to liboqs"
|
||||||
|
homepage = "https://rosenpass.eu/"
|
||||||
|
repository = "https://github.com/rosenpass/rosenpass"
|
||||||
|
readme = "readme.md"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rosenpass-cipher-traits = { workspace = true }
|
||||||
|
rosenpass-util = { workspace = true }
|
||||||
|
oqs-sys = { workspace = true }
|
||||||
|
paste = { workspace = true }
|
||||||
5
oqs/readme.md
Normal file
5
oqs/readme.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Rosenpass internal liboqs bindings
|
||||||
|
|
||||||
|
Rosenpass internal library providing bindings to liboqs.
|
||||||
|
|
||||||
|
This is an internal library; not guarantee is made about its API at this point in time.
|
||||||
80
oqs/src/kem_macro.rs
Normal file
80
oqs/src/kem_macro.rs
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
macro_rules! oqs_kem {
|
||||||
|
($name:ident) => { ::paste::paste!{
|
||||||
|
mod [< $name:snake >] {
|
||||||
|
use rosenpass_cipher_traits::Kem;
|
||||||
|
use rosenpass_util::result::Guaranteed;
|
||||||
|
|
||||||
|
pub enum [< $name:camel >] {}
|
||||||
|
|
||||||
|
/// # Panic & Safety
|
||||||
|
///
|
||||||
|
/// This Trait impl calls unsafe [oqs_sys] functions, that write to byte
|
||||||
|
/// slices only identified using raw pointers. It must be ensured that the raw
|
||||||
|
/// pointers point into byte slices of sufficient length, to avoid UB through
|
||||||
|
/// overwriting of arbitrary data. This is ensured through assertions in the
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// __Note__: This requirement is stricter than necessary, it would suffice
|
||||||
|
/// to only check that the buffers are big enough, allowing them to be even
|
||||||
|
/// bigger. However, from a correctness point of view it does not make sense to
|
||||||
|
/// allow bigger buffers.
|
||||||
|
impl Kem for [< $name:camel >] {
|
||||||
|
type Error = ::std::convert::Infallible;
|
||||||
|
|
||||||
|
const SK_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_secret_key >] as usize;
|
||||||
|
const PK_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_public_key >] as usize;
|
||||||
|
const CT_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_ciphertext >] as usize;
|
||||||
|
const SHK_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_shared_secret >] as usize;
|
||||||
|
|
||||||
|
fn keygen(sk: &mut [u8], pk: &mut [u8]) -> Guaranteed<()> {
|
||||||
|
assert_eq!(sk.len(), Self::SK_LEN);
|
||||||
|
assert_eq!(pk.len(), Self::PK_LEN);
|
||||||
|
unsafe {
|
||||||
|
oqs_call!(
|
||||||
|
::oqs_sys::kem::[< OQS_KEM _ $name:snake _ keypair >],
|
||||||
|
pk.as_mut_ptr(),
|
||||||
|
sk.as_mut_ptr()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encaps(shk: &mut [u8], ct: &mut [u8], pk: &[u8]) -> Guaranteed<()> {
|
||||||
|
assert_eq!(shk.len(), Self::SHK_LEN);
|
||||||
|
assert_eq!(ct.len(), Self::CT_LEN);
|
||||||
|
assert_eq!(pk.len(), Self::PK_LEN);
|
||||||
|
unsafe {
|
||||||
|
oqs_call!(
|
||||||
|
::oqs_sys::kem::[< OQS_KEM _ $name:snake _ encaps >],
|
||||||
|
ct.as_mut_ptr(),
|
||||||
|
shk.as_mut_ptr(),
|
||||||
|
pk.as_ptr()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decaps(shk: &mut [u8], sk: &[u8], ct: &[u8]) -> Guaranteed<()> {
|
||||||
|
assert_eq!(shk.len(), Self::SHK_LEN);
|
||||||
|
assert_eq!(sk.len(), Self::SK_LEN);
|
||||||
|
assert_eq!(ct.len(), Self::CT_LEN);
|
||||||
|
unsafe {
|
||||||
|
oqs_call!(
|
||||||
|
::oqs_sys::kem::[< OQS_KEM _ $name:snake _ decaps >],
|
||||||
|
shk.as_mut_ptr(),
|
||||||
|
ct.as_ptr(),
|
||||||
|
sk.as_ptr()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use [< $name:snake >] :: [< $name:camel >];
|
||||||
|
}}
|
||||||
|
}
|
||||||
21
oqs/src/lib.rs
Normal file
21
oqs/src/lib.rs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
macro_rules! oqs_call {
|
||||||
|
($name:path, $($args:expr),*) => {{
|
||||||
|
use oqs_sys::common::OQS_STATUS::*;
|
||||||
|
|
||||||
|
match $name($($args),*) {
|
||||||
|
OQS_SUCCESS => {}, // nop
|
||||||
|
OQS_EXTERNAL_LIB_ERROR_OPENSSL => {
|
||||||
|
panic!("OpenSSL error in liboqs' {}.", stringify!($name));
|
||||||
|
},
|
||||||
|
OQS_ERROR => {
|
||||||
|
panic!("Unknown error in liboqs' {}.", stringify!($name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
($name:ident) => { oqs_call!($name, ) };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod kem_macro;
|
||||||
|
oqs_kem!(kyber_512);
|
||||||
|
oqs_kem!(classic_mceliece_460896);
|
||||||
@@ -18,13 +18,13 @@ rosenpass-util = { workspace = true }
|
|||||||
rosenpass-constant-time = { workspace = true }
|
rosenpass-constant-time = { workspace = true }
|
||||||
rosenpass-sodium = { workspace = true }
|
rosenpass-sodium = { workspace = true }
|
||||||
rosenpass-ciphers = { workspace = true }
|
rosenpass-ciphers = { workspace = true }
|
||||||
|
rosenpass-cipher-traits = { workspace = true }
|
||||||
rosenpass-to = { workspace = true }
|
rosenpass-to = { workspace = true }
|
||||||
rosenpass-secret-memory = { workspace = true }
|
rosenpass-secret-memory = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
static_assertions = { workspace = true }
|
static_assertions = { workspace = true }
|
||||||
memoffset = { workspace = true }
|
memoffset = { workspace = true }
|
||||||
libsodium-sys-stable = { workspace = true }
|
libsodium-sys-stable = { workspace = true }
|
||||||
oqs-sys = { workspace = true }
|
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
paste = { workspace = true }
|
paste = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
use anyhow::{bail, ensure};
|
use anyhow::{bail, ensure};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use rosenpass_cipher_traits::Kem;
|
||||||
|
use rosenpass_ciphers::kem::StaticKem;
|
||||||
use rosenpass_secret_memory::file::StoreSecret;
|
use rosenpass_secret_memory::file::StoreSecret;
|
||||||
use rosenpass_util::file::{LoadValue, LoadValueB64};
|
use rosenpass_util::file::{LoadValue, LoadValueB64};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::app_server;
|
use crate::app_server;
|
||||||
use crate::app_server::AppServer;
|
use crate::app_server::AppServer;
|
||||||
use crate::{
|
use crate::protocol::{SPk, SSk, SymKey};
|
||||||
pqkem::{StaticKEM, KEM},
|
|
||||||
protocol::{SPk, SSk, SymKey},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::config;
|
use super::config;
|
||||||
|
|
||||||
@@ -163,7 +162,7 @@ impl Cli {
|
|||||||
// generate the keys and store them in files
|
// generate the keys and store them in files
|
||||||
let mut ssk = crate::protocol::SSk::random();
|
let mut ssk = crate::protocol::SSk::random();
|
||||||
let mut spk = crate::protocol::SPk::random();
|
let mut spk = crate::protocol::SPk::random();
|
||||||
StaticKEM::keygen(ssk.secret_mut(), spk.secret_mut())?;
|
StaticKem::keygen(ssk.secret_mut(), spk.secret_mut())?;
|
||||||
|
|
||||||
ssk.store_secret(skf)?;
|
ssk.store_secret(skf)?;
|
||||||
spk.store_secret(pkf)?;
|
spk.store_secret(pkf)?;
|
||||||
|
|||||||
@@ -3,15 +3,10 @@ pub mod cli;
|
|||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod hash_domains;
|
pub mod hash_domains;
|
||||||
pub mod msgs;
|
pub mod msgs;
|
||||||
pub mod pqkem;
|
|
||||||
pub mod protocol;
|
pub mod protocol;
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum RosenpassError {
|
pub enum RosenpassError {
|
||||||
#[error("error in OQS")]
|
|
||||||
Oqs,
|
|
||||||
#[error("error from external library while calling OQS")]
|
|
||||||
OqsExternalLib,
|
|
||||||
#[error("buffer size mismatch, required {required_size} but found {actual_size}")]
|
#[error("buffer size mismatch, required {required_size} but found {actual_size}")]
|
||||||
BufferSizeMismatch {
|
BufferSizeMismatch {
|
||||||
required_size: usize,
|
required_size: usize,
|
||||||
@@ -20,34 +15,3 @@ pub enum RosenpassError {
|
|||||||
#[error("invalid message type")]
|
#[error("invalid message type")]
|
||||||
InvalidMessageType(u8),
|
InvalidMessageType(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RosenpassError {
|
|
||||||
/// Helper function to check a buffer size
|
|
||||||
fn check_buffer_size(required_size: usize, actual_size: usize) -> Result<(), Self> {
|
|
||||||
if required_size != actual_size {
|
|
||||||
Err(Self::BufferSizeMismatch {
|
|
||||||
required_size,
|
|
||||||
actual_size,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extension trait to attach function calls to foreign types.
|
|
||||||
trait RosenpassMaybeError {
|
|
||||||
/// Checks whether something is an error or not
|
|
||||||
fn to_rg_error(&self) -> Result<(), RosenpassError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RosenpassMaybeError for oqs_sys::common::OQS_STATUS {
|
|
||||||
fn to_rg_error(&self) -> Result<(), RosenpassError> {
|
|
||||||
use oqs_sys::common::OQS_STATUS;
|
|
||||||
match self {
|
|
||||||
OQS_STATUS::OQS_SUCCESS => Ok(()),
|
|
||||||
OQS_STATUS::OQS_ERROR => Err(RosenpassError::Oqs),
|
|
||||||
OQS_STATUS::OQS_EXTERNAL_LIB_ERROR_OPENSSL => Err(RosenpassError::OqsExternalLib),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -44,7 +44,8 @@
|
|||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use super::RosenpassError;
|
use super::RosenpassError;
|
||||||
use crate::pqkem::*;
|
use rosenpass_cipher_traits::Kem;
|
||||||
|
use rosenpass_ciphers::kem::{EphemeralKem, StaticKem};
|
||||||
use rosenpass_ciphers::{aead, xaead, KEY_LEN};
|
use rosenpass_ciphers::{aead, xaead, KEY_LEN};
|
||||||
|
|
||||||
// Macro magic ////////////////////////////////////////////////////////////////
|
// Macro magic ////////////////////////////////////////////////////////////////
|
||||||
@@ -108,7 +109,7 @@ macro_rules! data_lense(
|
|||||||
(maybe_docstring_link $x:expr) => (stringify!([$x]));
|
(maybe_docstring_link $x:expr) => (stringify!([$x]));
|
||||||
|
|
||||||
// struct name < optional generics > := optional doc string field name : field length, ...
|
// struct name < optional generics > := optional doc string field name : field length, ...
|
||||||
($type:ident $( < $( $generic:ident ),+ > )? := $( $( #[ $attr:meta ] )* $field:ident : $len:expr ),+) => (::paste::paste!{
|
($type:ident $( < $( $generic:ident ),+ > )? := $( $( #[ $attr:meta ] )* $field:ident : $len:expr ),+) => (::paste::paste!{
|
||||||
|
|
||||||
#[allow(rustdoc::broken_intra_doc_links)]
|
#[allow(rustdoc::broken_intra_doc_links)]
|
||||||
/// A data lense to manipulate byte slices.
|
/// A data lense to manipulate byte slices.
|
||||||
@@ -274,9 +275,9 @@ data_lense! { InitHello :=
|
|||||||
/// Randomly generated connection id
|
/// Randomly generated connection id
|
||||||
sidi: 4,
|
sidi: 4,
|
||||||
/// Kyber 512 Ephemeral Public Key
|
/// Kyber 512 Ephemeral Public Key
|
||||||
epki: EphemeralKEM::PK_LEN,
|
epki: EphemeralKem::PK_LEN,
|
||||||
/// Classic McEliece Ciphertext
|
/// Classic McEliece Ciphertext
|
||||||
sctr: StaticKEM::CT_LEN,
|
sctr: StaticKem::CT_LEN,
|
||||||
/// Encryped: 16 byte hash of McEliece initiator static key
|
/// Encryped: 16 byte hash of McEliece initiator static key
|
||||||
pidic: aead::TAG_LEN + 32,
|
pidic: aead::TAG_LEN + 32,
|
||||||
/// Encrypted TAI64N Time Stamp (against replay attacks)
|
/// Encrypted TAI64N Time Stamp (against replay attacks)
|
||||||
@@ -289,9 +290,9 @@ data_lense! { RespHello :=
|
|||||||
/// Copied from InitHello
|
/// Copied from InitHello
|
||||||
sidi: 4,
|
sidi: 4,
|
||||||
/// Kyber 512 Ephemeral Ciphertext
|
/// Kyber 512 Ephemeral Ciphertext
|
||||||
ecti: EphemeralKEM::CT_LEN,
|
ecti: EphemeralKem::CT_LEN,
|
||||||
/// Classic McEliece Ciphertext
|
/// Classic McEliece Ciphertext
|
||||||
scti: StaticKEM::CT_LEN,
|
scti: StaticKem::CT_LEN,
|
||||||
/// Empty encrypted message (just an auth tag)
|
/// Empty encrypted message (just an auth tag)
|
||||||
auth: aead::TAG_LEN,
|
auth: aead::TAG_LEN,
|
||||||
/// Responders handshake state in encrypted form
|
/// Responders handshake state in encrypted form
|
||||||
|
|||||||
@@ -1,168 +0,0 @@
|
|||||||
//! Traits and implementations for Key Encapsulation Mechanisms (KEMs)
|
|
||||||
//!
|
|
||||||
//! KEMs are the interface provided by almost all post-quantum
|
|
||||||
//! secure key exchange mechanisms.
|
|
||||||
//!
|
|
||||||
//! Conceptually KEMs are akin to public-key encryption, but instead of encrypting
|
|
||||||
//! arbitrary data, KEMs are limited to the transmission of keys, randomly chosen during
|
|
||||||
//!
|
|
||||||
//! encapsulation.
|
|
||||||
//! The [KEM] Trait describes the basic API offered by a Key Encapsulation
|
|
||||||
//! Mechanism. Two implementations for it are provided, [StaticKEM] and [EphemeralKEM].
|
|
||||||
|
|
||||||
use crate::{RosenpassError, RosenpassMaybeError};
|
|
||||||
|
|
||||||
/// Key Encapsulation Mechanism
|
|
||||||
///
|
|
||||||
/// The KEM interface defines three operations: Key generation, key encapsulation and key
|
|
||||||
/// decapsulation.
|
|
||||||
pub trait KEM {
|
|
||||||
/// Secrete Key length
|
|
||||||
const SK_LEN: usize;
|
|
||||||
/// Public Key length
|
|
||||||
const PK_LEN: usize;
|
|
||||||
/// Ciphertext length
|
|
||||||
const CT_LEN: usize;
|
|
||||||
/// Shared Secret length
|
|
||||||
const SHK_LEN: usize;
|
|
||||||
|
|
||||||
/// Generate a keypair consisting of secret key (`sk`) and public key (`pk`)
|
|
||||||
///
|
|
||||||
/// `keygen() -> sk, pk`
|
|
||||||
fn keygen(sk: &mut [u8], pk: &mut [u8]) -> Result<(), RosenpassError>;
|
|
||||||
|
|
||||||
/// From a public key (`pk`), generate a shared key (`shk`, for local use)
|
|
||||||
/// and a cipher text (`ct`, to be sent to the owner of the `pk`).
|
|
||||||
///
|
|
||||||
/// `encaps(pk) -> shk, ct`
|
|
||||||
fn encaps(shk: &mut [u8], ct: &mut [u8], pk: &[u8]) -> Result<(), RosenpassError>;
|
|
||||||
|
|
||||||
/// From a secret key (`sk`) and a cipher text (`ct`) derive a shared key
|
|
||||||
/// (`shk`)
|
|
||||||
///
|
|
||||||
/// `decaps(sk, ct) -> shk`
|
|
||||||
fn decaps(shk: &mut [u8], sk: &[u8], ct: &[u8]) -> Result<(), RosenpassError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A KEM that is secure against Chosen Ciphertext Attacks (CCA).
|
|
||||||
/// In the context of rosenpass this is used for static keys.
|
|
||||||
/// Uses [Classic McEliece](https://classic.mceliece.org/) 460896 from liboqs.
|
|
||||||
///
|
|
||||||
/// Classic McEliece is chosen because of its high security margin and its small
|
|
||||||
/// ciphertexts. The public keys are humongous, but (being static keys) the are never transmitted over
|
|
||||||
/// the wire so this is not a big problem.
|
|
||||||
pub struct StaticKEM;
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// This Trait impl calls unsafe [oqs_sys] functions, that write to byte
|
|
||||||
/// slices only identified using raw pointers. It must be ensured that the raw
|
|
||||||
/// pointers point into byte slices of sufficient length, to avoid UB through
|
|
||||||
/// overwriting of arbitrary data. This is checked in the following code before
|
|
||||||
/// the unsafe calls, and an early return with an Err occurs if the byte slice
|
|
||||||
/// size does not match the required size.
|
|
||||||
///
|
|
||||||
/// __Note__: This requirement is stricter than necessary, it would suffice
|
|
||||||
/// to only check that the buffers are big enough, allowing them to be even
|
|
||||||
/// bigger. However, from a correctness point of view it does not make sense to
|
|
||||||
/// allow bigger buffers.
|
|
||||||
impl KEM for StaticKEM {
|
|
||||||
const SK_LEN: usize = oqs_sys::kem::OQS_KEM_classic_mceliece_460896_length_secret_key as usize;
|
|
||||||
const PK_LEN: usize = oqs_sys::kem::OQS_KEM_classic_mceliece_460896_length_public_key as usize;
|
|
||||||
const CT_LEN: usize = oqs_sys::kem::OQS_KEM_classic_mceliece_460896_length_ciphertext as usize;
|
|
||||||
const SHK_LEN: usize =
|
|
||||||
oqs_sys::kem::OQS_KEM_classic_mceliece_460896_length_shared_secret as usize;
|
|
||||||
|
|
||||||
fn keygen(sk: &mut [u8], pk: &mut [u8]) -> Result<(), RosenpassError> {
|
|
||||||
RosenpassError::check_buffer_size(sk.len(), Self::SK_LEN)?;
|
|
||||||
RosenpassError::check_buffer_size(pk.len(), Self::PK_LEN)?;
|
|
||||||
unsafe {
|
|
||||||
oqs_sys::kem::OQS_KEM_classic_mceliece_460896_keypair(pk.as_mut_ptr(), sk.as_mut_ptr())
|
|
||||||
.to_rg_error()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn encaps(shk: &mut [u8], ct: &mut [u8], pk: &[u8]) -> Result<(), RosenpassError> {
|
|
||||||
RosenpassError::check_buffer_size(shk.len(), Self::SHK_LEN)?;
|
|
||||||
RosenpassError::check_buffer_size(ct.len(), Self::CT_LEN)?;
|
|
||||||
RosenpassError::check_buffer_size(pk.len(), Self::PK_LEN)?;
|
|
||||||
unsafe {
|
|
||||||
oqs_sys::kem::OQS_KEM_classic_mceliece_460896_encaps(
|
|
||||||
ct.as_mut_ptr(),
|
|
||||||
shk.as_mut_ptr(),
|
|
||||||
pk.as_ptr(),
|
|
||||||
)
|
|
||||||
.to_rg_error()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decaps(shk: &mut [u8], sk: &[u8], ct: &[u8]) -> Result<(), RosenpassError> {
|
|
||||||
RosenpassError::check_buffer_size(shk.len(), Self::SHK_LEN)?;
|
|
||||||
RosenpassError::check_buffer_size(sk.len(), Self::SK_LEN)?;
|
|
||||||
RosenpassError::check_buffer_size(ct.len(), Self::CT_LEN)?;
|
|
||||||
unsafe {
|
|
||||||
oqs_sys::kem::OQS_KEM_classic_mceliece_460896_decaps(
|
|
||||||
shk.as_mut_ptr(),
|
|
||||||
ct.as_ptr(),
|
|
||||||
sk.as_ptr(),
|
|
||||||
)
|
|
||||||
.to_rg_error()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements a KEM that is secure against Chosen Plaintext Attacks (CPA).
|
|
||||||
/// In the context of rosenpass this is used for ephemeral keys.
|
|
||||||
/// Currently the implementation uses
|
|
||||||
/// [Kyber 512](https://openquantumsafe.org/liboqs/algorithms/kem/kyber) from liboqs.
|
|
||||||
///
|
|
||||||
/// This is being used for ephemeral keys; since these are use-once the first post quantum
|
|
||||||
/// wireguard paper claimed that CPA security would be sufficient. Nonetheless we choose kyber
|
|
||||||
/// which provides CCA security since there are no publicly vetted KEMs out there which provide
|
|
||||||
/// only CPA security.
|
|
||||||
pub struct EphemeralKEM;
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// This Trait impl calls unsafe [oqs_sys] functions, that write to byte
|
|
||||||
/// slices only identified using raw pointers. It must be ensured that the raw
|
|
||||||
/// pointers point into byte slices of sufficient length, to avoid UB through
|
|
||||||
/// overwriting of arbitrary data. This is checked in the following code before
|
|
||||||
/// the unsafe calls, and an early return with an Err occurs if the byte slice
|
|
||||||
/// size does not match the required size.
|
|
||||||
///
|
|
||||||
/// __Note__: This requirement is stricter than necessary, it would suffice
|
|
||||||
/// to only check that the buffers are big enough, allowing them to be even
|
|
||||||
/// bigger. However, from a correctness point of view it does not make sense to
|
|
||||||
/// allow bigger buffers.
|
|
||||||
impl KEM for EphemeralKEM {
|
|
||||||
const SK_LEN: usize = oqs_sys::kem::OQS_KEM_kyber_512_length_secret_key as usize;
|
|
||||||
const PK_LEN: usize = oqs_sys::kem::OQS_KEM_kyber_512_length_public_key as usize;
|
|
||||||
const CT_LEN: usize = oqs_sys::kem::OQS_KEM_kyber_512_length_ciphertext as usize;
|
|
||||||
const SHK_LEN: usize = oqs_sys::kem::OQS_KEM_kyber_512_length_shared_secret as usize;
|
|
||||||
fn keygen(sk: &mut [u8], pk: &mut [u8]) -> Result<(), RosenpassError> {
|
|
||||||
RosenpassError::check_buffer_size(sk.len(), Self::SK_LEN)?;
|
|
||||||
RosenpassError::check_buffer_size(pk.len(), Self::PK_LEN)?;
|
|
||||||
unsafe {
|
|
||||||
oqs_sys::kem::OQS_KEM_kyber_512_keypair(pk.as_mut_ptr(), sk.as_mut_ptr()).to_rg_error()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn encaps(shk: &mut [u8], ct: &mut [u8], pk: &[u8]) -> Result<(), RosenpassError> {
|
|
||||||
RosenpassError::check_buffer_size(shk.len(), Self::SHK_LEN)?;
|
|
||||||
RosenpassError::check_buffer_size(ct.len(), Self::CT_LEN)?;
|
|
||||||
RosenpassError::check_buffer_size(pk.len(), Self::PK_LEN)?;
|
|
||||||
unsafe {
|
|
||||||
oqs_sys::kem::OQS_KEM_kyber_512_encaps(ct.as_mut_ptr(), shk.as_mut_ptr(), pk.as_ptr())
|
|
||||||
.to_rg_error()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn decaps(shk: &mut [u8], sk: &[u8], ct: &[u8]) -> Result<(), RosenpassError> {
|
|
||||||
RosenpassError::check_buffer_size(shk.len(), Self::SHK_LEN)?;
|
|
||||||
RosenpassError::check_buffer_size(sk.len(), Self::SK_LEN)?;
|
|
||||||
RosenpassError::check_buffer_size(ct.len(), Self::CT_LEN)?;
|
|
||||||
unsafe {
|
|
||||||
oqs_sys::kem::OQS_KEM_kyber_512_decaps(shk.as_mut_ptr(), ct.as_ptr(), sk.as_ptr())
|
|
||||||
.to_rg_error()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -19,8 +19,9 @@
|
|||||||
//! [CryptoServer].
|
//! [CryptoServer].
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
|
//! use rosenpass_cipher_traits::Kem;
|
||||||
|
//! use rosenpass_ciphers::kem::StaticKem;
|
||||||
//! use rosenpass::{
|
//! use rosenpass::{
|
||||||
//! pqkem::{StaticKEM, KEM},
|
|
||||||
//! protocol::{SSk, SPk, MsgBuf, PeerPtr, CryptoServer, SymKey},
|
//! protocol::{SSk, SPk, MsgBuf, PeerPtr, CryptoServer, SymKey},
|
||||||
//! };
|
//! };
|
||||||
//! # fn main() -> anyhow::Result<()> {
|
//! # fn main() -> anyhow::Result<()> {
|
||||||
@@ -30,11 +31,11 @@
|
|||||||
//!
|
//!
|
||||||
//! // initialize secret and public key for peer a ...
|
//! // initialize secret and public key for peer a ...
|
||||||
//! let (mut peer_a_sk, mut peer_a_pk) = (SSk::zero(), SPk::zero());
|
//! 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.secret_mut())?;
|
||||||
//!
|
//!
|
||||||
//! // ... and for peer b
|
//! // ... and for peer b
|
||||||
//! let (mut peer_b_sk, mut peer_b_pk) = (SSk::zero(), SPk::zero());
|
//! 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.secret_mut())?;
|
||||||
//!
|
//!
|
||||||
//! // initialize server and a pre-shared key
|
//! // initialize server and a pre-shared key
|
||||||
//! let psk = SymKey::random();
|
//! let psk = SymKey::random();
|
||||||
@@ -67,9 +68,11 @@
|
|||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use crate::{hash_domains, msgs::*, pqkem::*};
|
use crate::{hash_domains, msgs::*};
|
||||||
use anyhow::{bail, ensure, Context, Result};
|
use anyhow::{bail, ensure, Context, Result};
|
||||||
|
use rosenpass_cipher_traits::Kem;
|
||||||
use rosenpass_ciphers::hash_domain::{SecretHashDomain, SecretHashDomainNamespace};
|
use rosenpass_ciphers::hash_domain::{SecretHashDomain, SecretHashDomainNamespace};
|
||||||
|
use rosenpass_ciphers::kem::{EphemeralKem, StaticKem};
|
||||||
use rosenpass_ciphers::{aead, xaead, KEY_LEN};
|
use rosenpass_ciphers::{aead, xaead, KEY_LEN};
|
||||||
use rosenpass_secret_memory::{Public, Secret};
|
use rosenpass_secret_memory::{Public, Secret};
|
||||||
use rosenpass_util::{cat, mem::cpy_min, ord::max_usize, time::Timebase};
|
use rosenpass_util::{cat, mem::cpy_min, ord::max_usize, time::Timebase};
|
||||||
@@ -77,6 +80,7 @@ use std::collections::hash_map::{
|
|||||||
Entry::{Occupied, Vacant},
|
Entry::{Occupied, Vacant},
|
||||||
HashMap,
|
HashMap,
|
||||||
};
|
};
|
||||||
|
use std::convert::Infallible;
|
||||||
|
|
||||||
// CONSTANTS & SETTINGS //////////////////////////
|
// CONSTANTS & SETTINGS //////////////////////////
|
||||||
|
|
||||||
@@ -135,10 +139,10 @@ pub fn has_happened(ev: Timing, now: Timing) -> bool {
|
|||||||
|
|
||||||
// DATA STRUCTURES & BASIC TRAITS & ACCESSORS ////
|
// 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 = Secret<{ StaticKem::PK_LEN }>; // Just Secret<> instead of Public<> so it gets allocated on the heap
|
||||||
pub type SSk = Secret<{ StaticKEM::SK_LEN }>;
|
pub type SSk = Secret<{ StaticKem::SK_LEN }>;
|
||||||
pub type EPk = Public<{ EphemeralKEM::PK_LEN }>;
|
pub type EPk = Public<{ EphemeralKem::PK_LEN }>;
|
||||||
pub type ESk = Secret<{ EphemeralKEM::SK_LEN }>;
|
pub type ESk = Secret<{ EphemeralKem::SK_LEN }>;
|
||||||
|
|
||||||
pub type SymKey = Secret<KEY_LEN>;
|
pub type SymKey = Secret<KEY_LEN>;
|
||||||
pub type SymHash = Public<KEY_LEN>;
|
pub type SymHash = Public<KEY_LEN>;
|
||||||
@@ -1248,7 +1252,7 @@ impl HandshakeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// I loathe "error: constant expression depends on a generic parameter"
|
// I loathe "error: constant expression depends on a generic parameter"
|
||||||
pub fn encaps_and_mix<T: KEM, const SHK_LEN: usize>(
|
pub fn encaps_and_mix<T: Kem<Error = Infallible>, const SHK_LEN: usize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ct: &mut [u8],
|
ct: &mut [u8],
|
||||||
pk: &[u8],
|
pk: &[u8],
|
||||||
@@ -1258,7 +1262,7 @@ impl HandshakeState {
|
|||||||
self.mix(pk)?.mix(shk.secret())?.mix(ct)
|
self.mix(pk)?.mix(shk.secret())?.mix(ct)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decaps_and_mix<T: KEM, const SHK_LEN: usize>(
|
pub fn decaps_and_mix<T: Kem<Error = Infallible>, const SHK_LEN: usize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
sk: &[u8],
|
sk: &[u8],
|
||||||
pk: &[u8],
|
pk: &[u8],
|
||||||
@@ -1422,7 +1426,7 @@ impl CryptoServer {
|
|||||||
ih.sidi_mut().copy_from_slice(&hs.core.sidi.value);
|
ih.sidi_mut().copy_from_slice(&hs.core.sidi.value);
|
||||||
|
|
||||||
// IHI3
|
// IHI3
|
||||||
EphemeralKEM::keygen(hs.eski.secret_mut(), &mut *hs.epki)?;
|
EphemeralKem::keygen(hs.eski.secret_mut(), &mut *hs.epki)?;
|
||||||
ih.epki_mut().copy_from_slice(&hs.epki.value);
|
ih.epki_mut().copy_from_slice(&hs.epki.value);
|
||||||
|
|
||||||
// IHI4
|
// IHI4
|
||||||
@@ -1430,7 +1434,7 @@ impl CryptoServer {
|
|||||||
|
|
||||||
// IHI5
|
// IHI5
|
||||||
hs.core
|
hs.core
|
||||||
.encaps_and_mix::<StaticKEM, { StaticKEM::SHK_LEN }>(
|
.encaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
|
||||||
ih.sctr_mut(),
|
ih.sctr_mut(),
|
||||||
peer.get(self).spkt.secret(),
|
peer.get(self).spkt.secret(),
|
||||||
)?;
|
)?;
|
||||||
@@ -1469,7 +1473,7 @@ impl CryptoServer {
|
|||||||
core.mix(ih.sidi())?.mix(ih.epki())?;
|
core.mix(ih.sidi())?.mix(ih.epki())?;
|
||||||
|
|
||||||
// IHR5
|
// IHR5
|
||||||
core.decaps_and_mix::<StaticKEM, { StaticKEM::SHK_LEN }>(
|
core.decaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
|
||||||
self.sskm.secret(),
|
self.sskm.secret(),
|
||||||
self.spkm.secret(),
|
self.spkm.secret(),
|
||||||
ih.sctr(),
|
ih.sctr(),
|
||||||
@@ -1499,10 +1503,10 @@ impl CryptoServer {
|
|||||||
core.mix(rh.sidr())?.mix(rh.sidi())?;
|
core.mix(rh.sidr())?.mix(rh.sidi())?;
|
||||||
|
|
||||||
// RHR4
|
// RHR4
|
||||||
core.encaps_and_mix::<EphemeralKEM, { EphemeralKEM::SHK_LEN }>(rh.ecti_mut(), ih.epki())?;
|
core.encaps_and_mix::<EphemeralKem, { EphemeralKem::SHK_LEN }>(rh.ecti_mut(), ih.epki())?;
|
||||||
|
|
||||||
// RHR5
|
// RHR5
|
||||||
core.encaps_and_mix::<StaticKEM, { StaticKEM::SHK_LEN }>(
|
core.encaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
|
||||||
rh.scti_mut(),
|
rh.scti_mut(),
|
||||||
peer.get(self).spkt.secret(),
|
peer.get(self).spkt.secret(),
|
||||||
)?;
|
)?;
|
||||||
@@ -1567,14 +1571,14 @@ impl CryptoServer {
|
|||||||
core.mix(rh.sidr())?.mix(rh.sidi())?;
|
core.mix(rh.sidr())?.mix(rh.sidi())?;
|
||||||
|
|
||||||
// RHI4
|
// RHI4
|
||||||
core.decaps_and_mix::<EphemeralKEM, { EphemeralKEM::SHK_LEN }>(
|
core.decaps_and_mix::<EphemeralKem, { EphemeralKem::SHK_LEN }>(
|
||||||
hs!().eski.secret(),
|
hs!().eski.secret(),
|
||||||
&*hs!().epki,
|
&*hs!().epki,
|
||||||
rh.ecti(),
|
rh.ecti(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// RHI5
|
// RHI5
|
||||||
core.decaps_and_mix::<StaticKEM, { StaticKEM::SHK_LEN }>(
|
core.decaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
|
||||||
self.sskm.secret(),
|
self.sskm.secret(),
|
||||||
self.spkm.secret(),
|
self.spkm.secret(),
|
||||||
rh.scti(),
|
rh.scti(),
|
||||||
@@ -1810,7 +1814,7 @@ mod test {
|
|||||||
fn keygen() -> Result<(SSk, SPk)> {
|
fn keygen() -> Result<(SSk, SPk)> {
|
||||||
// TODO: Copied from the benchmark; deduplicate
|
// TODO: Copied from the benchmark; deduplicate
|
||||||
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
|
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
|
||||||
StaticKEM::keygen(sk.secret_mut(), pk.secret_mut())?;
|
StaticKem::keygen(sk.secret_mut(), pk.secret_mut())?;
|
||||||
Ok((sk, pk))
|
Ok((sk, pk))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user