jedisct1 / libsodium

A modern, portable, easy to use crypto library.
https://libsodium.org
Other
12.15k stars 1.73k forks source link

New feature: Hybrid Public Key Encryption #1044

Closed chris-wood closed 3 years ago

chris-wood commented 3 years ago

Hybrid public key encryption is a well-known cryptographic construction that allows a sender to encrypt arbitrarily-sized messages under a receiver’s public key. ECIES, for example, is one variant of this particular construction built on elliptic curve Diffie Hellman for non-interactive key exchange. However, there exists a number of standardized versions of ECIES, each of which differs in features, flexibility, security properties and, importantly, interoperability.

HPKE is an emerging IRTF standard aimed at providing a single standard for all applications and use cases wherein public key encryption is required. This includes several other IETF standards, such as the Message Layer Security protocol, TLS Encrypted Client Hello, and Oblivious DNS over HTTPS. HPKE is flexible in almost every dimension, being built primarily on Key Encapsulation Mechanisms (KEMs), Key Derivation Functions, and AEAD algorithms. (Parameterization by KEMs is particularly useful in making the protocol ready for post-quantum algorithms.)

HPKE has a growing number of interoperable implementations in widely used cryptographic libraries. The draft has test vectors available for all supported features.

HPKE is through the CFRG review process, is currently under review by the ISRG, and will likely be an RFC within the next couple of months. Given the maturity of the specification, growing number of dependent protocols and use cases, and wide community support, it seems like a fine candidate to include in libsodium. Picking a suite that is MTI for protocols like ECH seems like a perfectly fine approach. Assuming there’s support, I am definitely willing to contribute code or reviews to help land the feature!

jedisct1 commented 3 years ago

Hi Chris,

Plans for supporting HPKE were originally abandoned due to its lack of flexibility regarding the set of supported AEADs.

In order for it to make sense within libsodium, it has to be usable just as a key exchange mechanism. So that the resulting key can be used with XChaChaPoly, AEGIS, the secretstream construction, and other constructions that we have, but don't have an assigned ID. On the other hand, AES-128 GCM is not available. HPKE's single-message AEAD API is also quite limiting in addition to being redundant.

Hence the concerns I raised a while back and the consensus we came up with the "reserved" ID and usage of exported keys.

Plans for HPKE were replaced by NOISE-based constructions, as we already do in libhydrogen (and the API is really nice, and something that can be used as-is in libsodium).

But with the recent changes having been made to HPKE, it may become the primary option again.

I have a preliminary HPKE implementation for Zig that is going to make it into the standard library soon. It is not going to take much to port that implementation back into libsodium afterwards.

chris-wood commented 3 years ago

Thanks for considering the request! (I assumed this was already on your mind.)

But with the recent changes having been made to HPKE, it may become the primary option again.

Yeah, this is precisely what I was thinking :-)

I have a preliminary HPKE implementation for Zig that is going to make it into the standard library soon. It is not going to take much to port that implementation back into libsodium afterwards.

Oh, great! Can you share a pointer to the Zig change(s)?

jedisct1 commented 3 years ago

Oh, great! Can you share a pointer to the Zig change(s)?

https://github.com/jedisct1/zig-hpke - unfinished, as I paused it to write the compact Go one.

Something a little bit annoying in implementing HPKE, which is transparent in Go and Rust, is the fact that it requires dynamic memory allocations. In libsodium, absolutely nothing (besides memory-hard KDFs) does heap allocations, and in Zig, these must be explicit and tend to be avoided as much as possible.

chris-wood commented 3 years ago

Something a little bit annoying in implementing HPKE, which is transparent in Go and Rust, is the fact that it requires dynamic memory allocations.

Yeah, that is annoying. Could you put a cap on the amount of arbitrary information (info, psk_id, etc.) that clients provide and allocate on the stack internally based on that? I definitely agree that avoiding allocations is something we should try and avoid.

jedisct1 commented 3 years ago

Yeah, that is annoying. Could you put a cap on the amount of arbitrary information (info, psk_id, etc.) that clients provide and allocate on the stack internally based on that? I definitely agree that avoiding allocations is something we should try and avoid.

Yes, capping the sizes is probably what we will have to do.

Not sure that this is desirable, but for interoperability purposes, documenting caps in the specification may be worth it.