RustCrypto / RustCrypto/KEMs

Hybrid KEM combiner design feedback: SHA3-256 concat vs HKDF for X25519 + ML-KEM-1024

Open
#346 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
111
Forks
53
Avg merge
5d 29m
Merged PRs (30d)
2

Description

Context

I've been building a post-quantum authenticated command-and-control layer for MAVLink v2 drones using crates from this org: ml-kem for session key encapsulation, ml-dsa for per-command signing, hmac + sha3 for the session MAC. The library is at https://github.com/cleitonaugusto/CleitonQ if the code is useful context.

One thing I'd value feedback on is the hybrid KDF combiner.

The combiner pattern

For session establishment, I combine X25519 and ML-KEM-1024 shared secrets using a SHA3-256 concatenation combiner (NIST SP 800-227 §4.3.1):

pub fn derive_hybrid_session_key(x25519_ss: &[u8; 32], ml_kem_ss: &[u8; 32]) -> [u8; 32] {
    let mut h = Sha3_256::new();
    h.update(x25519_ss);
    h.update(ml_kem_ss);
    h.update(b"cleitonq-hybrid-v1");  // domain separation
    h.finalize().into()
}

The rationale: secure as long as either component is pseudo-random (so a broken X25519 or a broken ML-KEM-1024 doesn't compromise the session key in isolation), and SHA3-256 as a random oracle gives this property.

The question: would you prefer HKDF-SHA3-256(salt=x25519_ss, ikm=ml_kem_ss, info=label) over the concatenation form here? HKDF has the extract-then-expand structure that seems designed for exactly this kind of multi-source key material, but SP 800-227 lists both as valid combiners for hybrid KEMs. Is there a reason to prefer one over the other when both inputs are fixed-length (32 bytes) and the output is used directly as a MAC key?

The relay finding (as context for the use case)

During testing I found something that might be worth noting for anyone else building authenticated protocols over MAVLink: any authentication material appended after a MAVLink v2 frame boundary — after the CRC — is silently stripped by any MAVLink-aware relay (MAVProxy, mavlink-router, QGC) during normal parse-and-forward. The relay reads exactly 10 + LEN + 2 bytes per spec and discards the rest.

This affects any signature scheme (classical or post-quantum) that uses the "append-after-frame" pattern. The fix is to carry authentication material as first-class MAVLink messages so relays treat them as valid but opaque frames. A GitHub Security Advisory (GHSA-f5rj-mrxh-r7vm) documents the class of affected schemes.

The reason I mention it: if anyone else is evaluating ml-kem or ml-dsa for similar protocol-level authenticated channels, this constraint shapes the wire format significantly.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No repository file, test, or entry point is named; the issue presents an external Rust implementation and asks for design feedback. Start by reviewing the derive_hybrid_session_key example and NIST SP 800-227 §4.3.1, then determine whether the maintainers want an API or documentation change. Done means a decided and documented combiner recommendation.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cryptography, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.