ML-KEM Programming Guide

Abbreviations and Acronyms

Term Definition
API Application Programming Interface
KEM Key Encapsulation Mechanism
ML-DSA Module-Lattice Key Encapsulation Algorithm
PKCS Public Key Cryptography Standards

References

Document Author Title
FIPS 203 NIST Module-Lattice-Based Key-Encapsulation Mechanism Standard (nist.gov)
  OASIS https://groups.oasis-open.org/higherlogic/ws/public/download/72453/pkcs11-spec-v3.2-wd08.docx

Overview

This document discusses how the ML-KEM API, incorporated into the Luna HSM starting with firmware version 7.9.0, is made available to applications.

ML-KEM/Kyber services are supplied through mechanisms, objects and attributes of the Cryptoki interface.

NOTE   Hybrid key agreement combines the secret from a legacy method (e.g. DH or RSA Transport) with the secret produced by ML-KEM to make the shared session symmetric key. That is outside the scope of this document.

If applications need to do Hybrid key derive then they must support that themselves, outside the HSM. This means that such applications will need to operate the HSM while it is not in FIPS approved configuration (formerly FIPS mode).

Refer to the NIST FIPS 203 standard publication for the definitive description of a KEM.

The shared secret created by the ML_KEM encryption and decryption is a 32 byte value which may to be used as a symmetric key (as it is randomly generated).

The Encapsulation and Decapsulation operations take a template specifying the attributes of the shared secret key object to be created.

The CKA_KEY_TYPE and CKA_VALUE_LENGTH may be used to create a symmetric key with a value length less than or equal 32 bytes.

ML-KEM Key Types and Sizes

ML-KEM keys may be generated with different sizes to balance size and performance.

CKA_KEY_TYPE CKA_PARAM_SET Public Key Private Key Cipher Shared Secret

CKA_KEY_TYPE CKA_PARAM_SET Public Key Private Key Cipher Shared Secret
CKK_ML_KEM CKP_ML_KEM_512 800 1632 768 32
CKK_ML_KEM CKP_ML_KEM_768 1184 2400 1088 32
CKK_ML_KEM CKP_ML_KEM_1024 1568 3168 1568 32

Lengths of keys and other values depend on the strength that is chosen.

ML-KEM Private Key Format

The decapsulation key dk has this format:

dk ← (dkPKE∥ek∥H(ek)∥z)

where:

>dk is the decapsulation key

>dkPEK is the low level decapsulation key

>ek is the encapsulation key (t || rho)

>H(ek) is a hash of the ek

>z is a random string used during implicit reject operation

A decapsulation key holds the value of the public key within it.

Public Keys

During the session establishment the public key value is passed from the party who did the key pair generation, to the party doing the encapsulation (and usually authenticated with an associated signature scheme).

The party who did the key pair generation does not use the public key object in the decapsulation operation. Instead, it uses the public key in the private key object.

Public keys should be validated before being used to encapsulate. Since public key objects need to be created before they can be used, validating them as the object is created precedes any use of the public key.

PKCS#8 style encoding of public keys is part of the PKCS#11 specification. Any private key and public key can provide a CKA_PUBLIC_KEY_INFO attribute, which (if present) holds a DER encoded public key. That is, an Algorithm OID and a public key value encoded together.

The C_CreateObject command recognizes either the CKA_VALUE or CKA_PUBLIC_KEY_INFO attributes as valid ways to create a public key object.

Key Cloning Backup and SKS

The ML-KEM keys are cloned during HA Key Cloning, which also enables backup (to compatible HSMs) with these keys.

Key Wrapping

ML-KEM Private keys may be represented in two forms.

1.Full: A collection of PKE keys, a hash and a random value = dkPKE∥ek∥H(ek)∥z

2.Seed: The Seeds that allows the Full representation to be re-generated; that is, two 32-byte random values

An HSM may internally store either (or both) form depending on performance/storage trade off.

Some applications specify the Seed form (i.e. ITEF).

The Luna HSM stores both Full and Seed forms in the Private key, in anticipation of PKCS#11 support for wrapping the Seed form. The Full form is always used for signing and the Seed form is used only for key wrapping/unwrapping.

Therefore, when cloning ML-KEM private keys, the full internal representation of the key is encoded and unwrapped into the target. That is, Seeds and Full components are cloned.

When wrapping an ML-KEM private key for export outside the Luna environment only the Seed format will be wrapped.

Wrapped Private Key Format PKCS#8

For wrapping ML-KEM private keys, the PKCS#8 scheme is used.

PKCS#8: Private-key information have ASN.1 type PrivateKeyInfo:

PrivateKeyInfo ::= SEQUENCE {
version                   Version,
privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
privateKey                PrivateKey,
attributes           [0]  IMPLICIT Attributes OPTIONAL }
Version ::= INTEGER
PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
PrivateKey ::= OCTET STRING
Attributes ::= SET OF Attribute
The fields of type PrivateKeyInfo have the following meanings:
version is the syntax version number, for compatibility with 
future revisions.  It is 0 for this version.
privateKeyAlgorithm identifies the private-key algorithm. 
See section below on CKA_PUBLIC_KEY_INFO attribute.
privateKey is an octet string whose contents are the value of the private key.  
The interpretation of the contents is defined in the registration of the private-key algorithm.  
For an ML-KEM private key the contents are the 64 byte ‘D|Z’ seed value (or potentially the expanded private key).
attributes is a set of attributes.  
These are the extended information that is encrypted along with the private-key information. ML-KEM attributes are absent.

See Internet X.509 Public Key Infrastructure - Algorithm Identifiers for Module-Lattice-Based Key-Encapsulation Mechanism (ML-KEM) (ietf.org)  for details on ML_KEM encoding.

Capabilities and Policies

The container configuration flags CONTAINER_CONFIG_PRIVATE_KEY_UNWRAPPING (see Allow private key unwrapping) and CONTAINER_CONFIG_PRIVATE_KEY_WRAPPING (see Allow private key wrapping)should be enabled as appropriate for wrapping or unwrapping of ML-KEM private keys.

The container configuration flags CONTAINER_CONFIG_SECRET_KEY_UNWRAPPING (see Allow secret key unwrapping) and CONTAINER_CONFIG_SECRET_KEY_WRAPPING (see Allow secret key wrapping) should be enabled as appropriate for decapsulation or encapsulation operations.

Multiple Use Keys

There is no requirement in the FIPS 203 specification that ML-KEM must be used only once.

Therefore, you can generate a key pair and use it to establish different session keys for multiple sessions.

PKI

For the initial implementation, no Public Key Certs certificate creation is performed.

Key cloning Protocol in PQC hybrid mode

ML_KEM algorithm is added to cloning protocol version 4 (CPv4), but not to CPv1 or 2.

PKCS#11 Status

During the Luna HSM development and testing window for the release of firmware version 7.9.0, official specifications were still in draft status. To provide customers with usable functionality with respect to C_EncapsulateKey and C_DecapsulateKey functions, we have Implemented proprietary CA_EncapsulateKey and CA_DecapsulateKey, and will revisit standard versions when the specification solidifies.

 

Regarding ITEF progress on PKCS#8 format for ML_KEM private/public keys, we proceeded on the assumption that draft 8 of the ITEF spec describing PKCS#8 format for private and public keys will become official without change.

The wrapping of ML_KEM and ML_DSA private key SEEDs is not specified and therefore not implemented until an official API is known.

Unwrapping is possible for SEED or Expanded private ML_KEM keys in the initial release.

PKCS#11 C_EncapsulateKey and C_DecapsulateKey

Draft specification 3.2 adds mechanisms plus C_EncapsulateKey and C_DecapsulateKey functions plus new key types and attribute for ML-KEM.

The CKM_ML_KEM mechanism can be used only with these new functions.

Pending the official C_EncapsulateKey when PKCS#11 3.2 is officially released, we (Thales) provide a proprietary version with CA_EncapsulateKey.

C_EncapsulateKey

CA_EncapsulateKey

CK_RV C_EncapsulateKey(
CK_SESSION_HANDLE hSession,		// IN session
CK_MECHANISM_PTR pMechanism,		// IN encap mechanism and parameters (if any)
CK_OBJECT_HANDLE hPublicKey,		// IN other parties’ public key
CK_ATTRIBUTE_PTR pTemplate,		// IN attributes of new symmetric key
CK_ULONG ulAttributeCount,		// IN
CK_BYTE_PTR pCiphertext, 		// OUT encrypted key or null
CK_ULONG_PTR pulCiphertextLen,	// OUT length prediction allowed
CK_OBJECT_HANDLE_PTR phKey);		// OUT handle of new key

The CKA_ENCAPSULATE attribute of the private key, which indicates whether the key supports encapsulation, MUST be CK_TRUE.

The new key has:

>the CKA_ALWAYS_SENSITIVE attribute set to CK_FALSE,

>the CKA_NEVER_EXTRACTABLE attribute set to CK_FALSE.

>the CKA_EXTRACTABLE set to the value of the input template with a default of CK_TRUE if not provided,

>the CKA_LOCAL attribute set to CKA_FALSE

If a call to C_EncapsulateKey cannot support the precise template supplied to it, it will fail and return without creating any key object.

The key object created by a successful call to C_EncapsulateKey has its CKA_LOCAL attribute set to CK_FALSE. In addition, the object created has a value for CKA_UNIQUE_ID generated and assigned.

C_DecapsulateKey

CA_DecapsulateKey

CK_RV C_DecapsulateKey(
CK_SESSION_HANDLE hSession,	// IN session
CK_MECHANISM_PTR pMechanism,	// IN mechanism and optional parameters
CK_OBJECT_HANDLE hPrivateKey,  // IN decap key handle
CK_ATTRIBUTE_PTR pTemplate,	// IN attributes of new key
CK_ULONG ulAttributeCount,	// IN
CK_BYTE_PTR pCiphertextKey,	// IN cipher texr
CK_ULONG ulCiphertextLen,	// IN
CK_OBJECT_HANDLE_PTR phKey	// OUT handle of new key
);

>C_Decapsulate creates a new secret key object based on the private key and cipher text generated by and encapsulate operation. The new key is identical the key returned by encapsulate. This function is a KEM style function.

>The CKA_DECAPSULATE attribute of the private key, which indicates whether the key supports decapsulation, MUST be CK_TRUE.

The new key has:

>the CKA_ALWAYS_SENSITIVE attribute set to CK_FALSE,

>the CKA_NEVER_EXTRACTABLE attribute set to CK_FALSE.

>the CKA_EXTRACTABLE set to the value of the input template with a default of CK_TRUE if not provided,

>the CKA_LOCAL attribute set to CKA_FALSE

If a call to C_DecapsulateKey cannot support the precise template supplied to it, it fails and returns without creating any key object.

FUNCTION LISTS

The older PKCS#11 specs defined a function table called CK_FUNCTION_LIST. The function C_GetFunctionList is used to return a pointer it.

From PKCS#11 version 3.0, cryptoki supports multiple function tables. As well as the original CK_FUNCTION_LIST you can fetch a CK_FUNCTION_LIST_3_0 or a CK_FUNCTION_LIST_3_2.

Each function table is a super-set of the preceding i.e. the first part of the CK_FUNCTION_LIST_3_0 is equal to CK_FUNCTION_LIST.

To manage these new function tables a new structure is defined. CK_INTERFACE is a structure which contains an interface name with a function list and flag.

The C_GetInterfaceList and C_GetInterface are new functions to query and fetch any supported function list (including Vendor defined).

PKCS#11 Constants

Here are the current working of KEM constantsvalues.

#define CKA_PARAMETER_SET 0x061d

#define CKA_ENCAPSULATE 0x0633

#define CKA_DECAPSULATE 0x0634

#define CKA_PUBLIC_KEY_INFO 0x0129

#define CKA_SEED TBD

#define CKK_ML_KEM 0x49

#define CKM_ML_KEM 0x17

#define CKM_ML_KEM_KEY_PAIR_GEN 0xf

typedef CK_ULONG CK_ML_KEM_PARAMETER_SET_TYPE;

Parameter set types:

CKP_ML_KEM_512	1
CKP_ML_KEM_768	2
CKP_ML_KEM_1024	3

Mechanism Flags include bits to show if the Mechanism supports Encapsulation or Decapsulation.

#define CKF_ENCAPSULATE 0x10000000UL

#define CKF_DECAPSULATE 0x20000000UL

ML_KEM Key Pair Generate

CKM_ML_KEM_KEY_PAIR_GEN is a mechanism that can be used with C_GenerateKeyPair functions.

The mechanism does not take a parameter.

For this mechanism, the ulMinKeySize and ulMaxKeySize fields of the CK_MECHANISM_INFO structure specify the supported range of ML-KEM public key in bytes.

The attribute CKA_PARAMETER_SET in public key template must be used to specify the key size required.

The CKA_PARAMETER_SET attribute is the only required content in either key template. All other attributes are set to a default value by the Key Generation mechanism.

Private Key Attributes

Attribute KeyPair Gen Priv Template Value Default Comments
CKA_CLASS CKO_PRIVATE_KEY CKO_PRIVATE_KEY

Must match default if present

CKA_KEY_TYPE CKK_ML_KEM CKK_ML_KEM Must match default if present
CKA_TOKEN True or False False  
CKA_PRIVATE True True Must not be set false (depending on partition policies)
CKA_LABEL Optional string Null

User defined

CKA_MODIFIABLE True or False True User defined
CKA_PARAMETER_SET CK_ML_KEM_PARAMETER_SET_TYPE   May be supplied by caller
CKA_ID Optional byte array Null User defined
CKA_START_DATE Optional Null User defined
CKA_END_DATE Optional Null User defined
CKA_DERIVE False False Default False
CKA_SUBJECT Optional string Null User defined
CKA_SENSITIVE True True Must match default if present
CKA_DECRYPT False False Default False
CKA_SIGN False False Default False
CKA_SIGN_RECOVER False False Default False
CKA_UNWRAP False False Default False
CKA_EXTRACTABLE False Depends on partition policies Default False
CKA_UNWRAP_TEMPLATE Optional template Null

User defined

CKA_DECAPSULATE True or False True Default to True

The following attributes must not be specified in the private key template. They are all supplied by the mechanism.

CKA_VALUE Decapsulation key (sensitive)   Provided by mechanism
CKA_SEED Key Gen Seed (sensitive)   Provided by mechanism
CKA_LOCAL True   Provided by mechanism
CKA_PUBLIC_KEY_INFO DER encoded Encapsulation Key   Provided by mechanism
CKA_PUBLIC_KEY Raw Encapsulation Key   Provided by mechanism
CKA_ALWAYS_SENSITIVE Read only Based on sensitive Provided by mechanism
CKA_NEVER_EXTRACTABLE Read only Based on extractable Provided by mechanism

Attributes described as “Provided by Mechanism” must not be put in the template during key generation.

Public Key Attributes

Attribute KeyPair Gen Pub Template Value Default Comments

Attribute KeyPair Gen Priv Template Value Default Comments
CKA_CLASS CKO_PUBLIC_KEY CKO_PUBLIC_KEY Must match default if present
CKA_KEY_TYPE CKK_ML_KEM CKK_ML_KEM Must match default if present
CKA_TOKEN True or False False  
CKA_PRIVATE True True  
CKA_LABEL Optional string Null User defined
CKA_MODIFIABLE True or False True User defined
CKA_PARAMETER_SET CK_ML_KEM_PARAMETER_SET_TYPE   Must be supplied during KeyGen – no default
CKA_ID Optional byte array Null User defined
CKA_START_DATE Optional Null User defined
CKA_END_DATE Optional Null User defined
CKA_DERIVE False False Default False
CKA_SUBJECT Optional string Null User defined
CKA_ENCRYPT False False Default False
CKA_VERIFY False False Default False
CKA_VERIFY_RECOVER False False Default False
CKA_WRAP False False Default False
CKA_ENCAPSULATE True or False True Default to True

The following attributes must not be specified in the public key template. They are all supplied by the mechanism.

CKA_VALUE Encapsulation key   Provided by mechanism
CKA_PUBLIC_KEY_INFO DER encoded Encapsulation Key   Provided by mechanism
CKA_LOCAL True   Provided by mechanism

CKA_PUBLIC_KEY_INFO attribute

The CKA_PUBLIC_KEY_INFO attribute holds the public key values as a DER encoded SubjectPublicKeyInfo (as used in X509 certs).

SubjectPublicKeyInfo  ::=  SEQUENCE  {
algorithm            AlgorithmIdentifier,
subjectPublicKey     BIT STRING  }

The ‘algorithm’ is a sequence with an OID and optional params.

AlgorithmIdentifier ::=  SEQUENCE  {
algorithm            OBJECT IDENTIFIER,
parameter            ANY DEFINED BY algorithm OPTIONAL }

From Internet X.509 Public Key Infrastructure - Algorithm Identifiers for Module-Lattice-Based Key-Encapsulation Mechanism (ML-KEM) (ietf.org)

The recommendation uses a different OID for each key size (does not use the algorithm parameter field).

kems OBJECT IDENTIFIER ::= { joint-iso-ccitt(2)
   country(16) us(840) organization(1) gov(101) csor(3)
   nistAlgorithm(4) kems(4) } 


  id-alg-ml-kem-512 OBJECT IDENTIFIER ::= { kems 1 }
  id-alg-ml-kem-768 OBJECT IDENTIFIER ::= { kems 2 }
  id-alg-ml-kem-1024 OBJECT IDENTIFIER ::= { kems 3 }

2.16.840.1.101.3.4.4.1 (ML-KEM-512)

2.16.840.1.101.3.4.4.2 (ML-KEM-768)

2.16.840.1.101.3.4.4.3 (ML-KEM-1024)

DER Encoding for id-alg-ml-kem-512:

   06 -- OID Tag

   09 -- Length

   60 86 48 01 65 03 04 04 01 -- OID ML-KEM-512

The subjectPublicKey is a bit string that holds the public key value. Its content format depends on the algorithm. For ML-KEM this is an octet array of size 800 or 1184 or 1568 (not a DER encoding – just the 800 etc bytes with the usual leading ‘00’ to indicate no bit padding).

The parameter field in the AlgorithmIdentifier is empty (missing).

Creating a ML_KEM Public Key Object

Cryptoki uses C_CreateObject to construct public key objects from known public keys.

The caller supplies sufficient attributes to allow the object to be created.

Attribute KeyPair Gen Priv Template Value Default Comments
CKA_CLASS CKO_PUBLIC_KEY CKO_PUBLIC_KEY Must be set
CKA_KEY_TYPE CKK_ML_KEM CKK_ML_KEM Must be set
CKA_TOKEN True or False

False

 
CKA_PRIVATE True True  
CKA_LABEL Optional string Null User defined
CKA_MODIFIABLE True or False True User defined
CKA_PARAMETER_SET CK_ML_KEM_PARAMETER_SET_TYPE   Optional, must match key length if present
CKA_ID Optional byte array Null User defined
CKA_START_DATE Optional Null User defined
CKA_END_DATE Optional Null User defined
CKA_DERIVE False False DefaultFalse
CKA_SUBJECT Optional string Null User defined
CKA_ENCRYPT False False DefaultFalse
CKA_VERIFY False False DefaultFalse
CKA_VERIFY_RECOVER False False DefaultFalse
CKA_WRAP False False DefaultFalse
CKA_ENCAPSULATE True or False True Default to True
CKA_VALUE Encapsulation key   Either CKA_VALUE or CKA_PUBLIC_KEY_INFO must be provided
CKA_PUBLIC_KEY_INFO

DER encoded Encapsulation Key

 

The following attributes must not be specified in the public key template. They are all supplied by the mechanism.

CKA_LOCAL False    

CKM_ML_KEM Key Agreement

The ML-KEM Key Agreement mechanism, denoted CKM_ML_KEM, is a mechanism for key encapsulation and decapsulation using ML-KEM. Both are defined in [FIPS 203].

It has no parameters.

When used by C_EncapsulateKey, this mechanism generates a 32 byte shared secret value.

The shared secret is then used to create a symmetric key object - as defined by the template.

The shared secret is also encapsulated using the ML-KEM Public Key and ML-KEM.Enc() operation to make a cipher text.

When used in C_DecapsulateKey, this mechanism recovers the shared secret from an encapsulated cipher text using the ML-KEM Private key with the ML-KEM.Dec() operation. The shared secret is then used to create a symmetric key object - as defined by the template.

The CKA_CLASS is supplied by the mechanism as CKO_SECRET_KEY.

The CKA_KEY_TYPE must be specified in the template and may be CKK_AES or CKK_GENERIC_SECRET.

The mechanism contributes the result as the CKA_VALUE attribute of the new key; other attributes required by the key type must be specified in the template.

The CKA_VALUE_LEN attribute of the template can be used to set the new key’s length where the key type is ambiguous e.g. CKK_AES.

If the output key type is CKK_GENERIC_SECRET then resulting keys must contain the full output of the underlying mechanism e.g. 32 bytes for ML_KEM.

Otherwise, if the output key is an AES and is shorter than the shared secret, then the CKA_VALUE will be selected from the left most bytes of the shared secret.

The container configuration flags CONTAINER_CONFIG_SECRET_KEY_UNWRAPPING and CONTAINER_CONFIG_SECRET_KEY_WRAPPING should be enabled as appropriate for decapsulation or encapsulation of Secret Keys.

The CKA_KEYRING_OUID may be provided in the template for the new symmetric key or be present in the Decapsulation Key or Encapsulation Key.

En/Decapsulation Key has
CKA_KEYRING_OUID
New Key Template has
CKA_KEYRING_OUID

Behavior

No No No action
Yes No CKA_KEYRING_UOID of new key is set to value of Base key
No Yes Verify OUID is a valid OUID and caller has access
Yes Yes Both OUID values must match else CKR_ATTRIBUTE_VALUE_INVALID is returned

Error Codes

TBD.

Key Attributes

There are new attributes - CKA_PARAMETER_SET, CKA_PUBLIC_KEY_INFO, CKA_SEED, CKA_DECAPSULATE and CKA_ENCAPSULATE.

Private Key Import/Export

Private keys can be imported and exported with existing PKCS#11 functions using the appropriate published DER encoding.

Key Backup and Cloning

Backups and cloning of ML_KEM keys is supported.