HPKE, defined in RFC 9180, is a CFRG standard that describes a scheme for hybrid public key encryption. It is co-authored by my Cryspen co-founder Karthikeyan Bhargavan and one of his PhD students Benjamin Lipp as part of his research at Inria.
This blog post will give a brief overview of the specification and describes some use cases.
If you want to learn more about the security proofs behind HPKE and the RFC process, Benjamin wrote an excellent blog post about it.
Hybrid Public Key Encryption, or short HPKE, is a cyrptographic mechanism that allows encrypting payload to a public key. It is called “hybrid” because the payload is encrypted with a symmetric scheme. The symmetric key is then encrypted to the receivers public key. The HPKE standard defines a number of natural extensions to the basic setting that allow the sender to authenticate themselves.
Hybrid Crypto Systems
Hybrid public key encryption has been used in different ways since the early 1990s in protocols such as PGP or SMIME. While these two protocols are for a very specific use case a more general version of hybrid encryption is described in ECIES. ECIES is part of many systems nowadays. Storing keys in the secure enclave on an iOS device for example uses ECIES. For a deeper explanation and history of hybrid crypto systems I recommend reading Christopher Wood’s blog post.
However, there’s no general description of hybrid public key encryption with modern primitives. The HPKE standard solves this issue. Even before the RFC is finalised it is used in specifications for ECH, MLS, ODOH, and PPM. This shows the high demand for HPKE.
HPKE has four distinct modes of operation: Base, Auth, PSK, AuthPSK. In this blog post we only describe the two most commonly used modes Base and Auth.
The Base mode is the most common use case for HPKE where payload is encrypted to a public key. All other modes are authenticated in different ways.
- Auth uses the sender’s private key for authentication
- PSK uses a pre-shared, high-entropy, key for authentication
- AuthPSK uses the sender’s private key as well as a pre-shared, high-entropy, key for authentication
Encrypting to a public key
The following figure depicts the general flow of encrypting to a public key.
This is the Base mode in HPKE.
This is the most basic application of hybrid crypto systems.
Alex knows the public key from Sasha and wants to send some
Data to them.
Shasha’s public key is used to encrypt a shared secret, which is used to encrypt
The encrypted shared secret as well as the encrypted data is sent to Sasha, who
can retrieve the shared secret with their corresponding private key.
Encrypting to a public key & Authenticating with an asymmetric key
Sometimes it is useful or necessary to authenticate the sender of the data. This is depicted in the figure below and represents the HPKE Auth mode. The authentication is achieved by mixing in the sender’s private key such that the receiver will only retrieve the correct shared secret if the public key they use for the sender corresponds to the used private key.
HPKE is essentially standardising how to use Key Encapsulation Mechanisms (KEM) for hybrid encryption. The sender in HPKE uses a KEM to generate the shared secret as well as the encapsulation. The shared secret is then used in an AEAD (after running it through a key schedule) in order to encrypt a payload.
All HPKE use cases so far only take advantage of the single-shot APIs from HPKE.
In order to encrypt a payload to a public key the sender needs to provide the
receiver’s public key
pkR, some information
info and additional data
aad to bind the encryption
to a certain context, as well as the payload
HPKE returns the cipher text
ct as well as the encapsulation
enc that are both sent to
enc, ct <- Seal(pkR, info, aad, pt)
When using the Auth mode the sender’s private key
sk is needed in addition.
The receiver takes the encapsulation
enc and cipher text
ct together with their
private key to retrieve the payload.
pt <- Open(enc, skR, info, aad, ct)
When using the Auth mode the sender’s public key
pkS is needed in addition.
HPKE allows multiple encryptions with the same shared secret. This is favourable if multiple messages are sent from the sender to the receiver. To this end HPKE generates a context that allows encrypting (and decrypting) multiple messages.
enc, ContextS <- SetupS(pkR, info) ContextR <- SetupR(enc, skR, info)
Note that HPKE goes a step further than the AEAD RFC and simplifies the API. The consumer only needs to provide the payload and (potentially empty) additional data. HPKE takes care of providing unique nonces to the AEAD and fails if the maximum number of encryptions with the context have been performed — in particular if the nonce would overflow.
ct <- ContextS.Seal(aad, pt) pt <- ContextR.Open(aad, ct)
In some scenarios applications need to establish additional shared secrets.
This can be achieved with the HPKE exporter interface.
The API is similar to the
Open functions above but don’t require
a payload or additional data.
exporter_context and the length of the exported secret
L have to
enc, exported_secret <- SendExport(pkR, info, exporter_context, L) exported_secret <- ReceiveExport(enc, skR, info, exporter_context, L)
HPKE in MLS
MLS (Message Layer Security) is an IETF draft that standardises a new way of efficiently encrypting messages between participants in groups. It aims to solve the problem of end-to-end encryption in instant messaging. HPKE is a core building block. In order to encrypt a message to a specific entity in the protocol, MLS uses HPKE to encrypt the message to the specific public key.
HPKE in ECH
ECH (Encrypted Client Hello) is a mechanism in TLS (Transport Layer Security) for encrypting a ClientHello message under a server public key. This description from the ECH draft corresponds directly to the Base mode of HPKE as described above. This allows TLS connections to become more private because they don’t leak information about the connection, in particular the exact server the client wants to connect to.
In order to better understand the message flow and working of HPKE we put together an interactive demo below to demonstrate how HPKE works.
- First generate a key pair for the receiver.
- Then populate the info, additional data, and payload fields on the sender side.
- When clicking the “HPKE Seal” button on the sender the following happens
- The sender retrieves the public key from the receiver that has been generated in the first step.
- The sender uses HPKE to encrypt the payload together with the info and additional data to the receiver’s public key.
- The result is written into the Encoded Shared Secret and Ciphertext fields.
- When clicking “HPKE Open” the receiver uses the private key to retrieve the shared secret and decrypt the ciphertext. The “Info” and “Additional Data” are the same as entered on the sender’s side.
Try it out now!
HPKE is a simple, but very powerful new tool that allows to efficiently solve key distribution problems (see the MLS use case) as well as increase privacy in existing protocols (see the ECH use case).