Expand description
HPKE š¤ hacspec
š” This is a hacspec representation of the HPKE RFC. The text is mostly verbatim from the RFC with changes where required. It demonstrates the possibilities of hacspec for specifications.
This document describes a scheme for hybrid public-key encryption (HPKE). This scheme provides a variant of public-key encryption of arbitrary-sized plaintexts for a recipient public key. It also includes three authenticated variants, including one which authenticates possession of a pre-shared key, and two optional ones which authenticate possession of a KEM private key. HPKE works for any combination of an asymmetric key encapsulation mechanism (KEM), key derivation function (KDF), and authenticated encryption with additional data (AEAD) encryption function. Some authenticated variants may not be supported by all KEMs. We provide instantiations of the scheme using widely used and efficient primitives, such as Elliptic Curve Diffie-Hellman key agreement, HKDF, and SHA2.
The original document is a product of the Crypto Forum Research Group (CFRG) in the IRTF.
Introduction
Encryption schemes that combine asymmetric and symmetric algorithms have been specified and practiced since the early days of public-key cryptography, e.g., RFC1421. Combining the two yields the key management advantages of asymmetric cryptography and the performance benefits of symmetric cryptography. The traditional combination has been āencrypt the symmetric key with the public key.ā āHybridā public-key encryption schemes (HPKE), specified here, take a different approach: āgenerate the symmetric key and its encapsulation with the public key.ā Specifically, encrypted messages convey an encryption key encapsulated with a public-key scheme, along with one or more arbitrary-sized ciphertexts encrypted using that key. This type of public key encryption has many applications in practice, including Messaging Layer Security mls-protocol and TLS Encrypted ClientHello tls-esni.
Currently, there are numerous competing and non-interoperable standards and variants for hybrid encryption, mostly based on ECIES, including ANSI X9.63 (ECIES), IEEE1363, ISO/IEC 18033-2, and SECG SEC 1. See MAEA10 for a thorough comparison. All these existing schemes have problems, e.g., because they rely on outdated primitives, lack proofs of IND-CCA2 security, or fail to provide test vectors.
This document defines an HPKE scheme that provides a subset of the functions provided by the collection of schemes above, but specified with sufficient clarity that they can be interoperably implemented. The HPKE construction defined herein is secure against (adaptive) chosen ciphertext attacks (IND-CCA2 secure) under classical assumptions about the underlying primitives HPKEAnalysis, ABHKLR20. A summary of these analyses is in Section 9.1.
This document represents the consensus of the Crypto Forum Research Group (CFRG).
Notation
The following terms are used throughout this document to describe the operations, roles, and behaviors of HPKE:
(skX, pkX)
: A Key Encapsulation Mechanism (KEM) key pair used in role X, where X is one of S, R, or E as sender, recipient, and ephemeral, respectively;skX
is the private key andpkX
is the public key.pk(skX)
: The KEM public key corresponding to the KEM private keyskX
.- Sender (S): Role of entity which sends an encrypted message.
- Recipient (R): Role of entity which receives an encrypted message.
- Ephemeral (E): Role of a fresh random value meant for one-time use.
I2OSP(n, w)
: Convert non-negative integern
to aw
-length, big-endian byte string as described in RFC8017.OS2IP(x)
: Convert byte stringx
to a non-negative integer as described in RFC8017, assuming big-endian byte order.concat(x0, ..., xN)
: Concatenation of byte strings.concat(0x01, 0x0203, 0x040506) = 0x010203040506
.random(n)
: A pseudorandom byte string of lengthn
bytesxor(a,b)
: XOR of byte strings;xor(0xF0F0, 0x1234) = 0xE2C4
. It is an error to call this function with two arguments of unequal length.
Cryptographic Dependencies
HPKE variants rely on the following primitives:
- A Key Encapsulation Mechanism (KEM)
- A Key Derivation Function (KDF)
- An AEAD encryption algorithm RFC5116
A ciphersuite is a triple (KEM, KDF, AEAD) containing a choice of algorithm for each primitive.
A set of algorithm identifiers for concrete instantiations of these primitives is provided in KEM, KDF, and AEAD. Algorithm identifier values are two bytes long. Future specifications may introduce new KEM, KDF, and AEAD algorithm identifiers and retain the security guarantees presented in this document.
Note that GenerateKeyPair
can be implemented as DeriveKeyPair(random(Nsk))
.
The notation pk(skX)
, depending on its use and the KEM and its
implementation, is either the
computation of the public key using the private key, or just syntax
expressing the retrieval of the public key assuming it is stored along
with the private key object.
Hybrid Public Key Encryption
In this section, we define a few HPKE variants. All variants take a
recipient public key and a sequence of plaintexts pt
, and produce an
encapsulated key enc
and a sequence of ciphertexts ct
. These outputs are
constructed so that only the holder of skR
can decapsulate the key from
enc
and decrypt the ciphertexts. All the algorithms also take an
info
parameter that can be used to influence the generation of keys
(e.g., to fold in identity information) and an aad
parameter that
provides Additional Authenticated Data to the AEAD
algorithm in use.
In addition to the base case of encrypting to a public key, we include three authenticated variants, one which authenticates possession of a pre-shared key, one which authenticates possession of a KEM private key, and one which authenticates possession of both a pre-shared key and a KEM private key. All authenticated variants contribute additional keying material to the encryption operation. The following one-byte values will be used to distinguish between modes:
Mode | Value |
---|---|
mode_base | 0x00 |
mode_psk | 0x01 |
mode_auth | 0x02 |
mode_auth_psk | 0x03 |
All these cases follow the same basic two-step pattern:
- Set up an encryption context that is shared between the sender and the recipient.
- Use that context to encrypt or decrypt content.
A context is an implementation-specific structure that encodes
the AEAD algorithm and key in use, and manages the nonces used so
that the same nonce is not used with multiple plaintexts. It also
has an interface for exporting secret values, as described in
Context_Export
. See HPKE DEM for a description of this structure
and its interfaces. HPKE decryption fails when the underlying AEAD
decryption fails.
The constructions described here presume that the relevant non-private
parameters (enc
, psk_id
, etc.) are transported between the sender and the
recipient by some application making use of HPKE. Moreover, a recipient with more
than one public key needs some way of determining which of its public keys was
used for the encapsulation operation. As an example, applications may send this
information alongside a ciphertext from sender to recipient. Specification of
such a mechanism is left to the application. See Message Encoding for more
details.
Note that some KEMs may not support AuthEncap()
or AuthDecap()
.
For such KEMs, only mode_base
or mode_psk
are supported. Future specifications
which define new KEMs MUST indicate whether these modes are supported.
See Future KEMs for more details.
The procedures described in this section are laid out in a Python-like pseudocode. The algorithms in use are left implicit. See the Implementation Considerations Section for details on the differences to this hacspec implementation.
Creating the Encryption Context
The variants of HPKE defined in this document share a common key schedule that translates the protocol inputs into an encryption context.
See KeySchedule()
for details.
Encryption to a Public Key
The most basic function of an HPKE scheme is to enable encryption to the holder of a given KEM private key.
See SetupBaseS()
and SetupBaseR()
for details.
Authentication using a Pre-Shared Key
This variant extends the base mechanism by allowing the recipient to authenticate that the sender possessed a given PSK.
See SetupPSKS()
and SetupPSKR()
for details.
Authentication using an Asymmetric Key
This variant extends the base mechanism by allowing the recipient to authenticate that the sender possessed a given KEM private key.
See SetupAuthS()
and SetupAuthR()
for details.
Authentication using both a PSK and an Asymmetric Key
This mode is a straightforward combination of the PSK and authenticated modes.
See SetupAuthPSKS()
and SetupAuthPSKR()
for details.
Encryption and Decryption
HPKE allows multiple encryption operations to be done based on a given setup transaction.
See ContextS_Seal
and ContextR_Open
for details.
Secret Export
HPKE provides an interface for exporting secrets from the encryption context using a variable-length PRF, similar to the TLS 1.3 exporter interface.
See Context_Export
for details.
Single-Shot APIs
Encryption and Decryption - Single-Shot
In many cases, applications encrypt only a single message to a recipientās public key.
See HpkeSeal
and HpkeOpen
for details.
Secret Export - Single-Shot
Applications may also want to derive a secret known only to a given recipient. This section provides templates for HPKE APIs that implement stateless āsingle-shotā secret export using APIs specified in Secret Export:
See SendExport
and ReceiveExport
.
As in Single Shot Encryption, the MODE
template parameter is one of Base, PSK,
Auth, or AuthPSK. The optional parameters indicated by āā¦ā depend on MODE
and may
be empty.
Algorithm Identifiers
This section lists algorithm identifiers suitable for different HPKE configurations. Future specifications may introduce new KEM, KDF, and AEAD algorithm identifiers and retain the security guarantees presented in this document provided they adhere to the security requirements in KEM Security, KDF Security, and AEAD Security, respectively.
See KDF, KEM, and AEAD for details on the algorithms.
API Considerations
This section documents considerations for interfaces to implementations of HPKE. This includes error handling considerations and recommendations that improve interoperability when HPKE is used in applications.
Auxiliary Authenticated Application Information
HPKE has two places at which applications can specify auxiliary authenticated information:
(1) during context construction via the Setup info
parameter, and (2) during Context
operations, i.e., with the aad
parameter for Open()
and Seal()
, and the exporter_context
parameter
for Export()
. Application information applicable to multiple operations on a single Context
should use the Setup info
parameter. This avoids redundantly processing this information for
each Context operation. In contrast, application information that varies on a per-message basis
should be specified via the Context APIs (Seal()
, Open()
, or Export()
).
Applications that only use the single-shot APIs described in {{single-shot-apis}} should use the
Setup info
parameter for specifying auxiliary authenticated information. Implementations which
only expose single-shot APIs should not allow applications to use both Setup info
and Context
aad
or exporter_context
auxiliary information parameters.
Errors
The high-level, public HPKE APIs specified in this document are all fallible.
See Errors for details.
Message Encoding
This document does not specify a wire format encoding for HPKE messages. Applications
that adopt HPKE must therefore specify an unambiguous encoding mechanism which includes,
minimally: the encapsulated value enc
, ciphertext value(s) (and order if there are
multiple), and any info values that are not implicit. One example of a non-implicit
value is the recipient public key used for encapsulation, which may be needed if a
recipient has more than one public key.
The AEAD interface used in this document is based on RFC5116, which produces and
consumes a single ciphertext value. As discussed in RFC5116, this ciphertext value
contains the encrypted plaintext as well as any authentication data, encoded in a manner
described by the individual AEAD scheme. Some implementations are not structured in this
way, instead providing a separate ciphertext and authentication tag. When such
AEAD implementations are used in HPKE implementations, the HPKE implementation must combine
these inputs into a single ciphertext value within Seal()
, and parse them out within
Open()
, where the parsing details are defined by the AEAD scheme. For example, with
the AES-GCM schemes specified in this document, the GCM authentication tag is placed in
the last Nt bytes of the ciphertext output.
Security Properties
HPKE has several security goals, depending on the mode of operation, against active and adaptive attackers that can compromise partial secrets of senders and recipients. The desired security goals are detailed below:
- Message secrecy: Confidentiality of the senderās messages against chosen ciphertext attacks
- Export key secrecy: Indistinguishability of each export
secret from a uniformly random bitstring of equal length, i.e.,
Context.Export
is a variable-length PRF - Sender authentication: Proof of sender origin for PSK, Auth, and AuthPSK modes
These security goals are expected to hold for any honest sender and honest recipient keys, as well as if the honest sender and honest recipient keys are the same.
HPKE mitigates malleability problems (called benign malleability SECG SEC 1) in prior public key encryption standards based on ECIES by including all public keys in the context of the key schedule.
HPKE does not provide forward secrecy with respect to recipient compromise.
In the Base and Auth modes, the secrecy properties are only expected to
hold if the recipient private key skR
is not compromised at any point
in time. In the PSK and AuthPSK modes, the secrecy properties are
expected to hold if the recipient private key skR
and the pre-shared key
are not both compromised at any point in time. See the non-goals section for more
details.
In the Auth mode, sender authentication is generally expected to hold if
the sender private key skS
is not compromised at the time of message
reception. In the AuthPSK mode, sender authentication is generally
expected to hold if at the time of message reception, the sender private
key skS and the pre-shared key are not both compromised.
Besides forward secrecy and key-compromise impersonation, which are highlighted in this section because of their particular cryptographic importance, HPKE has other non-goals that are described in the non-goals section: no tolerance of message reordering or loss, no downgrade or replay prevention, no hiding of the plaintext length, no protection against bad ephemeral randomness. The non-goals section suggests application-level mitigations for some of them.
Key-Compromise Impersonation
The DHKEM variants defined in this document are
vulnerable to key-compromise impersonation attacks BJM97,
which means that sender authentication cannot be expected to hold in the
Auth mode if the recipient private key skR
is compromised, and in the
AuthPSK mode if the pre-shared key and the recipient private key skR
are
both compromised. NaClās box
interface NaCl has the same issue. At
the same time, this enables repudiability.
As shown by ABHKLR20, key-compromise impersonation attacks are generally possible on HPKE because KEM ciphertexts are not bound to HPKE messages. An adversary who knows a recipientās private key can decapsulate an observed KEM ciphertext, compute the key schedule, and encrypt an arbitrary message that the recipient will accept as coming from the original sender. Importantly, this is possible even with a KEM that is resistant to key-compromise impersonation attacks. As a result, mitigating this issue requires fundamental changes that are out-of-scope of this specification.
Applications that require resistance against key-compromise impersonation
SHOULD take extra steps to prevent this attack. One possibility is to
produce a digital signature over (enc, ct)
tuples using a senderās
private key ā where ct
is an AEAD ciphertext produced by the single-shot
or multi-shot API, and enc
the corresponding KEM encapsulated key.
Given these properties, pre-shared keys strengthen both the authentication and the secrecy properties in certain adversary models. One particular example in which this can be useful is a hybrid quantum setting: if a non-quantum-resistant KEM used with HPKE is broken by a quantum computer, the security properties are preserved through the use of a pre-shared key. As described in RFC8696 Section 7 this assumes that the pre-shared key has not been compromised.
Computational Analysis
It is shown in CS01 that a hybrid public-key encryption scheme of essentially the same form as the Base mode described here is IND-CCA2-secure as long as the underlying KEM and AEAD schemes are IND-CCA2-secure. Moreover, it is shown in HHK06 that IND-CCA2 security of the KEM and the data encapsulation mechanism are necessary conditions to achieve IND-CCA2 security for hybrid public-key encryption. The main difference between the scheme proposed in CS01 and the Base mode in this document (both named HPKE) is that we interpose some KDF calls between the KEM and the AEAD. Analyzing the HPKE Base mode instantiation in this document therefore requires verifying that the additional KDF calls do not cause the IND-CCA2 property to fail, as well as verifying the additional export key secrecy property.
Analysis of the PSK, Auth, and AuthPSK modes defined in this document additionally requires verifying the sender authentication property. While the PSK mode just adds supplementary keying material to the key schedule, the Auth and AuthPSK modes make use of a non-standard authenticated KEM construction. Generally, the authenticated modes of HPKE can be viewed and analyzed as flavors of signcryption SigncryptionDZ10.
A preliminary computational analysis of all HPKE modes has been done in HPKEAnalysis, indicating asymptotic security for the case where the KEM is DHKEM, the AEAD is any IND-CPA and INT-CTXT-secure scheme, and the DH group and KDF satisfy the following conditions:
- DH group: The gap Diffie-Hellman (GDH) problem is hard in the appropriate subgroup GAP.
Extract()
andExpand()
:Extract()
can be modeled as a random oracle.Expand()
can be modeled as a pseudorandom function, wherein the first argument is the key.
In particular, the KDFs and DH groups defined in this document (see kdf-ids and kem-ids) satisfy these properties when used as specified. The analysis in HPKEAnalysis demonstrates that under these constraints, HPKE continues to provide IND-CCA2 security, and provides the additional properties noted above. Also, the analysis confirms the expected properties hold under the different key compromise cases mentioned above. The analysis considers a sender that sends one message using the encryption context, and additionally exports two independent secrets using the secret export interface.
The table below summarizes the main results from HPKEAnalysis. N/A
means that a property does not apply for the given mode, whereas y
means
the given mode satisfies the property.
Variant | Message Sec. | Export Sec. | Sender Auth. |
---|---|---|---|
Base | y | y | N/A |
PSK | y | y | y |
Auth | y | y | y |
AuthPSK | y | y | y |
If non-DH-based KEMs are to be used with HPKE, further analysis will be necessary to prove their security. The results from CS01 provide some indication that any IND-CCA2-secure KEM will suffice here, but are not conclusive given the differences in the schemes.
A detailed computational analysis of HPKEās Auth mode single-shot
encryption API has been done in ABHKLR20.
The paper defines security notions for authenticated
KEMs and for authenticated public key encryption, using the outsider and
insider security terminology known from signcryption SigncryptionDZ10.
The analysis proves that DHKEMās AuthEncap()
/AuthDecap()
interface
fulfills these notions for all Diffie-Hellman groups specified in this document,
and indicates exact security bounds, under the assumption that the
gap Diffie-Hellman (GDH) problem is hard in the appropriate subgroup GAP,
and that HKDF can be modeled as a random oracle.
Further, ABHKLR20 proves composition theorems, showing that HPKEās
Auth mode fulfills the security notions of authenticated public key encryption
for all KDFs and AEAD schemes specified in this document, given any
authenticated KEM satisfying the previously defined security notions
for authenticated KEMs. The theorems assume that the KEM is perfectly correct;
they could easily be adapted to work with KEMs that have a non-zero but negligible
probability for decryption failure. The assumptions on the KDF are that Extract()
and Expand()
can be modeled as pseudorandom functions wherein the first
argument is the key, respectively. The assumption for the AEAD is
IND-CPA and IND-CTXT security.
In summary, the analysis in ABHKLR20 proves that the single-shot encryption API of HPKEās Auth mode satisfies the desired message confidentiality and sender authentication properties listed at the beginning of this section; it does not consider multiple messages, nor the secret export API.
Post-Quantum Security
All of CS01, HPKEAnalysis, and ABHKLR20 are premised on classical security models and assumptions, and do not consider adversaries capable of quantum computation. A full proof of post-quantum security would need to take appropriate security models and assumptions into account, in addition to simply using a post-quantum KEM. However, the composition theorems from ABHKLR20 for HPKEās Auth mode only make standard assumptions (i.e., no random oracle assumption) that are expected to hold against quantum adversaries (although with slightly worse bounds). Thus, these composition theorems, in combination with a post-quantum-secure authenticated KEM, guarantee the post-quantum security of HPKEās Auth mode.
In future work, the analysis from ABHKLR20 can be extended to cover HPKEās other modes and desired security properties. The hybrid quantum-resistance property described above, which is achieved by using the PSK or AuthPSK mode, is not proven in HPKEAnalysis because this analysis requires the random oracle model; in a quantum setting, this model needs adaption to, for example, the quantum random oracle model.
Pre-Shared Key Recommendations
In the PSK and AuthPSK modes, the PSK MUST have at least 32 bytes of
entropy and SHOULD be of length Nh
bytes or longer. Using a PSK longer than
32 bytes but shorter than Nh
bytes is permitted.
HPKE is specified to use HKDF as key derivation function. HKDF is not
designed to slow down dictionary attacks, see RFC5869. Thus, HPKEās
PSK mechanism is not suitable for use with a low-entropy password as the
PSK: in scenarios in which the adversary knows the KEM shared secret
shared_secret
and has access to an oracle that allows to distinguish between
a good and a wrong PSK, it can perform PSK-recovering attacks. This oracle
can be the decryption operation on a captured HPKE ciphertext or any other
recipient behavior which is observably different when using a wrong PSK.
The adversary knows the KEM shared secret shared_secret
if it knows all
KEM private keys of one participant. In the PSK mode this is trivially
the case if the adversary acts as sender.
To recover a lower entropy PSK, an attacker in this scenario can trivially
perform a dictionary attack. Given a set S
of possible PSK values, the
attacker generates an HPKE ciphertext for each value in S
, and submits
the resulting ciphertexts to the oracle to learn which PSK is being used by
the recipient. Further, because HPKE uses AEAD schemes that are not key-committing,
an attacker can mount a partitioning oracle attack LGR20 which can recover
the PSK from a set of S
possible PSK values, with |S| = m*k, in roughly
m + log k queries to the oracle using ciphertexts of length proportional to
k, the maximum message length in blocks. (Applying the multi-collision algorithm from
LGR20 requires a small adaptation to the algorithm wherein the appropriate nonce
is computed for each candidate key. This modification adds one call to HKDF per key.
The number of partitioning oracle queries remains unchanged.) As a result, the PSK
must therefore be chosen with sufficient entropy so that m + log k is prohibitive for
attackers (e.g., 2^128). Future specifications can define new AEAD algorithms which
are key-committing.
Domain Separation
HPKE allows combining a DHKEM variant DHKEM(Group, KDF')
and a KDF
such that both KDFs are instantiated by the same KDF. By design, the
calls to Extract()
and Expand()
inside DHKEM and the remainder of
HPKE use separate input domains. This justifies modeling them as
independent functions even if instantiated by the same KDF.
This domain separation between DHKEM and the remainder of HPKE is achieved by
the suite_id
values in LabeledExtract()
and LabeledExpand()
:
The values used (KEM...
in DHKEM and HPKE...
in the remainder of HPKE)
are prefix-free (a set is prefix-free if no element is a prefix of
another within the set).
Future KEM instantiations MUST ensure, should Extract()
and
Expand()
be used internally, that they can be modeled as functions
independent from the invocations of Extract()
and Expand()
in the
remainder of HPKE. One way to ensure this is by using LabeledExtract()
and LabeledExpand()
with a suite_id
as defined in [base-crypto],
which will ensure input domain separation as outlined above.
Particular attention needs to
be paid if the KEM directly invokes functions that are used internally
in HPKEās Extract()
or Expand()
, such as Hash()
and HMAC()
in the case of HKDF.
It MUST be ensured that inputs to these invocations cannot collide with
inputs to the internal invocations of these functions inside Extract()
or
Expand()
. In HPKEās KeySchedule()
this is avoided by using Extract()
instead of
Hash()
on the arbitrary-length inputs info
and psk_id
.
The string literal āHPKE-v1ā used in LabeledExtract()
and LabeledExpand()
ensures that any secrets derived in HPKE are bound to the schemeās name
and version, even when possibly derived from the same Diffie-Hellman or
KEM shared secret as in another scheme or version.
Application Embedding and Non-Goals
HPKE is designed to be a fairly low-level mechanism. As a result, it assumes that certain properties are provided by the application in which HPKE is embedded, and leaves certain security properties to be provided by other mechanisms. Otherwise said, certain properties are out-of-scope for HPKE.
Message Order and Message Loss
The primary requirement that HPKE imposes on applications is the requirement
that ciphertexts MUST be presented to ContextR.Open()
in the same order in
which they were generated by ContextS.Seal()
. When the single-shot API is
used (see [single-shot-apis]), this is trivially true (since there is only
ever one ciphertext. Applications that allow for multiple invocations of
Open()
/ Seal()
on the same context MUST enforce the ordering property
described above.
Ordering requirements of this character are usually fulfilled by providing a
sequence number in the framing of encrypted messages. Whatever information is
used to determine the ordering of HPKE-encrypted messages SHOULD be included in
the AAD passed to ContextS.Seal()
and ContextR.Open()
. The specifics of
this scheme are up to the application.
HPKE is not tolerant of lost messages. Applications MUST be able to detect when a message has been lost. When an unrecoverable loss is detected, the application MUST discard any associated HPKE context.
Downgrade Prevention
HPKE assumes that the sender and recipient agree on what algorithms to use. Depending on how these algorithms are negotiated, it may be possible for an intermediary to force the two parties to use suboptimal algorithms.
Replay Protection
The requirement that ciphertexts be presented to the ContextR.Open()
function
in the same order they were generated by ContextS.Seal()
provides a degree of
replay protection within a stream of ciphertexts resulting from a given context.
HPKE provides no other replay protection.
Forward Secrecy
HPKE ciphertexts are not forward secret with respect to recipient compromise in any mode. This means that compromise of long-term recipient secrets allows an attacker to decrypt past ciphertexts encrypted under said secrets. This is because only long-term secrets are used on the side of the recipient.
HPKE ciphertexts are forward secret with respect to sender compromise in all modes. This is because ephemeral randomness is used on the senderās side, which is supposed to be erased directly after computation of the KEM shared secret and ciphertext.
Bad Ephemeral Randomness
If the randomness used for KEM encapsulation is bad ā i.e. of low entropy or compromised because of a broken or subverted random number generator ā the confidentiality guarantees of HPKE degrade significantly. In Base mode, confidentiality guarantees can be lost completely; in the other modes, at least forward secrecy with respect to sender compromise can be lost completely.
Such a situation could also lead to the reuse of the same KEM shared secret
and thus to the reuse of same key-nonce pairs for the AEAD.
The AEADs specified in this document are not secure
in case of nonce reuse. This attack vector is particularly relevant in
authenticated modes because knowledge of the ephemeral randomness is not
enough to derive shared_secret
in these modes.
One way for applications to mitigate the impacts of bad ephemeral randomness is to combine ephemeral randomness with a local long-term secret that has been generated securely, as described in RFC8937.
Hiding Plaintext Length
AEAD ciphertexts produced by HPKE do not hide the plaintext length. Applications requiring this level of privacy should use a suitable padding mechanism. See tls-esni and RFC8467 for examples of protocol-specific padding policies.
Bidirectional Encryption
HPKE encryption is unidirectional from sender to recipient. Applications that require bidirectional encryption can derive necessary keying material with the Secret Export interface. The type and length of such keying material depends on the application use case.
As an example, if an application needs AEAD encryption from recipient to sender, it can derive a key and nonce from the corresponding HPKE context as follows:
key = context.Export("response key", Nk)
nonce = context.Export("response nonce", Nn)
In this example, the length of each secret is based on the AEAD algorithm used for the corresponding HPKE context.
Note that HPKEās limitations with regard to sender authentication become limits on recipient authentication in this context. In particular, in the Base mode, there is no authentication of the remote party at all. Even in the Auth mode, where the remote party has proven that they hold a specific private key, this authentication is still subject to Key-Compromise Impersonation, as discussed in kci.
Metadata Protection
The authenticated modes of HPKE (PSK, Auth, AuthPSK) require that the recipient
know what key material to use for the sender. This can be signaled in
applications by sending the PSK ID (psk_id
above) and/or the senderās public
key (pkS
). However, these values themselves might be considered sensitive,
since in a given application context, they might identify the sender.
An application that wishes to protect these metadata values without requiring
further provisioning of keys can use an additional instance of HPKE, using the
unauthenticated Base mode. Where the application might have sent (psk_id, pkS, enc, ciphertext)
before, it would now send (enc2, ciphertext2, enc, ciphertext)
,
where (enc2, ciphertext2)
represent the encryption of the psk_id
and pkS
values.
The cost of this approach is an additional KEM operation each for the sender and the recipient. A potential lower-cost approach (involving only symmetric operations) would be available if the nonce-protection schemes in BNT19 could be extended to cover other metadata. However, this construction would require further analysis.
hacspec implementation considerations
When defining HPKE in hacspec there are a number of considerations that have an impact on the way the code looks.
The hacspec code is as close to the RFC pseudocode as possible. But some changes are necessary.
Randomness
hacspec does not allow to draw randomness. It is therefore necessary to pass in randomness every time it is needed.
This approach is pretty close to the way this would be implemented in native Rust where a random-number generator is passed in and used to generate randomness.
Configuration Parameters
The HPKE RFC makes most of the configuration implicit to the functions rather than passing the algorithm identifiers around. Because the hacspec implementation has to know which algorithm to pick, this is of course not possible here.
HPKE hacspec functions take either an HPKEConfig
object with all algorithms
in it or the specific algorithm identifier needed for the operation.
Naming
The HPKE RFC uses, in some cases, names that are impossible to use in hacspec because they are keywords or contain illegal characters. Further does hacspec not support member functions.
We therefore replace .
in function calls such as Context.Export
with an underscore,
i.e. write Context_Export
.
Keywords such as open
are replaced with a semantically equivalent, i.e. HpkeOpen
.
Secret bytes
hacspec has the notion of secret integers that canāt be used for certain operations and should enforce secret-independent computation time.
For simplicity the hacspec HPKE implementation uses secret bytes everywhere even if not necessary, e.g. for cipher texts.
Errors
While the RFC defines a set of errors it does not always define which errors
are raised.
For example, it leaves open whether implementations convert errors from the
Diffie-Hellman operations into KEM errors (EncapError
/DecapError
) or not.
With the specific implementation in hacspec here the errors are clearly defined.
Structs
Enums
A one-byte value indicating the HPKE mode, defined in the following table.
Functions
Compute Nonce
Stateful open.
Encryption and Decryption
Secret Export
Decryption
Encryption
Increment Sequence
Creating the Encryption Context
āsingle-shotā secret export receiver
āsingle-shotā secret export sender
Authentication using both a PSK and an Asymmetric Key - Receiver
Authentication using both a PSK and an Asymmetric Key - Sender
Authentication using an Asymmetric Key - Receiver
Authentication using an Asymmetric Key - Sender
Encryption to a Public Key - Receiver
Encryption to a Public Key - Sender
Authentication using a Pre-Shared Key - Receiver
Authentication using a Pre-Shared Key - Sender
Creating the Encryption Context