chore: Move kems out of rosenpass crate

This commit is contained in:
Karolin Varner
2023-12-01 19:45:10 +01:00
committed by Karolin Varner
parent 101c9bf4b3
commit 972e82b35f
22 changed files with 259 additions and 242 deletions

View File

@@ -144,5 +144,5 @@ jobs:
cargo fuzz run fuzz_aead_enc_into -- -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_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

18
Cargo.lock generated
View File

@@ -1110,9 +1110,9 @@ dependencies = [
"log",
"memoffset",
"mio",
"oqs-sys",
"paste",
"rand",
"rosenpass-cipher-traits",
"rosenpass-ciphers",
"rosenpass-constant-time",
"rosenpass-secret-memory",
@@ -1127,12 +1127,17 @@ dependencies = [
"toml",
]
[[package]]
name = "rosenpass-cipher-traits"
version = "0.1.0"
[[package]]
name = "rosenpass-ciphers"
version = "0.1.0"
dependencies = [
"anyhow",
"rosenpass-constant-time",
"rosenpass-oqs",
"rosenpass-secret-memory",
"rosenpass-sodium",
"rosenpass-to",
@@ -1154,6 +1159,7 @@ dependencies = [
"arbitrary",
"libfuzzer-sys",
"rosenpass",
"rosenpass-cipher-traits",
"rosenpass-ciphers",
"rosenpass-secret-memory",
"rosenpass-sodium",
@@ -1161,6 +1167,16 @@ dependencies = [
"stacker",
]
[[package]]
name = "rosenpass-oqs"
version = "0.1.0"
dependencies = [
"oqs-sys",
"paste",
"rosenpass-cipher-traits",
"rosenpass-util",
]
[[package]]
name = "rosenpass-secret-memory"
version = "0.1.0"

View File

@@ -3,10 +3,12 @@ resolver = "2"
members = [
"rosenpass",
"cipher-traits",
"ciphers",
"util",
"constant-time",
"sodium",
"oqs",
"to",
"fuzz",
"secret-memory",
@@ -25,9 +27,11 @@ rosenpass = { path = "rosenpass" }
rosenpass-util = { path = "util" }
rosenpass-constant-time = { path = "constant-time" }
rosenpass-sodium = { path = "sodium" }
rosenpass-cipher-traits = { path = "cipher-traits" }
rosenpass-ciphers = { path = "ciphers" }
rosenpass-to = { path = "to" }
rosenpass-secret-memory = { path = "secret-memory" }
rosenpass-oqs = { path = "oqs" }
criterion = "0.4.0"
test_bin = "0.4.0"
libfuzzer-sys = "0.4"
@@ -48,7 +52,7 @@ log = { version = "0.4.20" }
clap = { version = "4.4.10", features = ["derive"] }
serde = { version = "1.0.193", 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"] }
libsodium-sys-stable= { version = "1.20.4", features = ["use-pkg-config"] }
oqs-sys = { version = "0.8", default-features = false, features = ['classic_mceliece', 'kyber'] }

12
cipher-traits/Cargo.toml Normal file
View 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
View 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
View 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
View File

@@ -0,0 +1,2 @@
mod kem;
pub use kem::Kem;

View File

@@ -15,5 +15,6 @@ rosenpass-sodium = { workspace = true }
rosenpass-to = { workspace = true }
rosenpass-constant-time = { workspace = true }
rosenpass-secret-memory = { workspace = true }
rosenpass-oqs = { workspace = true }
static_assertions = { workspace = true }
zeroize = { workspace = true }

View File

@@ -22,3 +22,8 @@ pub mod xaead {
}
pub mod hash_domain;
pub mod kem {
pub use rosenpass_oqs::ClassicMceliece460896 as StaticKem;
pub use rosenpass_oqs::Kyber512 as EphemeralKem;
}

View File

@@ -14,6 +14,7 @@ stacker = { workspace = true }
rosenpass-secret-memory = { workspace = true }
rosenpass-sodium = { workspace = true }
rosenpass-ciphers = { workspace = true }
rosenpass-cipher-traits = { workspace = true }
rosenpass-to = { workspace = true }
rosenpass = { workspace = true }

View File

@@ -4,7 +4,8 @@ extern crate rosenpass;
use libfuzzer_sys::fuzz_target;
use rosenpass::pqkem::{EphemeralKEM, KEM};
use rosenpass_cipher_traits::Kem;
use rosenpass_ciphers::kem::EphemeralKem;
#[derive(arbitrary::Arbitrary, Debug)]
pub struct Input {
@@ -15,5 +16,5 @@ fuzz_target!(|input: Input| {
let mut ciphertext = [0u8; 768];
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();
});

View File

@@ -3,12 +3,13 @@ extern crate rosenpass;
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 shared_secret = [0u8; 32];
// 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
View 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
View 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
View 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
View 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);

View File

@@ -18,13 +18,13 @@ rosenpass-util = { workspace = true }
rosenpass-constant-time = { workspace = true }
rosenpass-sodium = { workspace = true }
rosenpass-ciphers = { workspace = true }
rosenpass-cipher-traits = { workspace = true }
rosenpass-to = { workspace = true }
rosenpass-secret-memory = { workspace = true }
anyhow = { workspace = true }
static_assertions = { workspace = true }
memoffset = { workspace = true }
libsodium-sys-stable = { workspace = true }
oqs-sys = { workspace = true }
thiserror = { workspace = true }
paste = { workspace = true }
log = { workspace = true }

View File

@@ -1,15 +1,14 @@
use anyhow::{bail, ensure};
use clap::Parser;
use rosenpass_cipher_traits::Kem;
use rosenpass_ciphers::kem::StaticKem;
use rosenpass_secret_memory::file::StoreSecret;
use rosenpass_util::file::{LoadValue, LoadValueB64};
use std::path::PathBuf;
use crate::app_server;
use crate::app_server::AppServer;
use crate::{
pqkem::{StaticKEM, KEM},
protocol::{SPk, SSk, SymKey},
};
use crate::protocol::{SPk, SSk, SymKey};
use super::config;
@@ -163,7 +162,7 @@ impl Cli {
// generate the keys and store them in files
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.secret_mut())?;
ssk.store_secret(skf)?;
spk.store_secret(pkf)?;

View File

@@ -3,15 +3,10 @@ pub mod cli;
pub mod config;
pub mod hash_domains;
pub mod msgs;
pub mod pqkem;
pub mod protocol;
#[derive(thiserror::Error, Debug)]
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}")]
BufferSizeMismatch {
required_size: usize,
@@ -20,34 +15,3 @@ pub enum RosenpassError {
#[error("invalid message type")]
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),
}
}
}

View File

@@ -44,7 +44,8 @@
//! ```
use super::RosenpassError;
use crate::pqkem::*;
use rosenpass_cipher_traits::Kem;
use rosenpass_ciphers::kem::{EphemeralKem, StaticKem};
use rosenpass_ciphers::{aead, xaead, KEY_LEN};
// Macro magic ////////////////////////////////////////////////////////////////
@@ -108,7 +109,7 @@ macro_rules! data_lense(
(maybe_docstring_link $x:expr) => (stringify!([$x]));
// 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)]
/// A data lense to manipulate byte slices.
@@ -274,9 +275,9 @@ data_lense! { InitHello :=
/// Randomly generated connection id
sidi: 4,
/// Kyber 512 Ephemeral Public Key
epki: EphemeralKEM::PK_LEN,
epki: EphemeralKem::PK_LEN,
/// Classic McEliece Ciphertext
sctr: StaticKEM::CT_LEN,
sctr: StaticKem::CT_LEN,
/// Encryped: 16 byte hash of McEliece initiator static key
pidic: aead::TAG_LEN + 32,
/// Encrypted TAI64N Time Stamp (against replay attacks)
@@ -289,9 +290,9 @@ data_lense! { RespHello :=
/// Copied from InitHello
sidi: 4,
/// Kyber 512 Ephemeral Ciphertext
ecti: EphemeralKEM::CT_LEN,
ecti: EphemeralKem::CT_LEN,
/// Classic McEliece Ciphertext
scti: StaticKEM::CT_LEN,
scti: StaticKem::CT_LEN,
/// Empty encrypted message (just an auth tag)
auth: aead::TAG_LEN,
/// Responders handshake state in encrypted form

View File

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

View File

@@ -19,8 +19,9 @@
//! [CryptoServer].
//!
//! ```
//! use rosenpass_cipher_traits::Kem;
//! use rosenpass_ciphers::kem::StaticKem;
//! use rosenpass::{
//! pqkem::{StaticKEM, KEM},
//! protocol::{SSk, SPk, MsgBuf, PeerPtr, CryptoServer, SymKey},
//! };
//! # fn main() -> anyhow::Result<()> {
@@ -30,11 +31,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.secret_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.secret_mut())?;
//!
//! // initialize server and a pre-shared key
//! 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 rosenpass_cipher_traits::Kem;
use rosenpass_ciphers::hash_domain::{SecretHashDomain, SecretHashDomainNamespace};
use rosenpass_ciphers::kem::{EphemeralKem, StaticKem};
use rosenpass_ciphers::{aead, xaead, KEY_LEN};
use rosenpass_secret_memory::{Public, Secret};
use rosenpass_util::{cat, mem::cpy_min, ord::max_usize, time::Timebase};
@@ -77,6 +80,7 @@ use std::collections::hash_map::{
Entry::{Occupied, Vacant},
HashMap,
};
use std::convert::Infallible;
// CONSTANTS & SETTINGS //////////////////////////
@@ -135,10 +139,10 @@ 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 SSk = Secret<{ StaticKEM::SK_LEN }>;
pub type EPk = Public<{ EphemeralKEM::PK_LEN }>;
pub type ESk = Secret<{ EphemeralKEM::SK_LEN }>;
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 EPk = Public<{ EphemeralKem::PK_LEN }>;
pub type ESk = Secret<{ EphemeralKem::SK_LEN }>;
pub type SymKey = Secret<KEY_LEN>;
pub type SymHash = Public<KEY_LEN>;
@@ -1248,7 +1252,7 @@ impl HandshakeState {
}
// 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,
ct: &mut [u8],
pk: &[u8],
@@ -1258,7 +1262,7 @@ impl HandshakeState {
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,
sk: &[u8],
pk: &[u8],
@@ -1422,7 +1426,7 @@ impl CryptoServer {
ih.sidi_mut().copy_from_slice(&hs.core.sidi.value);
// 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);
// IHI4
@@ -1430,7 +1434,7 @@ impl CryptoServer {
// IHI5
hs.core
.encaps_and_mix::<StaticKEM, { StaticKEM::SHK_LEN }>(
.encaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
ih.sctr_mut(),
peer.get(self).spkt.secret(),
)?;
@@ -1469,7 +1473,7 @@ impl CryptoServer {
core.mix(ih.sidi())?.mix(ih.epki())?;
// IHR5
core.decaps_and_mix::<StaticKEM, { StaticKEM::SHK_LEN }>(
core.decaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
self.sskm.secret(),
self.spkm.secret(),
ih.sctr(),
@@ -1499,10 +1503,10 @@ impl CryptoServer {
core.mix(rh.sidr())?.mix(rh.sidi())?;
// 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
core.encaps_and_mix::<StaticKEM, { StaticKEM::SHK_LEN }>(
core.encaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
rh.scti_mut(),
peer.get(self).spkt.secret(),
)?;
@@ -1567,14 +1571,14 @@ impl CryptoServer {
core.mix(rh.sidr())?.mix(rh.sidi())?;
// RHI4
core.decaps_and_mix::<EphemeralKEM, { EphemeralKEM::SHK_LEN }>(
core.decaps_and_mix::<EphemeralKem, { EphemeralKem::SHK_LEN }>(
hs!().eski.secret(),
&*hs!().epki,
rh.ecti(),
)?;
// RHI5
core.decaps_and_mix::<StaticKEM, { StaticKEM::SHK_LEN }>(
core.decaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
self.sskm.secret(),
self.spkm.secret(),
rh.scti(),
@@ -1810,7 +1814,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.secret_mut())?;
Ok((sk, pk))
}