Skip to content

Commit

Permalink
Remote key retrieval and interoperability fixes (#3)
Browse files Browse the repository at this point in the history
* Added the posibility to retrieve peer ephemeral or static key from handshake state
* Added methods for accessing inner and outer handshakes of a dual layer handshake
* Renamed RustCrypto Kyber wrapper to ML-KEM
* Modified PQ protocol name formation for compatibility with Nyquist
* Added related documentation updates
  • Loading branch information
jmlepisto authored Dec 12, 2024
1 parent f9d2714 commit 92a177a
Show file tree
Hide file tree
Showing 16 changed files with 229 additions and 100 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ default = [
"use-blake2",
"use-25519",
"use-pqclean-kyber",
"use-rust-crypto-kyber",
"use-rust-crypto-ml-kem",
]

alloc = []
Expand All @@ -55,7 +55,7 @@ use-blake2 = ["blake2"]
use-aes-gcm = ["aes-gcm"]
use-chacha20poly1305 = ["chacha20poly1305"]
use-pqclean-kyber = ["pqcrypto-kyber", "pqcrypto-traits"]
use-rust-crypto-kyber = ["ml-kem"]
use-rust-crypto-ml-kem = ["ml-kem"]
use-25519 = ["x25519-dalek"]

# docs.rs-specific configuration
Expand Down
69 changes: 56 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ pattern and no handshake payload data at all:
```rust
use clatter::crypto::cipher::ChaChaPoly;
use clatter::crypto::hash::Sha512;
use clatter::crypto::kem::rust_crypto_kyber::Kyber512;
use clatter::crypto::kem::rust_crypto_ml_kem::MlKem512;
use clatter::handshakepattern::noise_pqnn;
use clatter::traits::Handshaker;
use clatter::PqHandshake;
Expand All @@ -79,7 +79,7 @@ fn main() {
let mut rng_alice = rand::thread_rng();

// Instantiate initiator handshake
let mut alice = PqHandshake::<Kyber512, Kyber512, ChaChaPoly, Sha512, _>::new(
let mut alice = PqHandshake::<MlKem512, MlKem512, ChaChaPoly, Sha512, _>::new(
noise_pqnn(), // Handshake pattern
&[], // Prologue data
true, // Are we the initiator
Expand Down Expand Up @@ -127,17 +127,17 @@ fn main() {
Clatter allows user to pick the crypto primitives they wish to use via feature flags. Below is a table
of all the configurable features supported by Clatter:

| Feature flag | Description | Default | Details |
| --- | --- | --- | --- |
| `use-25519` | Enable X25519 DH | yes | |
| `use-aes-gcm` | Enable AES-GCM cipher | yes | |
| `use-chacha20poly1305` | Enable ChaCha20-Poly1305 cipher | yes | |
| `use-sha` | Enable SHA-256 and SHA-512 hashing | yes | |
| `use-blake2` | Enable BLAKE2 hashing | yes | |
| `use-rust-crypto-kyber` | Enable Kyber KEMs by [RustCrypto][RustCrypto] | yes | |
| `use-pqclean-kyber` | Enable Kyber KEMs by [PQClean][PQClean] | yes | |
| `std` | Enable standard library support | no | Enables `std` for supported dependencies |
| `alloc` | Enable allocator support | no | |
| Feature flag | Description | Default | Details |
| --- | --- | --- | --- |
| `use-25519` | Enable X25519 DH | yes | |
| `use-aes-gcm` | Enable AES-GCM cipher | yes | |
| `use-chacha20poly1305` | Enable ChaCha20-Poly1305 cipher | yes | |
| `use-sha` | Enable SHA-256 and SHA-512 hashing | yes | |
| `use-blake2` | Enable BLAKE2 hashing | yes | |
| `use-rust-crypto-ml-kem` | Enable ML-KEM (Kyber) KEMs by [RustCrypto][RustCrypto] | yes | |
| `use-pqclean-kyber` | Enable Kyber KEMs by [PQClean][PQClean] | yes | |
| `std` | Enable standard library support | no | Enables `std` for supported dependencies |
| `alloc` | Enable allocator support | no | |

[RustCrypto]: https://github.com/RustCrypto/KEMs
[PQClean]: https://github.com/rustpq/pqcrypto
Expand Down Expand Up @@ -182,6 +182,49 @@ possible to configure a separate KEM for ephemeral use.
* PQNoise presents *SEEC*, a method for improving RNG security in bad randomness settings. Clatter
does not currently implement *SEEC*.

## Protocol Naming and Interoperability

Noise uses the protocol name as a basis for the handshake hash and for this reason it is important for
cross-implementation compatibility to have consistent naming schemes for the crypto primitives. For all
the classical ones Noise spec defines the naming but there is no absolute source for naming the PQ ones.

On top of this, there's also the fact that Kyber KEM was renamed to "ML-KEM" during the selection process
and some crypto crates still use the term "Kyber" while others have migrated to "ML-KEM". Clatter uses
whichever name the underlying crate has chosen to use.

Thus Clatter proposes and uses the following naming scheme:

| Primitive | Protocol Name |
| --- | --- |
| Kyber 512 | `Kyber512` |
| Kyber 768 | `Kyber768` |
| Kyber 1024 | `Kyber1024` |
| ML-KEM-512 | `MLKEM512` |
| ML-KEM-768 | `MLKEM768` |
| ML-KEM-1024 | `MLKEM1024` |

Clatter also includes the possibility to pick different KEMs for ehpemeral and static operations. If the
same KEM is used for both, the name of the KEM is simply placed in the protocol name in place of the DH algorithm.

Examples:

```text
Noise_pqNN_Kyber512_ChaChaPoly_BLAKE2s
Noise_pqNN_MLKEM512_ChaChaPoly_BLAKE2s
```

If, however, a different KEM is used for ephemeral and static operations, the resulting name will include both
KEMs joined together with a `+` symbol - ephemeral KEM first.

Examples:
```text
Noise_pqNN_Kyber512+Kyber1024_ChaChaPoly_BLAKE2s
Noise_pqNN_MLKEM512+Kyber768_ChaChaPoly_BLAKE2s
```




## Verification

Caltter is verified by:
Expand Down
6 changes: 3 additions & 3 deletions examples/basic_dual_layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use core::str;
use clatter::crypto::cipher::ChaChaPoly;
use clatter::crypto::dh::X25519;
use clatter::crypto::hash::Sha512;
use clatter::crypto::kem::rust_crypto_kyber::Kyber512;
use clatter::crypto::kem::rust_crypto_ml_kem::MlKem512;
use clatter::handshakepattern::{noise_nn, noise_pqnn};
use clatter::traits::Handshaker;
use clatter::{DualLayerHandshake, NqHandshake, PqHandshake};
Expand Down Expand Up @@ -38,7 +38,7 @@ fn main() {
)
.unwrap();

let alice_pq = PqHandshake::<Kyber512, Kyber512, ChaChaPoly, Sha512, _>::new(
let alice_pq = PqHandshake::<MlKem512, MlKem512, ChaChaPoly, Sha512, _>::new(
noise_pqnn(),
&[],
true,
Expand All @@ -50,7 +50,7 @@ fn main() {
)
.unwrap();

let bob_pq = PqHandshake::<Kyber512, Kyber512, ChaChaPoly, Sha512, _>::new(
let bob_pq = PqHandshake::<MlKem512, MlKem512, ChaChaPoly, Sha512, _>::new(
noise_pqnn(),
&[],
false,
Expand Down
6 changes: 3 additions & 3 deletions examples/basic_pq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ use clatter::crypto::cipher::ChaChaPoly;
use clatter::crypto::hash::Sha512;
use clatter::crypto::kem::pqclean_kyber::Kyber768;
// We can mix and match KEMs from different vendors
use clatter::crypto::kem::rust_crypto_kyber::Kyber512;
use clatter::crypto::kem::rust_crypto_ml_kem::MlKem512;
use clatter::handshakepattern::noise_pqnn;
use clatter::traits::Handshaker;
use clatter::PqHandshake;

fn main() {
let mut rng_alice = rand::thread_rng();
let mut rng_bob = rand::thread_rng();
let mut alice = PqHandshake::<Kyber512, Kyber768, ChaChaPoly, Sha512, _>::new(
let mut alice = PqHandshake::<MlKem512, Kyber768, ChaChaPoly, Sha512, _>::new(
noise_pqnn(),
&[],
true,
Expand All @@ -24,7 +24,7 @@ fn main() {
)
.unwrap();

let mut bob = PqHandshake::<Kyber512, Kyber768, ChaChaPoly, Sha512, _>::new(
let mut bob = PqHandshake::<MlKem512, Kyber768, ChaChaPoly, Sha512, _>::new(
noise_pqnn(),
&[],
false,
Expand Down
6 changes: 3 additions & 3 deletions examples/custom_crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use clatter::bytearray::{ByteArray, SensitiveByteArray};
use clatter::crypto::cipher::ChaChaPoly;
use clatter::crypto::kem::pqclean_kyber::Kyber768;
// We can mix and match KEMs from different vendors
use clatter::crypto::kem::rust_crypto_kyber::Kyber512;
use clatter::crypto::kem::rust_crypto_ml_kem::MlKem512;
use clatter::handshakepattern::noise_pqnn;
use clatter::traits::Handshaker;
use clatter::PqHandshake;
Expand Down Expand Up @@ -62,7 +62,7 @@ impl clatter::traits::Hash for MySillyHash {
fn main() {
let mut rng_alice = rand::thread_rng();
let mut rng_bob = rand::thread_rng();
let mut alice = PqHandshake::<Kyber512, Kyber768, ChaChaPoly, MySillyHash, _>::new(
let mut alice = PqHandshake::<MlKem512, Kyber768, ChaChaPoly, MySillyHash, _>::new(
noise_pqnn(),
&[],
true,
Expand All @@ -74,7 +74,7 @@ fn main() {
)
.unwrap();

let mut bob = PqHandshake::<Kyber512, Kyber768, ChaChaPoly, MySillyHash, _>::new(
let mut bob = PqHandshake::<MlKem512, Kyber768, ChaChaPoly, MySillyHash, _>::new(
noise_pqnn(),
&[],
false,
Expand Down
18 changes: 9 additions & 9 deletions fuzz/fuzz_targets/pq_handshake_payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@ use clatter::constants::MAX_MESSAGE_LEN;
use clatter::crypto::cipher::{AesGcm, ChaChaPoly};
use clatter::crypto::hash::{Blake2b, Blake2s, Sha256, Sha512};
use clatter::crypto::kem::pqclean_kyber::Kyber768;
use clatter::crypto::kem::rust_crypto_kyber::Kyber512;
use clatter::crypto::kem::rust_crypto_ml_kem::MlKem512;
use clatter::handshakepattern::*;
use clatter::traits::{Cipher, Hash, Kem};
use clatter::{Handshaker, PqHandshake};
use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
// TODO: generate all combinations
verify_with::<Kyber768, Kyber512, AesGcm, Sha256>(data);
verify_with::<Kyber768, Kyber512, AesGcm, Sha512>(data);
verify_with::<Kyber768, Kyber512, AesGcm, Blake2b>(data);
verify_with::<Kyber768, Kyber512, AesGcm, Blake2s>(data);
verify_with::<Kyber768, Kyber512, ChaChaPoly, Sha256>(data);
verify_with::<Kyber768, Kyber512, ChaChaPoly, Sha512>(data);
verify_with::<Kyber768, Kyber512, ChaChaPoly, Blake2b>(data);
verify_with::<Kyber768, Kyber512, ChaChaPoly, Blake2b>(data);
verify_with::<Kyber768, MlKem512, AesGcm, Sha256>(data);
verify_with::<Kyber768, MlKem512, AesGcm, Sha512>(data);
verify_with::<Kyber768, MlKem512, AesGcm, Blake2b>(data);
verify_with::<Kyber768, MlKem512, AesGcm, Blake2s>(data);
verify_with::<Kyber768, MlKem512, ChaChaPoly, Sha256>(data);
verify_with::<Kyber768, MlKem512, ChaChaPoly, Sha512>(data);
verify_with::<Kyber768, MlKem512, ChaChaPoly, Blake2b>(data);
verify_with::<Kyber768, MlKem512, ChaChaPoly, Blake2b>(data);
});

fn verify_with<EKEM: Kem, SKEM: Kem, C: Cipher, H: Hash>(data: &[u8]) {
Expand Down
18 changes: 9 additions & 9 deletions fuzz/fuzz_targets/pq_handshake_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@ use clatter::constants::MAX_MESSAGE_LEN;
use clatter::crypto::cipher::{AesGcm, ChaChaPoly};
use clatter::crypto::hash::{Blake2b, Blake2s, Sha256, Sha512};
use clatter::crypto::kem::pqclean_kyber::Kyber768;
use clatter::crypto::kem::rust_crypto_kyber::Kyber512;
use clatter::crypto::kem::rust_crypto_ml_kem::MlKem512;
use clatter::handshakepattern::*;
use clatter::traits::{Cipher, Hash, Kem};
use clatter::{Handshaker, PqHandshake};
use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
// TODO: generate all combinations
verify_with::<Kyber768, Kyber512, AesGcm, Sha256>(data);
verify_with::<Kyber768, Kyber512, AesGcm, Sha512>(data);
verify_with::<Kyber768, Kyber512, AesGcm, Blake2b>(data);
verify_with::<Kyber768, Kyber512, AesGcm, Blake2s>(data);
verify_with::<Kyber768, Kyber512, ChaChaPoly, Sha256>(data);
verify_with::<Kyber768, Kyber512, ChaChaPoly, Sha512>(data);
verify_with::<Kyber768, Kyber512, ChaChaPoly, Blake2b>(data);
verify_with::<Kyber768, Kyber512, ChaChaPoly, Blake2b>(data);
verify_with::<Kyber768, MlKem512, AesGcm, Sha256>(data);
verify_with::<Kyber768, MlKem512, AesGcm, Sha512>(data);
verify_with::<Kyber768, MlKem512, AesGcm, Blake2b>(data);
verify_with::<Kyber768, MlKem512, AesGcm, Blake2s>(data);
verify_with::<Kyber768, MlKem512, ChaChaPoly, Sha256>(data);
verify_with::<Kyber768, MlKem512, ChaChaPoly, Sha512>(data);
verify_with::<Kyber768, MlKem512, ChaChaPoly, Blake2b>(data);
verify_with::<Kyber768, MlKem512, ChaChaPoly, Blake2b>(data);
});

fn verify_with<EKEM: Kem, SKEM: Kem, C: Cipher, H: Hash>(data: &[u8]) {
Expand Down
18 changes: 9 additions & 9 deletions fuzz/fuzz_targets/pq_transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@ use clatter::constants::MAX_MESSAGE_LEN;
use clatter::crypto::cipher::{AesGcm, ChaChaPoly};
use clatter::crypto::hash::{Blake2b, Blake2s, Sha256, Sha512};
use clatter::crypto::kem::pqclean_kyber::Kyber768;
use clatter::crypto::kem::rust_crypto_kyber::Kyber512;
use clatter::crypto::kem::rust_crypto_ml_kem::MlKem512;
use clatter::handshakepattern::*;
use clatter::traits::{Cipher, Hash, Kem};
use clatter::{Handshaker, PqHandshake};
use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
// TODO: generate all combinations
verify_with::<Kyber768, Kyber512, AesGcm, Sha256>(data);
verify_with::<Kyber768, Kyber512, AesGcm, Sha512>(data);
verify_with::<Kyber768, Kyber512, AesGcm, Blake2b>(data);
verify_with::<Kyber768, Kyber512, AesGcm, Blake2s>(data);
verify_with::<Kyber768, Kyber512, ChaChaPoly, Sha256>(data);
verify_with::<Kyber768, Kyber512, ChaChaPoly, Sha512>(data);
verify_with::<Kyber768, Kyber512, ChaChaPoly, Blake2b>(data);
verify_with::<Kyber768, Kyber512, ChaChaPoly, Blake2b>(data);
verify_with::<Kyber768, MlKem512, AesGcm, Sha256>(data);
verify_with::<Kyber768, MlKem512, AesGcm, Sha512>(data);
verify_with::<Kyber768, MlKem512, AesGcm, Blake2b>(data);
verify_with::<Kyber768, MlKem512, AesGcm, Blake2s>(data);
verify_with::<Kyber768, MlKem512, ChaChaPoly, Sha256>(data);
verify_with::<Kyber768, MlKem512, ChaChaPoly, Sha512>(data);
verify_with::<Kyber768, MlKem512, ChaChaPoly, Blake2b>(data);
verify_with::<Kyber768, MlKem512, ChaChaPoly, Blake2b>(data);
});

fn verify_with<EKEM: Kem, SKEM: Kem, C: Cipher, H: Hash>(data: &[u8]) {
Expand Down
4 changes: 2 additions & 2 deletions src/crypto_impl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ pub mod sha;
#[cfg(feature = "use-pqclean-kyber")]
pub mod pqclean_kyber;

#[cfg(feature = "use-rust-crypto-kyber")]
pub mod rust_crypto_kyber;
#[cfg(feature = "use-rust-crypto-ml-kem")]
pub mod rust_crypto_ml_kem;

// Ciphers
#[cfg(feature = "use-aes-gcm")]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Kyber implementation by RustCrypto: https://github.com/RustCrypto/KEMs
//! ML-KEM implementation by RustCrypto: https://github.com/RustCrypto/KEMs
use ml_kem::kem::{Decapsulate, DecapsulationKey, Encapsulate, EncapsulationKey};
use ml_kem::{EncodedSizeUser, KemCore, MlKem1024Params, MlKem512Params, MlKem768Params};
Expand All @@ -9,34 +9,34 @@ use crate::error::KemError;
use crate::traits::{CryptoComponent, Kem};
use crate::KeyPair;

/// Kyber512 KEM implementation
pub struct Kyber512;
/// Kyber768 KEM implementation
pub struct Kyber768;
/// Kyber1024 KEM implementation
pub struct Kyber1024;
/// ML-KEM-512 KEM implementation
pub struct MlKem512;
/// ML-KEM-768 KEM implementation
pub struct MlKem768;
/// ML-KEM-1024 KEM implementation
pub struct MlKem1024;

impl CryptoComponent for Kyber512 {
impl CryptoComponent for MlKem512 {
fn name() -> &'static str {
"Kyber512"
"MLKEM512"
}
}

impl CryptoComponent for Kyber768 {
impl CryptoComponent for MlKem768 {
fn name() -> &'static str {
"Kyber768"
"MLKEM768"
}
}

impl CryptoComponent for Kyber1024 {
impl CryptoComponent for MlKem1024 {
fn name() -> &'static str {
"Kyber1024"
"MLKEM1024"
}
}

macro_rules! impl_kyber {
($kyber:ty, $params:ty, $sk:expr, $pk:expr, $ct:expr) => {
impl Kem for $kyber {
macro_rules! impl_ml_kem {
($ml_kem:ty, $params:ty, $sk:expr, $pk:expr, $ct:expr) => {
impl Kem for $ml_kem {
#[cfg(feature = "alloc")]
type SecretKey = SensitiveByteArray<crate::bytearray::HeapArray<$sk>>;
#[cfg(not(feature = "alloc"))]
Expand Down Expand Up @@ -95,6 +95,6 @@ macro_rules! impl_kyber {
};
}

impl_kyber!(Kyber512, MlKem512Params, 1632, 800, 768);
impl_kyber!(Kyber768, MlKem768Params, 2400, 1184, 1088);
impl_kyber!(Kyber1024, MlKem1024Params, 3168, 1568, 1568);
impl_ml_kem!(MlKem512, MlKem512Params, 1632, 800, 768);
impl_ml_kem!(MlKem768, MlKem768Params, 2400, 1184, 1088);
impl_ml_kem!(MlKem1024, MlKem1024Params, 3168, 1568, 1568);
Loading

0 comments on commit 92a177a

Please sign in to comment.