Hybrid Public Key Encryption (HPKE) suite combining a KEM, KDF, and AEAD.
Implements an authenticated encryption encapsulation format that combines a semi-static asymmetric key exchange with a symmetric cipher. This was originally defined in an Informational document on the IRTF stream as RFC 9180 and is now being republished as a Standards Track document of the IETF as draft-ietf-hpke-hpke.
HPKE provides a variant of public key encryption for arbitrary-sized plaintexts using a recipient public key. It supports two modes:
- Base mode: Encryption to a public key without sender authentication
- PSK mode: Encryption with pre-shared key authentication
The cipher suite consists of:
- KEM: Key Encapsulation Mechanism for establishing shared secrets
- KDF: Key Derivation Function for deriving symmetric keys
- AEAD: Authenticated Encryption with Additional Data for encryption
new CipherSuite(
KEM,KDF,AEAD):CipherSuite
Creates a new HPKE cipher suite by combining a Key Encapsulation Mechanism (KEM), Key Derivation Function (KDF), and an Authenticated Encryption with Associated Data (AEAD) algorithm.
A cipher suite defines the complete cryptographic configuration for HPKE operations. The choice of algorithms affects security properties, performance, and compatibility across different platforms and runtimes.
| Parameter | Type | Description |
|---|---|---|
KEM |
KEMFactory |
KEM implementation factory. Must return an object conforming to the KEM interface. |
KDF |
KDFFactory |
KDF implementation factory. Must return an object conforming to the KDF interface. |
AEAD |
AEADFactory |
AEAD implementation factory. Must return an object conforming to the AEAD interface. |
CipherSuite
Traditional algorithms
import * as HPKE from 'hpke'
const suite: HPKE.CipherSuite = new HPKE.CipherSuite(
HPKE.KEM_DHKEM_P256_HKDF_SHA256,
HPKE.KDF_HKDF_SHA256,
HPKE.AEAD_AES_128_GCM,
)Hybrid post-quantum/traditional (PQ/T) KEM
import * as HPKE from 'hpke'
const suite: HPKE.CipherSuite = new HPKE.CipherSuite(
HPKE.KEM_MLKEM768_X25519,
HPKE.KDF_SHAKE256,
HPKE.AEAD_ChaCha20Poly1305,
)Post-quantum (PQ) KEM
import * as HPKE from 'hpke'
const suite: HPKE.CipherSuite = new HPKE.CipherSuite(
HPKE.KEM_ML_KEM_768,
HPKE.KDF_SHAKE256,
HPKE.AEAD_ChaCha20Poly1305,
)SetupRecipient(
privateKey,encapsulatedSecret,options?):Promise<RecipientContext>
Establishes a recipient decryption context.
Creates a context that can be used to decrypt multiple messages from the same sender.
Mode selection:
- If the options
pskandpskIdare omitted: Base mode (unauthenticated) - If the options
pskandpskIdare provided: PSK mode (authenticated with pre-shared key)
| Parameter | Type | Description |
|---|---|---|
privateKey |
KeyPair ∣ Key |
Recipient's private key or key pair |
encapsulatedSecret |
Uint8Array |
Encapsulated secret from the sender |
options? |
Options | |
options.info? |
Uint8Array |
Application-supplied information |
options.psk? |
Uint8Array |
Pre-shared key (for PSK mode) |
options.pskId? |
Uint8Array |
Pre-shared key identifier (for PSK mode) |
Promise<RecipientContext>
A Promise that resolves to the recipient context.
let suite!: HPKE.CipherSuite
let privateKey!: HPKE.Key | HPKE.KeyPair
// ... receive encapsulatedSecret from sender
let encapsulatedSecret!: Uint8Array
const ctx: HPKE.RecipientContext = await suite.SetupRecipient(
privateKey,
encapsulatedSecret,
)
// ... receive messages from sender
let aad1!: Uint8Array | undefined
let ct1!: Uint8Array
const pt1: Uint8Array = await ctx.Open(ct1, aad1)
let aad2!: Uint8Array | undefined
let ct2!: Uint8Array
const pt2: Uint8Array = await ctx.Open(ct2, aad2)SetupSender(
publicKey,options?):Promise<{ctx:SenderContext;encapsulatedSecret:Uint8Array; }>
Establishes a sender encryption context.
Creates a context that can be used to encrypt multiple messages to the same recipient, amortizing the cost of the public key operations.
Mode selection:
- If the options
pskandpskIdare omitted: Base mode (unauthenticated) - If the options
pskandpskIdare provided: PSK mode (authenticated with pre-shared key)
The returned context maintains a sequence number that increments with each encryption, ensuring nonce uniqueness.
| Parameter | Type | Description |
|---|---|---|
publicKey |
Key |
Recipient's public key |
options? |
Options | |
options.info? |
Uint8Array |
Application-supplied information |
options.psk? |
Uint8Array |
Pre-shared key (for PSK modes) |
options.pskId? |
Uint8Array |
Pre-shared key identifier (for PSK modes) |
Promise<{ ctx: SenderContext; encapsulatedSecret: Uint8Array; }>
A Promise that resolves to an object containing the encapsulated secret and the sender
context (ctx). The encapsulated secret is Nenc bytes.
let suite!: HPKE.CipherSuite
let publicKey!: HPKE.Key // recipient's public key
const { encapsulatedSecret, ctx } = await suite.SetupSender(publicKey)
// Encrypt multiple messages with the same context
const aad1: Uint8Array = new TextEncoder().encode('message 1 aad')
const pt1: Uint8Array = new TextEncoder().encode('First message')
const ct1: Uint8Array = await ctx.Seal(pt1, aad1)
const aad2: Uint8Array = new TextEncoder().encode('message 2 aad')
const pt2: Uint8Array = new TextEncoder().encode('Second message')
const ct2: Uint8Array = await ctx.Seal(pt2, aad2)DeriveKeyPair(
ikm,extractable?):Promise<KeyPair>
Deterministically derives a key pair for this CipherSuite's KEM from input keying material. By default, private keys are derived as non-extractable (their value cannot be exported).
Caution
Input keying material must not be reused elsewhere, particularly not with DeriveKeyPair() of
a different KEM. Re-use across different KEMs could leak information about the private key.
Caution
Input keying material should be generated from a cryptographically secure random source or derived from high-entropy secret material.
| Parameter | Type | Description |
|---|---|---|
ikm |
Uint8Array |
Input keying material (must be at least Nsk bytes) |
extractable? |
boolean |
Whether the derived key pair's private key should be extractable (e.g. by SerializePrivateKey) (default: false) |
Promise<KeyPair>
A Promise that resolves to the derived key pair.
let suite!: HPKE.CipherSuite
let ikm!: Uint8Array // ... previously serialized ikm of at least suite.KEM.Nsk length
const keyPair: HPKE.KeyPair = await suite.DeriveKeyPair(ikm)DeserializePrivateKey(
privateKey,extractable?):Promise<Key>
Deserializes a private key from bytes. By default, private keys are deserialized as non-extractable (their value cannot be exported).
| Parameter | Type | Description |
|---|---|---|
privateKey |
Uint8Array |
Serialized private key (must be exactly Nsk bytes) |
extractable? |
boolean |
Whether the deserialized private key should be extractable (e.g. by SerializePrivateKey) (default: false) |
Promise<Key>
A Promise that resolves to the deserialized private key.
let suite!: HPKE.CipherSuite
let serialized!: Uint8Array // ... previously serialized key of suite.KEM.Nsk length
const privateKey: HPKE.Key = await suite.DeserializePrivateKey(serialized)DeserializePublicKey(
publicKey):Promise<Key>
Deserializes a public key from bytes. Public keys are always deserialized as extractable (their value can be exported, e.g. by SerializePublicKey).
| Parameter | Type | Description |
|---|---|---|
publicKey |
Uint8Array |
Serialized public key (must be exactly Npk bytes) |
Promise<Key>
A Promise that resolves to the deserialized public key.
let suite!: HPKE.CipherSuite
let serialized!: Uint8Array // ... previously serialized key of suite.KEM.Npk length
const publicKey: HPKE.Key = await suite.DeserializePublicKey(serialized)GenerateKeyPair(
extractable?):Promise<KeyPair>
Generates a random key pair for this CipherSuite. By default, private keys are generated as non-extractable (their value cannot be exported).
| Parameter | Type | Description |
|---|---|---|
extractable? |
boolean |
Whether the generated key pair's private key should be extractable (e.g. by SerializePrivateKey) (default: false) |
Promise<KeyPair>
A Promise that resolves to a generated key pair.
let suite!: HPKE.CipherSuite
const keyPair: HPKE.KeyPair = await suite.GenerateKeyPair()SerializePrivateKey(
privateKey):Promise<Uint8Array>
Serializes an extractable private key to bytes.
| Parameter | Type | Description |
|---|---|---|
privateKey |
Key |
Private key to serialize |
Promise<Uint8Array>
A Promise that resolves to the serialized private key.
let suite!: HPKE.CipherSuite
let privateKey!: HPKE.Key
const serialized: Uint8Array = await suite.SerializePrivateKey(privateKey)SerializePublicKey(
publicKey):Promise<Uint8Array>
Serializes a public key to bytes.
| Parameter | Type | Description |
|---|---|---|
publicKey |
Key |
Public key to serialize |
Promise<Uint8Array>
A Promise that resolves to the serialized public key.
let suite!: HPKE.CipherSuite
let publicKey!: HPKE.Key
const serialized: Uint8Array = await suite.SerializePublicKey(publicKey)Open(
privateKey,encapsulatedSecret,ciphertext,options?):Promise<Uint8Array>
Single-shot API for decrypting a single message.
It combines context setup and decryption in one call.
Mode selection:
- If the options
pskandpskIdare omitted: Base mode (unauthenticated) - If the options
pskandpskIdare provided: PSK mode (authenticated with pre-shared key)
| Parameter | Type | Description |
|---|---|---|
privateKey |
KeyPair ∣ Key |
Recipient's private key or key pair |
encapsulatedSecret |
Uint8Array |
Encapsulated secret from the sender |
ciphertext |
Uint8Array |
Ciphertext to decrypt |
options? |
Options | |
options.aad? |
Uint8Array |
Additional authenticated data |
options.info? |
Uint8Array |
Application-supplied information |
options.psk? |
Uint8Array |
Pre-shared key (for PSK mode) |
options.pskId? |
Uint8Array |
Pre-shared key identifier (for PSK mode) |
Promise<Uint8Array>
A Promise that resolves to the decrypted plaintext.
let suite!: HPKE.CipherSuite
let privateKey!: HPKE.Key | HPKE.KeyPair
// ... receive encapsulatedSecret, ciphertext from sender
let encapsulatedSecret!: Uint8Array
let ciphertext!: Uint8Array
const plaintext: Uint8Array = await suite.Open(privateKey, encapsulatedSecret, ciphertext)ReceiveExport(
privateKey,encapsulatedSecret,exporterContext,length,options?):Promise<Uint8Array>
Single-shot API for receiving an exported secret.
It combines context setup and secret export in one call.
| Parameter | Type | Description |
|---|---|---|
privateKey |
KeyPair ∣ Key |
Recipient's private key or key pair |
encapsulatedSecret |
Uint8Array |
Encapsulated secret from the sender |
exporterContext |
Uint8Array |
Context of the export operation |
length |
number |
Desired length of exported secret in bytes |
options? |
Options | |
options.info? |
Uint8Array |
Application-supplied information |
options.psk? |
Uint8Array |
Pre-shared key (for PSK mode) |
options.pskId? |
Uint8Array |
Pre-shared key identifier (for PSK mode) |
Promise<Uint8Array>
A Promise that resolves to the exported secret.
let suite!: HPKE.CipherSuite
let privateKey!: HPKE.Key | HPKE.KeyPair
const exporterContext: Uint8Array = new TextEncoder().encode('exporter context')
// ... receive encapsulatedSecret from sender
let encapsulatedSecret!: Uint8Array
const exported: Uint8Array = await suite.ReceiveExport(
privateKey,
encapsulatedSecret,
exporterContext,
32,
)Seal(
publicKey,plaintext,options?):Promise<{ciphertext:Uint8Array;encapsulatedSecret:Uint8Array; }>
Single-shot API for encrypting a single message. It combines context setup and encryption in one call.
Mode selection:
- If the options
pskandpskIdare omitted: Base mode (unauthenticated) - If the options
pskandpskIdare provided: PSK mode (authenticated with pre-shared key)
| Parameter | Type | Description |
|---|---|---|
publicKey |
Key |
Recipient's public key |
plaintext |
Uint8Array |
Plaintext to encrypt |
options? |
Options | |
options.aad? |
Uint8Array |
Additional authenticated data passed to the AEAD |
options.info? |
Uint8Array |
Application-supplied information |
options.psk? |
Uint8Array |
Pre-shared key (for PSK modes) |
options.pskId? |
Uint8Array |
Pre-shared key identifier (for PSK modes) |
Promise<{ ciphertext: Uint8Array; encapsulatedSecret: Uint8Array; }>
A Promise that resolves to an object containing the encapsulated secret and ciphertext. The ciphertext is Nt bytes longer than the plaintext. The encapsulated secret is Nenc bytes.
let suite!: HPKE.CipherSuite
let publicKey!: HPKE.Key // recipient's public key
const plaintext: Uint8Array = new TextEncoder().encode('Hello, World!')
const { encapsulatedSecret, ciphertext } = await suite.Seal(publicKey, plaintext)SendExport(
publicKey,exporterContext,length,options?):Promise<{encapsulatedSecret:Uint8Array;exportedSecret:Uint8Array; }>
Single-shot API for deriving a secret known only to sender and recipient.
It combines context setup and secret export in one call.
The exported secret is indistinguishable from a uniformly random bitstring of equal length.
| Parameter | Type | Description |
|---|---|---|
publicKey |
Key |
Recipient's public key |
exporterContext |
Uint8Array |
Context of the export operation |
length |
number |
Desired length of exported secret in bytes |
options? |
Options | |
options.info? |
Uint8Array |
Application-supplied information |
options.psk? |
Uint8Array |
Pre-shared key (for PSK modes) |
options.pskId? |
Uint8Array |
Pre-shared key identifier (for PSK modes) |
Promise<{ encapsulatedSecret: Uint8Array; exportedSecret: Uint8Array; }>
A Promise that resolves to an object containing the encapsulated secret and the exported secret.
let suite!: HPKE.CipherSuite
let publicKey!: HPKE.Key // recipient's public key
const exporterContext: Uint8Array = new TextEncoder().encode('exporter context')
const { encapsulatedSecret, exportedSecret } = await suite.SendExport(
publicKey,
exporterContext,
32,
)get AEAD():
object
Provides read-only access to this suite's AEAD identifier, name, and other attributes.
An object with this suite's Authenticated Encryption with Associated Data (AEAD) cipher properties.
id:
number
The identifier of this suite's AEAD
name:
string
The name of this suite's AEAD
Nk:
number
The length in bytes of a key for this suite's AEAD
Nn:
number
The length in bytes of a nonce for this suite's AEAD
Nt:
number
The length in bytes of an authentication tag for this suite's AEAD
get KDF():
object
Provides read-only access to this suite's KDF identifier, name, and other attributes.
An object with this suite's Key Derivation Function (KDF) properties.
id:
number
The identifier of this suite's KDF
name:
string
The name of this suite's KDF
Nh:
number
For one-stage KDF: The security strength of this suite's KDF, in bytes.
For two-stage KDF: The output size of this suite's KDF Extract() function in bytes.
stages:
1∣2
When 1, this suite's KDF is a one-stage (Derive) KDF.
When 2, this suite's KDF is a two-stage (Extract and Expand) KDF.
get KEM():
object
Provides read-only access to this suite's KEM identifier, name, and other attributes.
An object with this suite's Key Encapsulation Mechanism (KEM) properties.
id:
number
The identifier of this suite's KEM
name:
string
The name of this suite's KEM
Nenc:
number
The length in bytes of this suite's KEM produced encapsulated secret
Npk:
number
The length in bytes of this suite's KEM public key
Nsecret:
number
The length in bytes of this suite's KEM produced shared secret
Nsk:
number
The length in bytes of this suite's KEM private key