Class HPKEParameterSpec

java.lang.Object
javax.crypto.spec.HPKEParameterSpec
All Implemented Interfaces:
AlgorithmParameterSpec

public final class HPKEParameterSpec extends Object implements AlgorithmParameterSpec
This immutable class specifies the set of parameters used with a Cipher for the Hybrid Public Key Encryption (HPKE) algorithm. HPKE is a public key encryption scheme for encrypting arbitrary-sized plaintexts with a recipient's public key. It combines a key encapsulation mechanism (KEM), a key derivation function (KDF), and an authenticated encryption with additional data (AEAD) cipher.

The standard algorithm name for the cipher is "HPKE". Unlike most other ciphers, HPKE is not expressed as a transformation string of the form "algorithm/mode/padding". Therefore, the argument to Cipher.getInstance must be the single algorithm name "HPKE".

In HPKE, the sender's Cipher is always initialized with the recipient's public key in encrypt mode, while the recipient's Cipher object is initialized with its own private key in decrypt mode.

An HPKEParameterSpec object must be provided at HPKE cipher initialization.

The of(int, int, int) static method creates an HPKEParameterSpec instance with the specified KEM, KDF, and AEAD algorithm identifiers. The terms "KEM algorithm identifiers", "KDF algorithm identifiers", and "AEAD algorithm identifiers" refer to their respective numeric values (specifically, kem_id, kdf_id, and aead_id) as defined in Section 7 of RFC 9180 and the IANA HPKE page.

Once an HPKEParameterSpec object is created, additional methods are available to generate new HPKEParameterSpec objects with different features:

  • Application-supplied information can be provided using the withInfo(byte[]) method by both sides.
  • To authenticate using a pre-shared key (mode_psk), the pre-shared key and its identifier must be provided using the withPsk(SecretKey, byte[]) method by both sides.
  • To authenticate using an asymmetric key (mode_auth), the asymmetric keys must be provided using the withAuthKey(AsymmetricKey) method. Precisely, the sender must call this method with its own private key and the recipient must call it with the sender's public key.
  • To authenticate using both a PSK and an asymmetric key (mode_auth_psk), both withAuthKey(AsymmetricKey) and withPsk(SecretKey, byte[]) methods must be called as described above.
  • In HPKE, a shared secret is negotiated during the KEM step and a key encapsulation message must be transmitted from the sender to the recipient so that the recipient can recover this shared secret. On the sender side, after the cipher is initialized, the key encapsulation message can be retrieved using the Cipher.getIV() method. On the recipient side, this message must be supplied as part of an HPKEParameterSpec object obtained from the withEncapsulation(byte[]) method.
For successful interoperability, both sides need to have identical algorithm identifiers, and supply identical info, psk, and psk_id or matching authentication keys if provided. For details about HPKE modes, refer to Section 5 of RFC 9180.

If an HPKE cipher is initialized without parameters, an InvalidKeyException is thrown.

At HPKE cipher initialization, if no HPKE implementation supports the provided key type, an InvalidKeyException is thrown. If the provided HPKEParameterSpec is not accepted by any HPKE implementation, an InvalidAlgorithmParameterException is thrown by the init method. The following are cases of invalid parameters:

  • An algorithm identifier is unsupported or does not match the provided key type.
  • The key encapsulation message is not provided on the recipient side.
  • An attempt to use withAuthKey(key) is made with an incompatible key.
  • An attempt to use withAuthKey(key) is made but mode_auth or mode_auth_psk is not supported by the KEM used.
After initialization, both the sender and recipient can process multiple messages in sequence with repeated doFinal calls, optionally preceded by one or more updateAAD and update. Each doFinal performs a complete HPKE encryption or decryption operation using a distinct IV derived from an internal sequence counter, as specified in Section 5.2 of RFC 9180. On the recipient side, each doFinal call must correspond to exactly one complete ciphertext, and the number and order of calls must match those on the sender side. This differs from the direct use of an AEAD cipher, where the caller must provide a fresh IV and reinitialize the cipher for each message. By managing IVs internally, HPKE allows a single initialization to support multiple messages while still ensuring IV uniqueness and preserving AEAD security guarantees.

This example shows a sender and a recipient using HPKE to securely exchange messages with an X25519 key pair.

// Recipient key pair generation
KeyPairGenerator g = KeyPairGenerator.getInstance("X25519");
KeyPair kp = g.generateKeyPair();

// The HPKE sender cipher is initialized with the recipient's public
// key and an HPKEParameterSpec using specified algorithm identifiers
// and application-supplied info.
Cipher senderCipher = Cipher.getInstance("HPKE");
HPKEParameterSpec ps = HPKEParameterSpec.of(
                HPKEParameterSpec.KEM_DHKEM_X25519_HKDF_SHA256,
                HPKEParameterSpec.KDF_HKDF_SHA256,
                HPKEParameterSpec.AEAD_AES_128_GCM)
        .withInfo("app_info".getBytes(StandardCharsets.UTF_8));
senderCipher.init(Cipher.ENCRYPT_MODE, kp.getPublic(), ps);

// Retrieve the key encapsulation message (from the KEM step) from
// the sender.
byte[] kemEncap = senderCipher.getIV();

// The HPKE recipient cipher is initialized with its own private key,
// an HPKEParameterSpec using the same algorithm identifiers as used by
// the sender, and the key encapsulation message from the sender.
Cipher recipientCipher = Cipher.getInstance("HPKE");
HPKEParameterSpec pr = HPKEParameterSpec.of(
                HPKEParameterSpec.KEM_DHKEM_X25519_HKDF_SHA256,
                HPKEParameterSpec.KDF_HKDF_SHA256,
                HPKEParameterSpec.AEAD_AES_128_GCM)
        .withInfo("app_info".getBytes(StandardCharsets.UTF_8))
        .withEncapsulation(kemEncap);
recipientCipher.init(Cipher.DECRYPT_MODE, kp.getPrivate(), pr);

// Encryption and decryption
byte[] msg = "Hello World".getBytes(StandardCharsets.UTF_8);
byte[] ct = senderCipher.doFinal(msg);
byte[] pt = recipientCipher.doFinal(ct);

assert Arrays.equals(msg, pt);
Implementation Note:
This class defines constants for some of the standard algorithm identifiers such as KEM_DHKEM_P_256_HKDF_SHA256, KDF_HKDF_SHA256, and AEAD_AES_128_GCM. An HPKE Cipher implementation may support all, some, or none of the algorithm identifiers defined here. An implementation may also support additional identifiers not listed here, including private or experimental values.
Since:
26
  • Field Details

  • Method Details

    • of

      public static HPKEParameterSpec of(int kem_id, int kdf_id, int aead_id)
      A factory method to create a new HPKEParameterSpec object with specified KEM, KDF, and AEAD algorithm identifiers in mode_base mode with an empty info.
      Parameters:
      kem_id - algorithm identifier for KEM, must be between 0 and 65535 (inclusive)
      kdf_id - algorithm identifier for KDF, must be between 0 and 65535 (inclusive)
      aead_id - algorithm identifier for AEAD, must be between 0 and 65535 (inclusive)
      Returns:
      a new HPKEParameterSpec object
      Throws:
      IllegalArgumentException - if any input value is out of range (must be between 0 and 65535, inclusive).
    • withInfo

      public HPKEParameterSpec withInfo(byte[] info)
      Creates a new HPKEParameterSpec object with the specified info value.

      For interoperability, RFC 9180 Section 7.2.1 recommends limiting this value to a maximum of 64 bytes.

      Parameters:
      info - application-supplied information. The contents of the array are copied to protect against subsequent modification.
      Returns:
      a new HPKEParameterSpec object
      Throws:
      NullPointerException - if info is null
      IllegalArgumentException - if info is empty.
    • withPsk

      public HPKEParameterSpec withPsk(SecretKey psk, byte[] psk_id)
      Creates a new HPKEParameterSpec object with the specified psk and psk_id values.

      RFC 9180 Section 5.1.2 requires the PSK MUST have at least 32 bytes of entropy. For interoperability, RFC 9180 Section 7.2.1 recommends limiting the key size and identifier length to a maximum of 64 bytes.

      Parameters:
      psk - pre-shared key
      psk_id - identifier for PSK. The contents of the array are copied to protect against subsequent modification.
      Returns:
      a new HPKEParameterSpec object
      Throws:
      NullPointerException - if psk or psk_id is null
      IllegalArgumentException - if psk is shorter than 32 bytes or psk_id is empty
    • withEncapsulation

      public HPKEParameterSpec withEncapsulation(byte[] encapsulation)
      Creates a new HPKEParameterSpec object with the specified key encapsulation message value that will be used by the recipient.
      Parameters:
      encapsulation - the key encapsulation message. The contents of the array are copied to protect against subsequent modification.
      Returns:
      a new HPKEParameterSpec object
      Throws:
      NullPointerException - if encapsulation is null
    • withAuthKey

      public HPKEParameterSpec withAuthKey(AsymmetricKey kS)
      Creates a new HPKEParameterSpec object with the specified authentication key value.

      Note: this method does not check whether the KEM supports mode_auth or mode_auth_psk. If the resulting object is used to initialize an HPKE cipher with an unsupported mode, an InvalidAlgorithmParameterException will be thrown at that time.

      Parameters:
      kS - the authentication key
      Returns:
      a new HPKEParameterSpec object
      Throws:
      NullPointerException - if kS is null
    • kem_id

      public int kem_id()
      Returns the algorithm identifier for KEM .
      Returns:
      the algorithm identifier for KEM
    • kdf_id

      public int kdf_id()
      Returns the algorithm identifier for KDF .
      Returns:
      the algorithm identifier for KDF
    • aead_id

      public int aead_id()
      Returns the algorithm identifier for AEAD .
      Returns:
      the algorithm identifier for AEAD
    • info

      public byte[] info()
      Returns a copy of the application-supplied information, empty if none.
      Returns:
      a copy of the application-supplied information, empty if none
    • psk

      public SecretKey psk()
      Returns pre-shared key, null if none.
      Returns:
      pre-shared key, null if none
    • psk_id

      public byte[] psk_id()
      Returns a copy of the identifier for PSK, empty if none.
      Returns:
      a copy of the identifier for PSK, empty if none
    • authKey

      public AsymmetricKey authKey()
      Returns the key for authentication, null if none.
      Returns:
      the key for authentication, null if none
    • encapsulation

      public byte[] encapsulation()
      Returns a copy of the key encapsulation message, null if none.
      Returns:
      a copy of the key encapsulation message, null if none
    • toString

      public String toString()
      Description copied from class: Object
      Returns a string representation of the object. Satisfying this method's contract implies a non-null result must be returned.
      Overrides:
      toString in class Object
      Returns:
      a string representation of the object