-
Notifications
You must be signed in to change notification settings - Fork 570
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ounsworth KEM Combiner #4119
base: master
Are you sure you want to change the base?
Ounsworth KEM Combiner #4119
Conversation
Initial comment is that the KDFs should be split out into their own PR, and should be actual The hash based one in already implemented as SP800-56A, with the apparent extension required that 56A hash KDF doesn't support a salt (LOL LMAO WTAF) and 56C does. The KMAC one should be implemented in a dedicated way - that is to say requiring and using only KMAC rather than being theoretically generic over the mechanism. |
Ops, you are right. I thought I'd looked into the existing KDFs and decided they didn't match. I'll create a separate PR where I address this 👍 |
846bc3d
to
aadcb2a
Compare
With #4126 merged, please rebase to fix the macOS build. |
c3a9e8e
to
541f3d3
Compare
Rebased: ounsworth_kem_combiner->kem-combiner-abstraction->master |
541f3d3
to
2a6b9bf
Compare
I've rebased to master and did some major refactoring. Using a single Mode is too inflexible. Now, applications can either pass lists of public and private keys directly or define callbacks to generate/load private/public keys directly. These callbacks are no longer collected in a single _Ounsworth_Mode_but are used individually for the respective constructors. (I updated the PR description above) |
2a6b9bf
to
a50d6cb
Compare
a50d6cb
to
164e2b3
Compare
Ounsworth KEM Combiner
This KEM Combiner is based on this draft specification. Unlike X-Wing, the Ounsworth combiner (named after its main author) offers great flexibility by supporting any KEM combination. X-Wing, on the other hand, only specifies a single KEM combination (ML-KEM-768 with X25519). This flexibility is beneficial when using BSI-recommended algorithms such as FrodoKEM and brainpool curves.
Since the current draft is still in its early stages and lacks test vectors, the specification may change in the future. Additionally, I may have misinterpreted certain parts of the specification. Therefore, I have marked the implementation as experimental using the
BOTAN_UNSTABLE_API
macro.Structure of the Implementation
The Ounsworth KEM Combiner is implemented as a regular KEM. It combines any number of sub-KEMs with a specified KDF. To load/create Ounsworth private and public keys users must define how to load or create the individual keys respectively. This is done using the
Ounsworth::PrivateKeyImportInfo
,Ounsworth::PublicKeyImportInfo
, andOunsworth::PublicKeyGenerationInfo
classes.To provide flexibility in defining sub-KEMs, I want to create an interface that allows users to define and use their own KEMs in the Ounsworth Combiner. This is useful in one of our research projects where experimental PKCS#11-based instances must be combined with the Ounsworth Combiner.
However, I also understand that most applications have more straightforward requirements. To accommodate this, I provide a straightforward constructor for the predefined algorithms such as Kyber, FrodoKEM for PQC, and X25519, X448, and ECDH for the classic choice. These algorithms can be selected using an enum value.
Example:
Some limitations with the current public/private key interface make generalization a bit messy. For example, to concatenate public keys without any encoding, we need to know the length of the public key in advance. The same goes for private keys. To address this, we may want to add methods like
pk_byte_length()
andsk_byte_length()
for the private and public key interfaces in the future. For now, I worked around this limitation using algorithm-dependent methods.I decided to compose the Ounsworth key using the raw public and private key bytes. Although the encoding is not specified in the draft, I believe this is the best approach. However, in most cases, this prevents me from using Botan's generic interfaces, which adds further complexity to the implementation (see
ounsworth_mode.cpp
).Testing
Since no test vectors are available yet, I used some tests covering most of the draft's requirements.
The underlying One-Step KDF of NIST.SP.800-56C is extended and tested in One-Step Key Derivation Method with KMAC #4121.
To ensure that the predefined KEMs are configured correctly, I conducted a roundtrip test using all predefined algorithms simultaneously.
The only potential source of error remaining is the creation of the KDF inputs, specifically the composition of various fields and lengths to form the KDF input. To test this, I created a handcrafted test vector that should represent other combinations.
I also tested the key interfaces using the generic keygen tests.
General Remarks
The draft is still in its early stages, so I had to make some assumptions. For instance, the structure of the private and public keys is not specified in the draft. To address this, I documented my decisions in the doxygen documentation of the private key class.
I've already defined some OIDs in Botan's private arc to make it easier to use in protocols. These OIDs use sensible combinations for different key strengths. I've even included combinations with Frodo and Brainpool curves, which the BSI recommends. I crafted these combinations myself, but feel free to suggest other options.
I welcome any feedback on the implementation.
Pull request dependencies