OpenTitan Cryptography Library Specification
This page is intended for users of the OpenTitan cryptographic library. The library is written in C and uses OpenTitan’s hardware blocks for accelerated cryptography. It generally attempts to minimize code size and protect against side-channel and fault-injection attacks, including by physically present attackers.
Note: at the time of writing, the crypto library is still under development, and not all algorithms described in this page are fully implemented and tested.
Supported Algorithms
The following is a quick reference for algorithms and modes supported by the OT cryptolib. For more details, see later sections (links in the “category” column).
Category | Supported schemes |
---|---|
AES | AES-{ECB,CBC,CFB,OFB,CTR} AES-KWP AES-GCM |
Hash functions | SHA2-{256,384,512} SHA3-{224,256,384,512} SHAKE{128,256} (XOF) cSHAKE{128,256} (XOF) |
Message authentication | HMAC-SHA256 KMAC{128,256} |
RSA | RSA-{2048,3072,4096} |
Elliptic curve cryptography | ECDSA-{P256,P384} ECDH-{P256,P384} Ed25519 X25519 |
Deterministic random bit generation | AES-CTR-DRBG |
Key derivation | HMAC-KDF-CTR KMAC-KDF-CTR |
Asynchronous operations
For some functions, OpenTitan’s cryptolib supports asynchronous calls. All operations which take longer than 10ms should have an asychronous interface. This is helpful for compatibility with TockOS, which has a low latency return call programming model.
The OpenTitan cryptolib does not implement any thread management. Instead, it treats the OTBN coprocessor as a “separate thread” to achieve non-blocking operation with virtually zero overhead. OTBN sends an interrupt when processing is complete.
All asynchronous operations have two functions:
- <algorithm>_async_start
- Takes input arguments. Checks that OTBN is available and idle. If so: does any necessary synchronous preprocessing, initializes OTBN, and starts the OTBN routine.
- <algorithm>_async_finalize
- Takes caller-allocated output buffers. Blocks until OTBN is done processing if needed, then checks whether it had errors. If not, does any necessary postprocessing and writes results to the buffers.
The caller should call the start
function, wait for the interrupt, and then call finalize
.
A few noteworthy aspects of this setup:
- While an asynchronous operation is running, OTBN will be unavailable and attempts to use it will return errors.
- Only one asynchronous operation may be in progress at any given time.
- The caller is responsible for properly managing asynchronous calls, including ensuring that the entity receiving the
finalize
results is the same as the one who calledstart
.
The following operations can run asynchronously:
Scheme | Operations |
---|---|
ECDSA | keygen, sign, verify |
ECDH | keygen, key exchange |
Ed25519 | keygen, sign, verify |
X25519 | keygen, key exchange |
RSA | keygen, sign, verify |
Data structures
These are the basic data structures used by the crypto library to communicate with the caller. Note that in the OpenTitan cryptolib, memory allocation is left mostly to the caller.
Status Codes
All functions in the OpenTitan cryptolib return crypto_status_t
.
This design is compatible with OpenTitan’s internal status_t
datatype.
sw/device/lib/crypto/include/datatypes.h#L32:
/**
* Return values for the crypto library.
*
* The crypto library's return value is defined as OpenTitan's internal
* `status_t` in order to simplify testing. However, informally the library
* guarantees that the concrete value contained in the status will be one of
* the members of the `crypto_status_value` enum below.
*/
typedef status_t crypto_status_t;
However, the cryptolib additionally guarantees that all status codes will be bit-compatible to the crypto_status_value
enum.
Callers who do not wish to use status_t
infrastructure may compare to these values.
sw/device/lib/crypto/include/datatypes.h#L60:
/**
* Possible status values for the cryptolib.
*
* As long as the OTCRYPTO_STATUS_DEBUG define is unset, all `crypto_status_t`
* codes returned by the cryptolib should be bit-by-bit equivalent with one of
* the values in this enum.
*
* Values are built to be bit-compatible with OpenTitan's internal `status_t`
* datatypes. The highest (sign) bit indicates if the value is an error (1) or
* not (0). For non-error statuses, the rest can be anything; in cryptolib
* status codes it is always `kHardenedBoolTrue`. For errors:
* - The next 15 bits are a module identifier, which is always 0 in the
* cryptolib status codes
* - The next 11 bits are a line number or other information; in the
* cryptolib status codes, it is a hardened value created to have high
* Hamming distance with the other valid status codes
* - The final 5 bits are an Abseil-compatible error code
*
* The hardened values for error codes were generated with:
* $ ./util/design/sparse-fsm-encode.py -d 5 -m 5 -n 11 \
* -s 4232058530 --language=sv --avoid-zero
*
* Use the same seed value and a larger `-m` argument to generate new values
* without changing all error codes. Remove the seed (-s argument) to generate
* completely new 11-bit values.
*/
typedef enum crypto_status_value {
// Status is OK; no errors.
kCryptoStatusOK = (int32_t)0x739,
// Invalid input arguments; wrong length or invalid type.
kCryptoStatusBadArgs = (int32_t)0x8000fea0 | kInvalidArgument,
// Error after which it is OK to retry (e.g. timeout).
kCryptoStatusInternalError = (int32_t)0x80005340 | kAborted,
// Error after which it is not OK to retry (e.g. integrity check).
kCryptoStatusFatalError = (int32_t)0x80006d80 | kFailedPrecondition,
// An asynchronous operation is still in progress.
kCryptoStatusAsyncIncomplete = (int32_t)0x8000ea40 | kUnavailable,
// TODO: remove all instances of this error before release; it is to track
// implementations that are not yet complete.
kCryptoStatusNotImplemented = (int32_t)0x80008d20 | kUnimplemented,
} crypto_status_value_t;
Data buffers
The cryptolib uses byte buffers for data that may not be 32-bit aligned, such as message inputs to hash functions.
sw/device/lib/crypto/include/datatypes.h#L83:
/**
* Struct to hold a fixed-length byte array.
*
* Note: the caller must (1) allocate sufficient space and (2) set the `len`
* field and `data` pointer when `crypto_byte_buf_t` is used for output. The
* crypto library will throw an error if `len` doesn't match expectations.
*/
typedef struct crypto_byte_buf {
// Length of the data in bytes.
size_t len;
// Pointer to the data.
uint8_t *data;
} crypto_byte_buf_t;
sw/device/lib/crypto/include/datatypes.h#L98:
/**
* Struct to hold a constant fixed-length byte array.
*
* The const annotations prevent any changes to the byte buffer. It is
* necessary to have this structure separate from `crypto_byte_buf_t` because
* data pointed to by a struct does not inherit `const`, so `const
* crypto_byte_buf_t` would still allow data to change.
*/
typedef struct crypto_const_byte_buf {
// Length of the data in bytes.
const size_t len;
// Pointer to the data.
const uint8_t *const data;
} crypto_const_byte_buf_t;
The cryptolib uses word buffers to enforce alignment where either the data is guaranteed to be aligned or where it is especially helpful for implementation reasons. Since most OpenTitan hardware interfaces expect aligned data, this is important sometimes for security and simplicity. Word buffers can be safely interpreted as byte streams by the caller; the bytes are arranged so that on a little-endian processor like Ibex, they will read as the correct byte-stream even if the specification calls for big-endian.
sw/device/lib/crypto/include/datatypes.h#L112:
/**
* Struct to hold a fixed-length word array.
*
* Note: the caller must (1) allocate sufficient space and (2) set the `len`
* field and `data` pointer when `crypto_word32_buf_t` is used for output. The
* crypto library will throw an error if `len` doesn't match expectations.
*/
typedef struct crypto_word32_buf {
// Length of the data in words.
size_t len;
// Pointer to the data.
uint32_t *data;
} crypto_word32_buf_t;
sw/device/lib/crypto/include/datatypes.h#L127:
/**
* Struct to hold a constant fixed-length word array.
*
* The const annotations prevent any changes to the word buffer. It is
* necessary to have this structure separate from `crypto_word32_buf_t` because
* data pointed to by a struct does not inherit `const`, so `const
* crypto_word32_buf_t` would still allow data to change.
*/
typedef struct crypto_const_word32_buf {
// Length of the data in words.
const size_t len;
// Pointer to the data.
const uint32_t *const data;
} crypto_const_word32_buf_t;
Key data structures
Keys receive extra protection from the cryptolib. Public keys are represented in plain, “unblinded” form, but have a checksum to protect their integrity. The checksum is implementation-specific and may change over time. Therefore, the caller should not compute the checksum themselves; use the key import/export functions to construct unblinded keys.
sw/device/lib/crypto/include/datatypes.h#L365:
/**
* Struct to handle unmasked key type.
*/
typedef struct crypto_unblinded_key {
// Mode for which the key usage is intended.
key_mode_t key_mode;
// Key length in bytes.
size_t key_length;
// Implementation specific, storage provided by caller.
uint32_t *key;
// Implementation specific, checksum for this struct.
uint32_t checksum;
} crypto_unblinded_key_t;
Secret keys are “blinded”, meaning that keys are represented by at least two “shares” the same size as the key. This helps protect against e.g. power side-channel attacks, because the code will never handle a bit of the “real” key, only the independent shares. The choice of blinding method depends on the algorithm and is implementation-specific. Callers should use key import/export functions to interpret blinded keys.
sw/device/lib/crypto/include/datatypes.h#L379:
/**
* Struct to handle masked key type.
*/
typedef struct crypto_blinded_key {
// Key configuration information.
const crypto_key_config_t config;
// Length of blinded key material in bytes.
const size_t keyblob_length;
// Implementation specific, storage provided by caller.
uint32_t *keyblob;
// Implementation specific, checksum for this struct.
uint32_t checksum;
} crypto_blinded_key_t;
As shown above, all secret keys have a configuration value. The configuration helps the cryptolib interpret how the key is represented and how it is permitted to be used. Nothing in the configuration is typically secret.
sw/device/lib/crypto/include/datatypes.h#L343:
/**
* Struct to represent the configuration of a blinded key.
*/
typedef struct crypto_key_config {
// Crypto library version for this key.
crypto_lib_version_t version;
// Mode for which the key usage is intended.
key_mode_t key_mode;
// Length in bytes of the unblinded form of this key.
size_t key_length;
// Whether the hardware key manager should produce this key.
hardened_bool_t hw_backed;
// Diversification input for key manager (ignored and may be
// `NULL` if `hw_backed` is false).
crypto_const_byte_buf_t diversification_hw_backed;
// Whether the key should be exportable (if this is true,
// `hw_backed` must be false).
hardened_bool_t exportable;
// Key security level.
crypto_key_security_level_t security_level;
} crypto_key_config_t;
In most cases, the caller needs to provide a configuration before calling algorithms which generate secret keys.
Callers may request keys from OpenTitan’s key manager block by setting hw_backed
and diversification_hw_backed
in the key configuration.
If the key is produced by the key manager, then the keyblob has length 0; the diversification information is enough to produce the key.
Bookkeeping data structures
This versioning enum helps the cryptolib keep backwards-compatibility if the representation of opaque data-structures changes. This way, a later version of the cryptolib can still recognize and interpret a data structure produced by an earlier version, for example a stored key.
sw/device/lib/crypto/include/datatypes.h#L335:
/**
* Enum to denote the crypto library version.
*
* In future updates, this enum will be extended to preserve some
* level of backwards-compatibility despite changes to internal
* details (for example, the preferred masking scheme for blinded
* keys).
*
* Values are hardened.
*/
typedef enum crypto_lib_version {
// Version 1.
kCryptoLibVersion1 = 0x7f4,
} crypto_lib_version_t;
Data structures for key types and modes help the cryptolib recognize and prevent misuse of a key for the wrong algorithm or mode.
sw/device/lib/crypto/include/datatypes.h#L139:
/**
* Enum to denote the key type of the handled key.
*
* Values are hardened.
*/
typedef enum key_type {
// Key type AES.
kKeyTypeAes = 0x8e9,
// Key type HMAC.
kKeyTypeHmac = 0xe3f,
// Key type KMAC.
kKeyTypeKmac = 0xb74,
// Key type RSA.
kKeyTypeRsa = 0x7ee,
// Key type ECC.
kKeyTypeEcc = 0x15b,
// Key type KDF.
kKeyTypeKdf = 0xb87,
} key_type_t;
sw/device/lib/crypto/include/datatypes.h#L162:
/**
* Enum to specify the AES modes that use a key.
*
* This will be used in the `key_mode_t` struct to indicate the mode
* for which the provided key is intended for.
*
* Values are hardened.
*/
typedef enum aes_key_mode {
// Mode AES ECB.
kAesKeyModeEcb = 0x1b6,
// Mode AES CBC.
kAesKeyModeCbc = 0xf3a,
// Mode AES CFB.
kAesKeyModeCfb = 0x0f9,
// Mode AES OFB.
kAesKeyModeOfb = 0xb49,
// Mode AES CTR.
kAesKeyModeCtr = 0x4ce,
// Mode AES GCM.
kAesKeyModeGcm = 0xaa5,
// Mode AES KWP.
kAesKeyModeKwp = 0x7d5,
} aes_key_mode_t;
sw/device/lib/crypto/include/datatypes.h#L187:
/**
* Enum to specify the HMAC modes that use a key.
*
* This will be used in the `key_mode_t` struct to indicate the mode
* for which the provided key is intended for.
*
* Values are hardened.
*/
typedef enum hmac_key_mode {
// Mode HMAC SHA256.
kHmacKeyModeSha256 = 0xc1d,
} hmac_key_mode_t;
sw/device/lib/crypto/include/datatypes.h#L200:
/**
* Enum to specify the KMAC modes that use a key.
*
* This will be used in the `key_mode_t` struct to indicate the mode
* for which the provided key is intended for.
*
* Values are hardened.
*/
typedef enum kmac_key_mode {
// Mode KMAC128.
kKmacKeyModeKmac128 = 0xa56,
// Mode KMAC256.
kKmacKeyModeKmac256 = 0x663,
} kmac_key_mode_t;
sw/device/lib/crypto/include/datatypes.h#L215:
/**
* Enum to specify the RSA modes that use a key.
*
* This will be used in the `key_mode_t` struct to indicate the mode
* for which the provided key is intended for.
*
* Values are hardened.
*/
typedef enum rsa_key_mode {
// Mode RSA Sign, RSASSA-PKCS.
kRsaKeyModeSignPkcs = 0x9ff,
// Mode RSA Sign, RSASSA-PSS.
kRsaKeyModeSignPss = 0xa95,
} rsa_key_mode_t;
sw/device/lib/crypto/include/datatypes.h#L230:
/**
* Enum to specify the ECC modes that use a key.
*
* This will be used in the `key_mode_t` struct to indicate the mode
* for which the provided key is intended for.
*
* Values are hardened.
*/
typedef enum ecc_key_mode {
// Mode ECDSA.
kEccKeyModeEcdsa = 0x4e5,
// Mode ECDH.
kEccKeyModeEcdh = 0x6bb,
// Mode Ed25519.
kEccKeyModeEd25519 = 0xd32,
// Mode X25519.
kEccKeyModeX25519 = 0x276,
} ecc_key_mode_t;
sw/device/lib/crypto/include/datatypes.h#L249:
/**
* Enum to specify the KDF modes that use a key.
*
* This will be used in the `key_mode_t` struct to indicate the mode
* for which the provided key is intended for.
*
* Values are hardened.
*/
typedef enum kdf_key_mode {
// Mode KDF with HMAC as PRF.
kKdfKeyModeHMAC = 0x5d8,
// Mode KDF with KMAC as PRF.
kKdfKeyModeKMAC = 0xb29,
} kdf_key_mode_t;
sw/device/lib/crypto/include/datatypes.h#L265:
/**
* Enum for opentitan crypto modes that use a key.
*
* Denotes the crypto mode for which the provided key is to be used.
* This `key_mode_t` will be a parameter in the `crypto_blinded_key_t`
* and `crypto_unblinded_key_t` structs.
*
* Values are hardened.
*/
typedef enum key_mode {
// Key is intended for AES ECB mode.
kKeyModeAesEcb = kKeyTypeAes << 16 | kAesKeyModeEcb,
// Key is intended for AES CBC mode.
kKeyModeAesCbc = kKeyTypeAes << 16 | kAesKeyModeCbc,
// Key is intended for AES CFB mode.
kKeyModeAesCfb = kKeyTypeAes << 16 | kAesKeyModeCfb,
// Key is intended for AES OFB mode.
kKeyModeAesOfb = kKeyTypeAes << 16 | kAesKeyModeOfb,
// Key is intended for AES CTR mode.
kKeyModeAesCtr = kKeyTypeAes << 16 | kAesKeyModeCtr,
// Key is intended for AES GCM mode.
kKeyModeAesGcm = kKeyTypeAes << 16 | kAesKeyModeGcm,
// Key is intended for AES KWP mode.
kKeyModeAesKwp = kKeyTypeAes << 16 | kAesKeyModeKwp,
// Key is intended for HMAC SHA256 mode.
kKeyModeHmacSha256 = kKeyTypeHmac << 16 | kHmacKeyModeSha256,
// Key is intended for KMAC128 mode.
kKeyModeKmac128 = kKeyTypeKmac << 16 | kKmacKeyModeKmac128,
// Key is intended for KMAC256 mode.
kKeyModeKmac256 = kKeyTypeKmac << 16 | kKmacKeyModeKmac256,
// Key is intended for RSA signature RSASSA-PKCS mode.
kKeyModeRsaSignPkcs = kKeyTypeRsa << 16 | kRsaKeyModeSignPkcs,
// Key is intended for RSA signature RSASSA-PSS mode.
kKeyModeRsaSignPss = kKeyTypeRsa << 16 | kRsaKeyModeSignPss,
// Key is intended for ECDSA mode.
kKeyModeEcdsa = kKeyTypeEcc << 16 | kEccKeyModeEcdsa,
// Key is intended for ECDH mode.
kKeyModeEcdh = kKeyTypeEcc << 16 | kEccKeyModeEcdh,
// Key is intended for Ed25519 mode.
kKeyModeEd25519 = kKeyTypeEcc << 16 | kEccKeyModeEd25519,
// Key is intended for X25519 mode.
kKeyModeX25519 = kKeyTypeEcc << 16 | kEccKeyModeX25519,
// Key is intended for KDF with HMAC as PRF.
kKeyModeKdfHmac = kKeyTypeKdf << 16 | kKdfKeyModeHMAC,
// Key is intended for KDF with KMAC as PRF.
kKeyModeKdfKmac = kKeyTypeKdf << 16 | kKdfKeyModeKMAC,
} key_mode_t;
Algorithm-specific data structures
AES data structures
sw/device/lib/crypto/include/aes.h#L46:
/**
* Enum to define AES mode of operation.
*
* Values are hardened.
*/
typedef enum block_cipher_mode {
// AES ECB mode (electronic codebook mode).
kBlockCipherModeEcb = 0x533,
// AES CBC mode (cipher block chaining mode).
kBlockCipherModeCbc = 0x45d,
// AES CFB mode (cipher feedback mode).
kBlockCipherModeCfb = 0xcd2,
// AES OFB mode (output feedback mode).
kBlockCipherModeOfb = 0x39a,
// AES CTR mode (counter mode).
kBlockCipherModeCtr = 0xd2c,
} block_cipher_mode_t;
sw/device/lib/crypto/include/aes.h#L64:
/**
* Enum to define AES operation to be performed.
*
* Values are hardened.
*/
typedef enum aes_operation {
// AES operation mode encrypt.
kAesOperationEncrypt = 0x2b6,
// AES operation mode decrypt.
kAesOperationDecrypt = 0x5f0,
} aes_operation_t;
sw/device/lib/crypto/include/aes.h#L76:
/**
* Enum to define padding scheme for AES data.
*
* Values are hardened.
*/
typedef enum aes_padding {
// Pads with value same as the number of padding bytes.
kAesPaddingPkcs7 = 0xe7f,
// Pads with 0x80 (10000000), followed by zero bytes.
kAesPaddingIso9797M2 = 0xfac,
// Add no padding.
kAesPaddingNull = 0x8ce,
} aes_padding_t;
sw/device/lib/crypto/include/aes.h#L24:
/**
* Enum to denote the AES-GCM tag length.
*
* Values are hardened.
*/
typedef enum aead_gcm_tag_len {
// Tag length 128 bits.
kAeadGcmTagLen128 = 0x167,
// Tag length 120 bits.
kAeadGcmTagLen120 = 0xabd,
// Tag length 112 bits.
kAeadGcmTagLen112 = 0xc1b,
// Tag length 104 bits.
kAeadGcmTagLen104 = 0xbe0,
// Tag length 96 bits.
kAeadGcmTagLen96 = 0x35a,
// Tag length 64 bits.
kAeadGcmTagLen64 = 0x5d4,
// Tag length 32 bits.
kAeadGcmTagLen32 = 0xf06,
} aead_gcm_tag_len_t;
Elliptic curve data structures
sw/device/lib/crypto/include/ecc.h#L24:
/**
* Struct to handle ECDSA or EdDSA signatures.
*/
typedef struct ecc_signature {
// Length of ECC signature R parameter, in bytes.
size_t len_r;
// ECC signature R parameter.
uint32_t *r;
// Length of ECC signature S parameter, in bytes.
size_t len_s;
// ECC signature S parameter.
uint32_t *s;
} ecc_signature_t;
sw/device/lib/crypto/include/ecc.h#L40:
/**
* Enum to define EdDSA mode for signature.
*
* Values are hardened.
*/
typedef enum eddsa_sign_mode {
// Signature mode EdDSA.
kEddsaSignModeEdDSA = 0xae1,
// Signature mode Hashed EdDSA.
kEddsaSignModeHashEdDSA = 0x9a6,
} eddsa_sign_mode_t;
sw/device/lib/crypto/include/ecc.h#L52:
/**
* Struct to handle ECDSA or ECDH public key type.
*
* Length of public key coordinates (x,y) follows len(p).
*/
typedef struct ecc_public_key {
// ECC public key x coordinate.
crypto_unblinded_key_t x;
// ECC public key y coordinate.
crypto_unblinded_key_t y;
} ecc_public_key_t;
sw/device/lib/crypto/include/ecc.h#L62:
/**
* Struct for domain parameters of a custom Weierstrass curve.
*/
typedef struct ecc_domain {
// Prime P (modulus of coordinate finite field).
crypto_const_byte_buf_t p;
// Coefficient a.
crypto_const_byte_buf_t a;
// Coefficient b.
crypto_const_byte_buf_t b;
// q (order of G).
crypto_const_byte_buf_t q;
// Value of x coordinate of G (basepoint). Same length as p.
const uint32_t *gx;
// Value of y coordinate of G (basepoint). Same length as p.
const uint32_t *gy;
// Cofactor of the curve.
const uint32_t cofactor;
// Checksum value of the parameters.
uint32_t checksum;
} ecc_domain_t;
sw/device/lib/crypto/include/ecc.h#L86:
/**
* Enum to define the type of elliptic curve used for the operation.
*
* Values are hardened.
*/
typedef enum ecc_curve_type {
// Generic Weierstrass curve, with custom domain parameters.
kEccCurveTypeCustom = 0xbf7,
// Named Weierstrass curve - NIST P256.
kEccCurveTypeNistP256 = 0xec8,
// Named Weierstrass curve - NIST P384.
kEccCurveTypeNistP384 = 0x1bc,
// Named Weierstrass curve - Brainpool P256r1.
kEccCurveTypeBrainpoolP256R1 = 0xc1e,
} ecc_curve_type_t;
sw/device/lib/crypto/include/ecc.h#L102:
/**
* Struct for ECC curve used for ECDSA / ECDH operation.
*
* Values are hardened.
*/
typedef struct ecc_curve {
// Type of the Weierstrass curve, custom curve or named curve.
ecc_curve_type_t curve_type;
// Domain parameters for a custom Weierstrass curve.
ecc_domain_t domain_parameter;
} ecc_curve_t;
Hash data structures
sw/device/lib/crypto/include/hash.h#L27:
/**
* Enum to define supported hashing modes.
*
* Values are hardened.
*/
typedef enum hash_mode {
// SHA2-256 mode.
kHashModeSha256 = 0x783,
// SHA2-384 mode.
kHashModeSha384 = 0xd16,
// SHA2-512 mode.
kHashModeSha512 = 0x2e9,
// SHA3-224 mode.
kHashModeSha3_224 = 0x13d,
// SHA3-256 mode.
kHashModeSha3_256 = 0xc99,
// SHA3-384 mode.
kHashModeSha3_384 = 0xb58,
// SHA3-512 mode.
kHashModeSha3_512 = 0x963,
} hash_mode_t;
sw/device/lib/crypto/include/hash.h#L49:
/**
* Enum to define the supported extendable-output functions.
*
* Values are hardened.
*/
typedef enum xof_mode {
// Shake128 mode.
kXofModeSha3Shake128 = 0x9bd,
// Shake256 mode.
kXofModeSha3Shake256 = 0x758,
// cShake128 mode.
kXofModeSha3Cshake128 = 0xbd3,
// cShake256 mode.
kXofModeSha3Cshake256 = 0x0fa,
} xof_mode_t;
Key derivation data structures
sw/device/lib/crypto/include/kdf.h#L26:
/**
* Enum to define the supported KDF constructions.
*
* Values are hardened.
*/
typedef enum kdf_type {
// KDF construction with HMAC as a PRF.
kKdfTypeHmac = 0x4f1,
// KDF construction with KMAC as a PRF.
kKdfTypeKmac = 0x754,
} kdf_type_t;
Message authentication data structures
sw/device/lib/crypto/include/mac.h#L26:
/**
* Enum to define KMAC mode.
*
* Values are hardened.
*/
typedef enum kmac_mode {
// KMAC128 mode.
kMacModeKmac128 = 0x336,
// KMAC256 mode.
kMacModeKmac256 = 0xec4,
} kmac_mode_t;
RSA data structures
sw/device/lib/crypto/include/rsa.h#L24:
/**
* Enum to define padding scheme for RSA data.
*
* Values are hardened.
*/
typedef enum rsa_padding {
// Pads input data according to the PKCS#1 (v1.5) scheme.
kRsaPaddingPkcs = 0x94e,
// Pads input data according to the PKCS#1-PSS scheme.
kRsaPaddingPss = 0x6b1,
} rsa_padding_t;
sw/device/lib/crypto/include/rsa.h#L36:
/**
* Enum to define hash modes for RSA schemes.
*
* Aligning with existing hash modes. Values are hardened.
*/
typedef enum rsa_hash {
// SHA2-256 hashing mode for RSA.
kRsaHashSha256 = 0x378,
// SHA2-384 hashing mode for RSA.
kRsaHashSha384 = 0xe8c,
// SHA2-512 hashing mode for RSA.
kRsaHashSha512 = 0xf1b,
// SHA3-384 hashing mode for RSA.
kRsaHashSha3_384 = 0x767,
} rsa_hash_t;
sw/device/lib/crypto/include/rsa.h#L50:
/**
* Struct to handle the RSA private exponent and modulus.
*/
typedef struct rsa_private_key {
// Unblinded key struct with RSA modulus.
crypto_unblinded_key_t n;
// Blinded key struct with RSA private exponent.
crypto_blinded_key_t d;
} rsa_private_key_t;
sw/device/lib/crypto/include/rsa.h#L62:
/**
* Enum to define possible lengths of RSA (public) keys.
*
* Values are hardened.
*/
typedef enum rsa_key_size {
// 2048-bit RSA key.
kRsaKeySize2048 = 0x5d1,
// 3072-bit RSA key.
kRsaKeySize3072 = 0xc35,
// 4096-bit RSA key.
kRsaKeySize4096 = 0x8da,
} rsa_key_size_t;
sw/device/lib/crypto/include/rsa.h#L74:
/**
* Struct to handle the RSA public exponent and modulus.
*/
typedef struct rsa_public_key {
// Unblinded key struct with RSA modulus.
crypto_unblinded_key_t n;
// Blinded key struct with RSA public exponent.
crypto_unblinded_key_t e;
} rsa_public_key_t;
Private data structures
The following data structures are considered implementation specific. The caller knows their size and must allocate space for them. However, they are essentially scratchpad space for the underlying implementation and should not be modified directly.
sw/device/lib/crypto/include/hash.h#L66:
/**
* Generic hash context.
*
* Representation is internal to the hash implementation; initialize
* with #otcrypto_hash_init.
*/
typedef struct hash_context {
// Required hash mode.
hash_mode_t mode;
// Context for the hash operation.
uint32_t data[52];
} hash_context_t;
sw/device/lib/crypto/include/mac.h#L39:
/**
* Generic hmac context.
*
* Representation is internal to the hmac implementation; initialize
* with #otcrypto_hmac_init.
*/
typedef struct hmac_context {
// Context for the hmac operation.
uint32_t data[42];
} hmac_context_t;
sw/device/lib/crypto/include/aes.h#L91:
/**
* Context for GCM GHASH operation.
*
* Representation is internal to the aes-gcm ghash implementation;
* initialize with #otcrypto_gcm_ghash_init.
*/
typedef struct gcm_ghash_context {
// Context for the gcm-ghash operation.
uint32_t ctx[68];
} gcm_ghash_context_t;
AES
OpenTitan includes a hardware AES block. The AES block supports five cipher modes (ECB, CBC, CFB, OFB, and CTR) with a key length of 128 bits, 192 bits and 256 bits.
The crypto library includes all five basic cipher modes supported by the hardware, as well as the AES-KWP key-wrapping scheme and AES-GCM authenticated encryption scheme. Padding schemes are defined in the aes_padding_t structure from this section.
Because the crypto library uses the hardware AES block, it does not expose an init/update/final interface for AES, since this would risk locking up the block if an operation is not finalized.
Key generation
Given a key configuration, generate an AES key. The key may be either randomly generated or derived using the key manager, depending on the configuration.
sw/device/lib/crypto/include/aes.h#L113:
/**
* Generates a new AES key.
*
* The caller should allocate and partially populate the blinded
* key struct, including populating the key configuration and
* allocating space for the keyblob. The caller should indicate
* the length of the allocated keyblob; this function will
* return an error if the keyblob length does not match
* expectations. For hardware-backed keys, the keyblob length is 0
* and the keyblob pointer may be `NULL`. For non-hardware-backed keys,
* the keyblob should be twice the length of the key. The value in
* the `checksum` field of the blinded key struct will be populated
* by the key generation function.
*
* @param[out] key Destination blinded key struct.
* @return The result of the cipher operation.
*/
crypto_status_t otcrypto_aes_keygen(crypto_blinded_key_t *key);
Block Cipher
A one-shot API initializes the required block cipher mode of operation (ECB, CBC, CFB, OFB or CTR) and performs the required encryption/decryption.
sw/device/lib/crypto/include/aes.h#L157:
/**
* Performs the AES operation.
*
* The input data in the `cipher_input` is first padded using the
* `aes_padding` scheme and the output is copied to `cipher_output`.
*
* The caller should allocate space for the `cipher_output` buffer, which is
* given in bytes by `otcrypto_aes_padded_plaintext_length`, and set the number
* of bytes allocated in the `len` field of the output. If the user-set length
* and the expected length do not match, an error message will be returned.
*
* Note that, during decryption, the padding mode is ignored. This function
* will NOT check the padding or return an error if the padding is invalid,
* since doing so could expose a padding oracle (especially in CBC mode).
*
* @param key Pointer to the blinded key struct with key shares.
* @param iv Initialization vector, used for CBC, CFB, OFB, CTR modes. May be
* NULL if mode is ECB.
* @param aes_mode Required AES mode of operation.
* @param aes_operation Required AES operation (encrypt or decrypt).
* @param cipher_input Input data to be ciphered.
* @param aes_padding Padding scheme to be used for the data.
* @param[out] cipher_output Output data after cipher operation.
* @return The result of the cipher operation.
*/
crypto_status_t otcrypto_aes(const crypto_blinded_key_t *key,
crypto_word32_buf_t iv,
block_cipher_mode_t aes_mode,
aes_operation_t aes_operation,
crypto_const_byte_buf_t cipher_input,
aes_padding_t aes_padding,
crypto_byte_buf_t cipher_output);
AES-GCM
AES-GCM (Galois/Counter Mode) is an authenticated encryption with associated data (AEAD) scheme. It protects both the confidentiality and authenticity of the main input and the authenticity (but not confidentiality) of the associated data.
GCM is specified in NIST SP800-38D. One important note for using AES-GCM is that shorter tags degrade authentication guarantees, so it is important to fully understand the implications before using shortened tags.
In addition, we expose the internal GHASH and GCTR operation that GCM relies upon (from NIST SP800-38D, section 6.4). This allows flexibility for use-cases that need custom GCM constructs: for example, we do not provide AES-GCM in streaming mode here because it encourages decryption and processing of unauthenticated data, but some users may need it for compatibility purposes. Additionally, the GHASH operation can be used to construct GCM with block ciphers other than AES.
GCM - Authenticated Encryption and Decryption
sw/device/lib/crypto/include/aes.h#L189:
/**
* Performs the AES-GCM authenticated encryption operation.
*
* This function encrypts the input `plaintext` to produce an
* output `ciphertext`. Together it generates an authentication
* tag `auth_tag` on the ciphered data and any non-confidential
* additional authenticated data `aad`.
*
* The caller should allocate space for the `ciphertext` buffer,
* (same length as input), `auth_tag` buffer (same as tag_len), and
* set the length of expected outputs in the `len` field of
* `ciphertext` and `auth_tag`. If the user-set length and the output
* length does not match, an error message will be returned.
*
* @param key Pointer to the blinded gcm-key struct.
* @param plaintext Input data to be encrypted and authenticated.
* @param iv Initialization vector for the encryption function.
* @param aad Additional authenticated data.
* @param tag_len Length of authentication tag to be generated.
* @param[out] ciphertext Encrypted output data, same length as input data.
* @param[out] auth_tag Generated authentication tag.
* @return Result of the authenticated encryption.
* operation
*/
crypto_status_t otcrypto_aes_encrypt_gcm(const crypto_blinded_key_t *key,
crypto_const_byte_buf_t plaintext,
crypto_const_word32_buf_t iv,
crypto_const_byte_buf_t aad,
aead_gcm_tag_len_t tag_len,
crypto_byte_buf_t *ciphertext,
crypto_byte_buf_t *auth_tag);
sw/device/lib/crypto/include/aes.h#L224:
/**
* Performs the AES-GCM authenticated decryption operation.
*
* This function first verifies if the authentication tag `auth_tag`
* matches the internally generated tag. Upon verification, the
* function decrypts the input `ciphertext` to get a `plaintext data.
*
* The caller should allocate space for the `plaintext` buffer,
* (same length as ciphertext), and set the length of expected output
* in the `len` field of `plaintext`. If the user-set length and the
* output length does not match, an error message will be returned.
*
* The caller must check the `success` argument before operating on
* `plaintext`. If the authentication check fails, then `plaintext` should not
* be used and there are no guarantees about its contents.
*
* @param key Pointer to the blinded gcm-key struct.
* @param ciphertext Input data to be decrypted.
* @param iv Initialization vector for the decryption function.
* @param aad Additional authenticated data.
* @param tag_len Length of authentication tag to be generated.
* @param auth_tag Authentication tag to be verified.
* @param[out] plaintext Decrypted plaintext data, same len as input data.
* @param[out] success True if the authentication check passed, otherwise false.
* @return Result of the authenticated decryption.
* operation
*/
crypto_status_t otcrypto_aes_decrypt_gcm(
const crypto_blinded_key_t *key, crypto_const_byte_buf_t ciphertext,
crypto_const_word32_buf_t iv, crypto_const_byte_buf_t aad,
aead_gcm_tag_len_t tag_len, crypto_const_byte_buf_t auth_tag,
crypto_byte_buf_t *plaintext, hardened_bool_t *success);
GCM - GHASH and GCTR
sw/device/lib/crypto/include/aes.h#L246:
/**
* Internal GHASH operation of Galois Counter Mode (GCM).
*
* GHASH is an operation internal to GCM. It can be used to create
* custom implementations that do not adhere to the AES-GCM encryption
* and decryption API provided here. However, custom GCM constructs
* can be dangerous; for most use cases, prefer the provided
* encryption and decryption operations.
*
* This function initializes the GHASH context and must be called
* to create a context object.
*
* @param hash_subkey Hash subkey (H), 16 bytes.
* @param[out] ctx Output GHASH context object, caller-allocated.
* @return Result of the operation.
*/
crypto_status_t otcrypto_gcm_ghash_init(const crypto_blinded_key_t *hash_subkey,
gcm_ghash_context_t *ctx);
sw/device/lib/crypto/include/aes.h#L267:
/**
* Internal GHASH operation of Galois Counter Mode (GCM).
*
* GHASH is an operation internal to GCM. It can be used to create
* custom implementations that do not adhere to the AES-GCM encryption
* and decryption API provided here. However, custom GCM constructs
* can be dangerous; for most use cases, prefer the provided
* encryption and decryption operations.
*
* This operation adds the input buffer to the message that will
* be hashed and updates the GHASH context. If the input length is
* not a multiple of 128 bits, it will be right-padded with zeros.
* The input length must not be zero.
*
* @param ctx GHASH context object.
* @param input Input buffer.
* @return Result of the operation.
*/
crypto_status_t otcrypto_gcm_ghash_update(gcm_ghash_context_t *ctx,
crypto_const_byte_buf_t input);
sw/device/lib/crypto/include/aes.h#L287:
/**
* Internal GHASH operation of Galois Counter Mode (GCM).
*
* GHASH is an operation internal to GCM. It can be used to create
* custom implementations that do not adhere to the AES-GCM encryption
* and decryption API provided here. However, custom GCM constructs
* can be dangerous; for most use cases, prefer the provided
* encryption and decryption operations.
*
* This operation signals that all input has been provided and
* extracts the digest from the GHASH context. The digest buffer must
* be 16 bytes.
*
* @param ctx GHASH context object.
* @param[out] digest Output buffer for digest, 16 bytes.
* @return Result of the operation.
*/
crypto_status_t otcrypto_gcm_ghash_final(gcm_ghash_context_t *ctx,
crypto_word32_buf_t digest);
sw/device/lib/crypto/include/aes.h#L308:
/**
* Internal AES-GCTR operation of AES Galois Counter Mode (AES-GCM).
*
* GCTR is an operation internal to AES-GCM and is based on AES-CTR.
* It can be used to create custom implementations that do not adhere
* to the AES-GCM encryption and decryption API provided here.
* However, custom GCM constructs can be dangerous; for most use
* cases, prefer the provided encryption and decryption operations.
*
* The caller-allocated output buffer must be the same length as the
* input.
*
* @param key AES key for the GCTR operation.
* @param icb Initial counter block.
* @param input Input buffer.
* @param[out] output Output buffer (same length as input).
* @return Result of the operation.
*/
crypto_status_t otcrypto_aes_gcm_gctr(const crypto_blinded_key_t *key,
crypto_const_word32_buf_t icb,
crypto_const_byte_buf_t input,
crypto_byte_buf_t output);
AES-KWP
AES Key Wrapping with Padding (KWP) is an authenticated encryption scheme designed for encrypting cryptographic keys. AES-KWP is specified in NIST SP800-38F.
sw/device/lib/crypto/include/aes.h#L329:
/**
* Performs the AES-KWP authenticated encryption operation.
*
* This encrypt function takes an input key `key_to_wrap` and using
* the encryption key `key_kek` outputs a wrapped key `wrapped_key`.
*
* The caller should allocate space for the `wrapped_key` buffer,
* (same len as `key_to_wrap`), and set the length of expected output
* in the `len` field of `wrapped_key`. If the user-set length and the
* output length does not match, an error message will be returned.
*
* @param key_to_wrap Pointer to the blinded key to be wrapped.
* @param key_kek Input Pointer to the blinded encryption key.
* @param[out] wrapped_key Pointer to the output wrapped key.
* @return Result of the aes-kwp encrypt operation.
*/
crypto_status_t otcrypto_aes_kwp_encrypt(
const crypto_blinded_key_t *key_to_wrap,
const crypto_blinded_key_t *key_kek, crypto_word32_buf_t *wrapped_key);
sw/device/lib/crypto/include/aes.h#L344:
/**
* Performs the AES-KWP authenticated decryption operation.
*
* This decrypt function takes a wrapped key `wrapped_key` and using
* encryption key `key_kek` outputs an unwrapped key `unwrapped_key`.
*
* @param wrapped_key Pointer to the input wrapped key.
* @param key_kek Input Pointer to the blinded encryption key.
* @param[out] unwrapped_key Pointer to the output unwrapped key struct.
* @return Result of the aes-kwp decrypt operation.
*/
crypto_status_t otcrypto_aes_kwp_decrypt(crypto_const_word32_buf_t wrapped_key,
const crypto_blinded_key_t *key_kek,
crypto_blinded_key_t *unwrapped_key);
Hash functions
OpenTitan’s KMAC block supports the fixed digest length SHA3[224, 256, 384, 512] cryptographic hash functions, and the extendable-output functions of variable digest length SHAKE[128, 256] and cSHAKE[128, 256].
SHA-2 functions are supported by OTBN, and one-shot SHA-256 is supported by the HMAC block The OpenTitan cryptolib supports SHA2-256, SHA2-384, and SHA2-512. For SHA2 only, the hash API supports both one-shot and streaming modes of operation.
Note that hardware support for one-shot SHA-256 means that the one-shot version will be significantly faster than streaming mode for that specific algorithm.
One-shot mode
This mode is used when the entire data to be hashed is available upfront.
This is a generic hash API where the required digest type and length is passed as an input parameter. The supported hash modes are SHA256, SHA384, SHA512, SHA3-224, SHA3-256, SHA3-384 and SHA3-512.
sw/device/lib/crypto/include/hash.h#L90:
/**
* Performs the required hash function on the input data.
*
* The caller should allocate space for the `digest` buffer, (expected
* length depends on `hash_mode`, refer table above), and set the
* length of expected output in the `len` field of `digest`. If the
* user-set length and the output length does not match, an error
* message will be returned.
*
* This function hashes the `input_message` using the `hash_mode_t`
* hash function and returns a `digest`.
*
* @param input_message Input message to be hashed.
* @param hash_mode Required hash mode for the digest.
* @param[out] digest Output digest after hashing the input message.
* @return Result of the hash operation.
*/
crypto_status_t otcrypto_hash(crypto_const_byte_buf_t input_message,
hash_mode_t hash_mode,
crypto_word32_buf_t *digest);
The cryptolib supports the SHAKE and cSHAKE extendable-output functions, which can produce a varaible-sized digest. To avoid locking up the KMAC block, only a one-shot mode is supported.
sw/device/lib/crypto/include/hash.h#L119:
/**
* Performs the required extendable output function on the input data.
*
* The `function_name_string` is used by NIST to define functions
* based on cSHAKE. When no function other than cSHAKE is desired; it
* can be empty. The `customization_string` is used to define a
* variant of the cSHAKE function. If no customization is desired it
* can be empty. The `function_name_string` and `customization_string`
* are ignored when the `xof_mode` is set to kHashModeSha3Shake128 or
* kHashModeSha3Shake256.
*
* The caller should allocate space for the `digest` buffer, with a word-length
* long enough to hold `required_output_len`, and set the `len` field of
* `digest` to the word-length of the allocated buffer. If the `len` field of
* digest does not match `required_output_len`, the function will return an
* error.
*
* @param input_message Input message for extendable output function.
* @param xof_mode Required extendable output function.
* @param function_name_string NIST Function name string.
* @param customization_string Customization string for cSHAKE.
* @param required_output_len Required output length, in bytes.
* @param[out] digest Output from the extendable output function.
* @return Result of the xof operation.
*/
crypto_status_t otcrypto_xof(crypto_const_byte_buf_t input_message,
xof_mode_t xof_mode,
crypto_const_byte_buf_t function_name_string,
crypto_const_byte_buf_t customization_string,
size_t required_output_len,
crypto_word32_buf_t *digest);
Streaming mode
The streaming mode API is used for incremental hashing, where the data to be hashed is split and passed in multiple blocks. Streaming is supported only for SHA2 hash modes (SHA256, SHA384, SHA512), because these hash functions are implemented in software and their state can therefore be saved without locking up hardware blocks. Attempting to use the streaming API for SHA3 will result in an error.
sw/device/lib/crypto/include/hash.h#L143:
/**
* Performs the INIT operation for a cryptographic hash function.
*
* Initializes the generic hash context. The required hash mode is
* selected through the `hash_mode` parameter. Only `kHashModeSha256`,
* `kHashModeSha384` and `kHashModeSha512` are supported. Other modes
* are not supported and an error would be returned.
*
* Populates the hash context with the selected hash mode and its
* digest and block sizes. The structure of hash context and how it
* populates the required fields are internal to the specific hash
* implementation.
*
* @param ctx Pointer to the generic hash context struct.
* @param hash_mode Required hash mode.
* @return Result of the hash init operation.
*/
crypto_status_t otcrypto_hash_init(hash_context_t *const ctx,
hash_mode_t hash_mode);
sw/device/lib/crypto/include/hash.h#L160:
/**
* Performs the UPDATE operation for a cryptographic hash function.
*
* The update operation processes the `input_message` using the selected
* hash compression function. The intermediate digest is stored in the
* context `ctx`. Any partial data is stored back in the context and
* combined with the subsequent bytes.
*
* #otcrypto_hash_init should be called before this function.
*
* @param ctx Pointer to the generic hash context struct.
* @param input_message Input message to be hashed.
* @return Result of the hash update operation.
*/
crypto_status_t otcrypto_hash_update(hash_context_t *const ctx,
crypto_const_byte_buf_t input_message);
sw/device/lib/crypto/include/hash.h#L181:
/**
* Performs the FINAL operation for a cryptographic hash function.
*
* The final operation processes the remaining partial blocks,
* computes the final hash and copies it to the `digest` parameter.
*
* #otcrypto_hash_update should be called before this function.
*
* The caller should allocate space for the `digest` buffer, (expected
* length depends on `hash_mode`, refer table-1), and set the length
* of expected output in the `len` field of `digest`. If the user-set
* length and the output length does not match, an error message will
* be returned.
*
* @param ctx Pointer to the generic hash context struct.
* @param[out] digest Output digest after hashing the input blocks.
* @return Result of the hash final operation.
*/
crypto_status_t otcrypto_hash_final(hash_context_t *const ctx,
crypto_word32_buf_t *digest);
Message Authentication
OpenTitan supports two kinds of message authentication codes (MACs):
- HMAC, a simple construction based on cryptographic hash functions
- KMAC, a Keccak-based MAC
OpenTitan’s HMAC block supports HMAC-SHA256 with a key length of 256 bits. The KMAC block supports KMAC128 and KMAC256, with a key length of 128, 192, 256, 384, or 512 bits.
Key Generation
Given a key configuration, generate an HMAC or KMAC key. The key may be either randomly generated or derived using the key manager, depending on the configuration.
sw/device/lib/crypto/include/mac.h#L59:
/**
* Generates a new HMAC or KMAC key.
*
* The caller should allocate and partially populate the blinded key struct,
* including populating the key configuration and allocating space for the
* keyblob. The caller should indicate the length of the allocated keyblob;
* this function will return an error if the keyblob length does not match
* expectations. For hardware-backed keys, the keyblob length is 0 and the
* keyblob pointer may be `NULL`. For non-hardware-backed keys, the keyblob
* should be twice the length of the key. The value in the `checksum` field of
* the blinded key struct will be populated by the key generation function.
*
* @param[out] key Destination blinded key struct.
* @return The result of the key generation operation.
*/
crypto_status_t otcrypto_mac_keygen(crypto_blinded_key_t *key);
One-shot mode
sw/device/lib/crypto/include/mac.h#L75:
/**
* Performs the HMAC-SHA256 function on the input data.
*
* This function computes the HMAC-SHA256 function on the `input_message`
* using the `key` and returns a `tag`.
*
* The caller should allocate 32 bytes (8 32-bit words) of space for the `tag`
* buffer and set its `len` field to 8.
*
* @param key Pointer to the blinded key struct with key shares.
* @param input_message Input message to be hashed.
* @param[out] tag Output authentication tag.
* @return The result of the HMAC operation.
*/
crypto_status_t otcrypto_hmac(const crypto_blinded_key_t *key,
crypto_const_byte_buf_t input_message,
crypto_word32_buf_t *tag);
sw/device/lib/crypto/include/mac.h#L101:
/**
* Performs the KMAC function on the input data.
*
* This function computes the KMAC on the `input_message` using the `key` and
* returns a `tag` of `required_output_len`. The customization string is passed
* through `customization_string` parameter. If no customization is desired it
* can be empty.
*
* The caller should allocate enough space in the `tag` buffer to hold
* `required_output_len` bytes, rounded up to the nearest word, and then set
* the `len` field of `tag` to the word length. If the word length is not long
* enough to hold `required_output_len` bytes, then the function will return an
* error.
*
* @param key Pointer to the blinded key struct with key shares.
* @param input_message Input message to be hashed.
* @param mac_mode Required KMAC mode.
* @param customization_string Customization string.
* @param required_output_len Required output length, in bytes.
* @param[out] tag Output authentication tag.
* @return The result of the KMAC operation.
*/
crypto_status_t otcrypto_kmac(const crypto_blinded_key_t *key,
crypto_const_byte_buf_t input_message,
kmac_mode_t kmac_mode,
crypto_const_byte_buf_t customization_string,
size_t required_output_len,
crypto_word32_buf_t *tag);
Streaming mode
The streaming mode API is used for incremental hashing use-case, where the data to be hashed is split and passed in multiple blocks.
To avoid locking up the KMAC hardware, the streaming mode is supported only for HMAC.
sw/device/lib/crypto/include/mac.h#L124:
/**
* Performs the INIT operation for HMAC.
*
* Initializes the generic HMAC context. The required HMAC mode is selected
* through the `hmac_mode` parameter. The structure of HMAC context and how it
* populates the required fields based on the HMAC mode are internal to the
* specific HMAC implementation.
*
* The HMAC streaming API supports only the `kMacModeHmacSha256` mode. Other
* modes are not supported and an error would be returned. The interface is
* designed to be generic to support other required modes in the future.
*
* @param ctx Pointer to the generic HMAC context struct.
* @param key Pointer to the blinded HMAC key struct.
* @return Result of the HMAC init operation.
*/
crypto_status_t otcrypto_hmac_init(hmac_context_t *ctx,
const crypto_blinded_key_t *key);
sw/device/lib/crypto/include/mac.h#L141:
/**
* Performs the UPDATE operation for HMAC.
*
* The update operation processes the `input_message` using the selected
* compression function. The intermediate state is stored in the HMAC context
* `ctx`. Any partial data is stored back in the context and combined with the
* subsequent bytes.
*
* #otcrypto_hmac_init should be called before calling this function.
*
* @param ctx Pointer to the generic HMAC context struct.
* @param input_message Input message to be hashed.
* @return Result of the HMAC update operation.
*/
crypto_status_t otcrypto_hmac_update(hmac_context_t *const ctx,
crypto_const_byte_buf_t input_message);
sw/device/lib/crypto/include/mac.h#L161:
/**
* Performs the FINAL operation for HMAC.
*
* The final operation processes the remaining partial blocks, computes the
* final authentication code and copies it to the `tag` parameter.
*
* #otcrypto_hmac_update should be called before calling this function.
*
* The caller should allocate space for the `tag` buffer, (expected length is
* 32 bytes = 8 32-bit words for HMAC), and set the length of expected output
* in the `len` field of `tag`. If the user-set length and the output length
* does not match, an error message will be returned.
*
* @param ctx Pointer to the generic HMAC context struct.
* @param[out] tag Output authentication tag.
* @return Result of the HMAC final operation.
*/
crypto_status_t otcrypto_hmac_final(hmac_context_t *const ctx,
crypto_word32_buf_t *tag);
RSA
RSA (Rivest-Shamir-Adleman) is a family of asymmetric cryptographic algorithms supporting signatures and encryption. OpenTitan uses the OpenTitan Big Number Accelerator to speed up RSA operations.
OpenTitan supports RSA key generation, signature generation, and signature verification for modulus lengths of 2048, 3072, and 4096 bits. Supported padding schemes are defined in the rsa_padding_t structure in this section.
All RSA operations may be run asynchronously through a dedicated asynchronous API.
Security considerations
RSA signatures use a hash function to compress the input message and a padding scheme to pad them to the length of the modulus. The algorithm can theoretically accept virtually any hash function or padding scheme, but not all are safe to use. In general, the hash function needs to have collision resistance that is at least as strong as the security strength of the RSA scheme.
NIST SP800-57 specifies security strength for RSA as follows (table 2):
Security strength | RSA modulus length |
---|---|
<= 80 bits | 1024 |
112 bits | 2048 |
128 bits | 3072 |
192 bits | 7680 |
Hash function collision resistance strengths are in the same document (table 3). Usually, the collision resistance of a hash function is half the length of its digest. For example, SHA-256 has a 256-bit digest and 128-bit strength for collision resistance.
Supported hashing modes are defined in the rsa_hash_t structure in this section. The cryptolib will return an error if the hash function lacks enough collision resistance for the RSA length.
Padding schemes are frequently critical for RSA security, and using RSA without a well-established padding scheme is very risky. Always ensure that you fully understand the security implications of the padding scheme you choose.
RSA Synchronous API
sw/device/lib/crypto/include/rsa.h#L110:
/**
* Performs the RSA key generation.
*
* Computes RSA private key (d) and RSA public key exponent (e) and
* modulus (n).
*
* The caller should allocate and partially populate all blinded and unblinded
* key structs underneath `rsa_private_key` and `rsa_public_key`.
*
* For unblinded keys, this means setting the key mode, allocating a buffer for
* the key material, and recording the length of the allocated buffer in
* `key_length`. If the buffer size does not match expectations, this function
* will return an error. RSA public key exponents should always have 32 bits (4
* bytes) allocated for them.
*
* For blinded key structs, the caller should fully populate the key
* configuration and allocate space for the keyblob. As for unblinded keys, the
* caller should record the allocated buffer length and this function will
* return an error if the keyblob length does not match expectations. The
* keyblob should be twice the length of the key.
*
* The value in the `checksum` field of key structs is not checked here and
* will be populated by the key generation function.
*
* @param required_key_len Requested key length.
* @param[out] rsa_public_key Pointer to RSA public exponent struct.
* @param[out] rsa_private_key Pointer to RSA private exponent struct.
* @return Result of the RSA key generation.
*/
crypto_status_t otcrypto_rsa_keygen(rsa_key_size_t required_key_len,
rsa_public_key_t *rsa_public_key,
rsa_private_key_t *rsa_private_key);
sw/device/lib/crypto/include/rsa.h#L130:
/**
* Computes the digital signature on the input message data.
*
* The caller should allocate space for the `signature` buffer,
* (expected length same as modulus length from `rsa_private_key`),
* and set the length of expected output in the `len` field of
* `signature`. If the user-set length and the output length does not
* match, an error message will be returned.
*
* @param rsa_private_key Pointer to RSA private exponent struct.
* @param input_message Input message to be signed.
* @param padding_mode Padding scheme to be used for the data.
* @param hash_mode Hashing mode to be used for the signature.
* @param[out] signature Pointer to the generated signature struct.
* @return The result of the RSA signature generation.
*/
crypto_status_t otcrypto_rsa_sign(const rsa_private_key_t *rsa_private_key,
crypto_const_byte_buf_t input_message,
rsa_padding_t padding_mode,
rsa_hash_t hash_mode,
crypto_word32_buf_t *signature);
sw/device/lib/crypto/include/rsa.h#L151:
/**
* Verifies the authenticity of the input signature.
*
* The generated signature is compared against the input signature and
* PASS / FAIL is returned.
*
* @param rsa_public_key Pointer to RSA public exponent struct.
* @param input_message Input message to be signed for verification.
* @param padding_mode Padding scheme to be used for the data.
* @param hash_mode Hashing mode to be used for signature verification.
* @param signature Pointer to the input signature to be verified.
* @param[out] verification_result Result of signature verification
* (Pass/Fail).
* @return Result of the RSA verify operation.
*/
crypto_status_t otcrypto_rsa_verify(const rsa_public_key_t *rsa_public_key,
crypto_const_byte_buf_t input_message,
rsa_padding_t padding_mode,
rsa_hash_t hash_mode,
crypto_const_word32_buf_t signature,
hardened_bool_t *verification_result);
RSA Asynchronous API
sw/device/lib/crypto/include/rsa.h#L171:
/**
* Starts the asynchronous RSA key generation function.
*
* Initializes OTBN and starts the OTBN routine to compute the RSA
* private key (d), RSA public key exponent (e) and modulus (n).
*
* Returns `kCryptoStatusOK` if the operation was successfully
* started, or`kCryptoStatusInternalError` if the operation cannot be
* started.
*
* @param required_key_len Requested key length.
* @return Result of async RSA keygen start operation.
*/
crypto_status_t otcrypto_rsa_keygen_async_start(
rsa_key_size_t required_key_len);
sw/device/lib/crypto/include/rsa.h#L186:
/**
* Finalizes the asynchronous RSA key generation function.
*
* Returns `kCryptoStatusOK` and copies the RSA private key (d), RSA
* public key exponent (e) and modulus (n) if the OTBN status is done,
* or `kCryptoStatusAsyncIncomplete` if the OTBN is busy or
* `kCryptoStatusInternalError` if there is an error.
*
* @param[out] rsa_public_key Pointer to RSA public exponent struct.
* @param[out] rsa_private_key Pointer to RSA private exponent struct.
* @return Result of asynchronous RSA keygen finalize operation.
*/
crypto_status_t otcrypto_rsa_keygen_async_finalize(
rsa_public_key_t *rsa_public_key, rsa_private_key_t *rsa_private_key);
sw/device/lib/crypto/include/rsa.h#L205:
/**
* Starts the asynchronous digital signature generation function.
*
* Initializes OTBN and starts the OTBN routine to compute the digital
* signature on the input message.
*
* Returns `kCryptoStatusOK` if the operation was successfully
* started, or`kCryptoStatusInternalError` if the operation cannot be
* started.
*
* @param rsa_private_key Pointer to RSA private exponent struct.
* @param input_message Input message to be signed.
* @param padding_mode Padding scheme to be used for the data.
* @param hash_mode Hashing scheme to be used for the signature scheme.
* @return Result of async RSA sign start operation.
*/
crypto_status_t otcrypto_rsa_sign_async_start(
const rsa_private_key_t *rsa_private_key,
crypto_const_byte_buf_t input_message, rsa_padding_t padding_mode,
rsa_hash_t hash_mode);
sw/device/lib/crypto/include/rsa.h#L226:
/**
* Finalizes the asynchronous digital signature generation function.
*
* Returns `kCryptoStatusOK` and copies the signature if the OTBN
* status is done, or `kCryptoStatusAsyncIncomplete` if the OTBN is
* busy or `kCryptoStatusInternalError` if there is an error.
*
* The caller should allocate space for the `signature` buffer,
* (expected length same as modulus length from `rsa_private_key`),
* and set the length of expected output in the `len` field of
* `signature`. If the user-set length and the output length does not
* match, an error message will be returned.
*
* @param[out] signature Pointer to generated signature struct.
* @return Result of async RSA sign finalize operation.
*/
crypto_status_t otcrypto_rsa_sign_async_finalize(
crypto_word32_buf_t *signature);
sw/device/lib/crypto/include/rsa.h#L239:
/**
* Starts the asynchronous signature verification function.
*
* Initializes OTBN and starts the OTBN routine to recover the message
* from the input signature.
*
* @param rsa_public_key Pointer to RSA public exponent struct.
* @param signature Pointer to the input signature to be verified.
* @return Result of async RSA verify start operation.
*/
crypto_status_t otcrypto_rsa_verify_async_start(
const rsa_public_key_t *rsa_public_key,
crypto_const_word32_buf_t signature);
sw/device/lib/crypto/include/rsa.h#L259:
/**
* Finalizes the asynchronous signature verification function.
*
* Returns `kCryptoStatusOK` and populates the `verification result`
* if the OTBN status is done, or `kCryptoStatusAsyncIncomplete` if
* OTBN is busy or `kCryptoStatusInternalError` if there is an error.
* The (hash of) recovered message is compared against the input
* message and a PASS or FAIL is returned.
*
* @param input_message Input message to be signed for verification.
* @param padding_mode Padding scheme to be used for the data.
* @param hash_mode Hashing scheme to be used for the signature scheme.
* @param[out] verification_result Result of signature verification
* (Pass/Fail).
* @return Result of async RSA verify finalize operation.
*/
crypto_status_t otcrypto_rsa_verify_async_finalize(
crypto_const_byte_buf_t input_message, rsa_padding_t padding_mode,
rsa_hash_t hash_mode, hardened_bool_t *verification_result);
Elliptic curve cryptography
Elliptic curve cryptography (ECC) refers to a wide range of asymmetric cryptography based on elliptic curve operations. It is widely used for key agreement and signature schemes. Compared to RSA, ECC uses much shorter key-lengths to provide equivalent security. OpenTitan uses the OpenTitan Big Number Accelerator to speed up ECC operations.
Elliptic-curve public keys are curve points; coordinates (x,y) that satisfy a particular equation that defines the curve. Elliptic curve private keys are scalar values, positive integers modulo the “curve order” (a large positive integer, usually denoted n). The specific value of n depends on the underlying curve.
All ECC operations may be run asynchronously through a dedicated asynchronous API.
Supported Curves
Elliptic curves of the short Weierstrass form, Montgomery form, and twisted Edward form are supported.
- For short Weierstrass form three predefined named curves are supported (NIST P-256, NIST P-384 and brainpool 256) along with support for user-defined generic curves.
- For the Montgomery form, only X25519 is supported.
- For twisted Edwards form only Ed25519 is supported.
Security considerations
ECC signatures typically require a hash function. To avoid degrading security, the collision resistance of the hash function should be at least as good as the security strength of the ECC scheme.
NIST SP800-57 specifies security strengths for ECC in table 2. The phrasing in that document is a bit cryptic, but essentially the security of ECC depends on the curve order, n. Usually the security is about n/2, but in some cases approximations are accepted. For example, the order of the edwards25519 curve is 253 bits, not 256, but FIPS standards specifically accept it as having “about 128 bits of security”. Below are security strengths for the curves supported by the OpenTitan cryptolib, as well as sources for those values.
Curve | Security strength | Schemes | Citation |
---|---|---|---|
P-256 | 128 bits | ECDSA-P256, ECDH-P256 | NIST SP800-57, table 2 |
P-384 | 192 bits | ECDSA-P384, ECDH-P384 | NIST SP800-57, table 2 |
edwards25519 | ~128 bits | Ed25519 | FIPS 186-5, section 7.1 |
curve25519 | ~128 bits | X25519 | same order as edwards25519 |
A note on understanding the table above: ECDSA signatures and ECDH key exchange can use the same underlying elliptic curve. However, Ed25519 and X25519 operate on different underlying curves, because EdDSA (the generic framework underlying Ed25519) requires a “twisted Edwards” form curve and X25519 requires a “Montgomery” form curve. The two curves are birationally equivalent, in mathematical terms, so it is possible (but not trivial) to convert points from one to the other.
ECC Synchronous API
ECDSA
For ECDSA, the cryptography library supports keypair generation, signing, and signature verification.
sw/device/lib/crypto/include/ecc.h#L133:
/**
* Performs the key generation for ECDSA operation.
*
* Computes private key (d) and public key (Q) keys for ECDSA operation.
*
* The caller should allocate and partially populate the blinded key struct,
* including populating the key configuration and allocating space for the
* keyblob. The caller should indicate the length of the allocated keyblob;
* this function will return an error if the keyblob length does not match
* expectations. For hardware-backed keys, the keyblob length is 0 and the
* keyblob pointer may be `NULL`. For non-hardware-backed keys, the keyblob
* should be twice the length of the key. The value in the `checksum` field of
* the blinded key struct will be populated by the key generation function.
*
* The `domain_parameter` field of the `elliptic_curve` is required only for a
* custom curve. For named curves this field is ignored and can be set to
* `NULL`.
*
* @param elliptic_curve Pointer to the elliptic curve to be used.
* @param[out] private_key Pointer to the blinded private key (d) struct.
* @param[out] public_key Pointer to the unblinded public key (Q) struct.
* @return Result of the ECDSA key generation.
*/
crypto_status_t otcrypto_ecdsa_keygen(const ecc_curve_t *elliptic_curve,
crypto_blinded_key_t *private_key,
ecc_public_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L151:
/**
* Performs the ECDSA digital signature generation.
*
* The `domain_parameter` field of the `elliptic_curve` is required
* only for a custom curve. For named curves this field is ignored
* and can be set to `NULL`.
*
* @param private_key Pointer to the blinded private key (d) struct.
* @param input_message Input message to be signed.
* @param elliptic_curve Pointer to the elliptic curve to be used.
* @param[out] signature Pointer to the signature struct with (r,s) values.
* @return Result of the ECDSA signature generation.
*/
crypto_status_t otcrypto_ecdsa_sign(const crypto_blinded_key_t *private_key,
crypto_const_byte_buf_t input_message,
const ecc_curve_t *elliptic_curve,
const ecc_signature_t *signature);
sw/device/lib/crypto/include/ecc.h#L172:
/**
* Performs the ECDSA digital signature verification.
*
* The `domain_parameter` field of the `elliptic_curve` is required
* only for a custom curve. For named curves this field is ignored
* and can be set to `NULL`.
*
* @param public_key Pointer to the unblinded public key (Q) struct.
* @param input_message Input message to be signed for verification.
* @param signature Pointer to the signature to be verified.
* @param elliptic_curve Pointer to the elliptic curve to be used.
* @param[out] verification_result Result of signature verification
* (Pass/Fail).
* @return Result of the ECDSA verification operation.
*/
crypto_status_t otcrypto_ecdsa_verify(const ecc_public_key_t *public_key,
crypto_const_byte_buf_t input_message,
const ecc_signature_t *signature,
const ecc_curve_t *elliptic_curve,
hardened_bool_t *verification_result);
ECDH
For ECDH (elliptic-curve Diffie-Hellman) key exchange, the cryptography library supports keypair generation and shared-key generation. Each party should generate a key pair, exchange public keys, and then generate the shared key using their own private key and the other party’s public key.
sw/device/lib/crypto/include/ecc.h#L202:
/**
* Performs the key generation for ECDH key agreement.
*
* Computes private key (d) and public key (Q) keys for ECDSA operation.
*
* The `domain_parameter` field of the `elliptic_curve` is required only for a
* custom curve. For named curves this field is ignored and can be set to
* `NULL`.
*
* The caller should allocate and partially populate the blinded key struct,
* including populating the key configuration and allocating space for the
* keyblob. The caller should indicate the length of the allocated keyblob;
* this function will return an error if the keyblob length does not match
* expectations. For hardware-backed keys, the keyblob length is 0 and the
* keyblob pointer may be `NULL`. For non-hardware-backed keys, the keyblob
* should be twice the length of the key. The value in the `checksum` field of
* the blinded key struct will be populated by the key generation function.
*
* @param elliptic_curve Pointer to the elliptic curve to be used.
* @param[out] private_key Pointer to the blinded private key (d) struct.
* @param[out] public_key Pointer to the unblinded public key (Q) struct.
* @return Result of the ECDH key generation.
*/
crypto_status_t otcrypto_ecdh_keygen(const ecc_curve_t *elliptic_curve,
crypto_blinded_key_t *private_key,
ecc_public_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L220:
/**
* Performs Elliptic Curve Diffie Hellman shared secret generation.
*
* The `domain_parameter` field of the `elliptic_curve` is required
* only for a custom curve. For named curves this field is ignored
* and can be set to `NULL`.
*
* @param private_key Pointer to the blinded private key (d) struct.
* @param public_key Pointer to the unblinded public key (Q) struct.
* @param elliptic_curve Pointer to the elliptic curve to be used.
* @param[out] shared_secret Pointer to generated blinded shared key struct.
* @return Result of ECDH shared secret generation.
*/
crypto_status_t otcrypto_ecdh(const crypto_blinded_key_t *private_key,
const ecc_public_key_t *public_key,
const ecc_curve_t *elliptic_curve,
crypto_blinded_key_t *shared_secret);
Ed25519
For Ed25519 (a curve-specialized version of EdDSA, the Edwards curve digital signature algorithm), the cryptography library supports keypair generation, signature generation, and signature verification. There is no need to specify curve parameters for Ed25519, since it operates on a specific curve already.
sw/device/lib/crypto/include/ecc.h#L247:
/**
* Generates a new Ed25519 key pair.
*
* Computes the private exponent (d) and public key (Q) based on
* Curve25519.
*
* No `domain_parameter` is needed and is automatically set for Ed25519.
*
* The caller should allocate and partially populate the blinded key struct,
* including populating the key configuration and allocating space for the
* keyblob. The caller should indicate the length of the allocated keyblob;
* this function will return an error if the keyblob length does not match
* expectations. For hardware-backed keys, the keyblob length is 0 and the
* keyblob pointer may be `NULL`. For non-hardware-backed keys, the keyblob
* should be twice the length of the key. The value in the `checksum` field of
* the blinded key struct will be populated by the key generation function.
*
* @param[out] private_key Pointer to the blinded private key struct.
* @param[out] public_key Pointer to the unblinded public key struct.
* @return Result of the Ed25519 key generation.
*/
crypto_status_t otcrypto_ed25519_keygen(crypto_blinded_key_t *private_key,
crypto_unblinded_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L260:
/**
* Generates an Ed25519 digital signature.
*
* @param private_key Pointer to the blinded private key struct.
* @param input_message Input message to be signed.
* @param sign_mode Parameter for EdDSA or Hash EdDSA sign mode.
* @param[out] signature Pointer to the EdDSA signature with (r,s) values.
* @return Result of the EdDSA signature generation.
*/
crypto_status_t otcrypto_ed25519_sign(const crypto_blinded_key_t *private_key,
crypto_const_byte_buf_t input_message,
eddsa_sign_mode_t sign_mode,
const ecc_signature_t *signature);
sw/device/lib/crypto/include/ecc.h#L277:
/**
* Verifies an Ed25519 signature.
*
* @param public_key Pointer to the unblinded public key struct.
* @param input_message Input message to be signed for verification.
* @param sign_mode Parameter for EdDSA or Hash EdDSA sign mode.
* @param signature Pointer to the signature to be verified.
* @param[out] verification_result Result of signature verification
* (Pass/Fail).
* @return Result of the EdDSA verification operation.
*/
crypto_status_t otcrypto_ed25519_verify(
const crypto_unblinded_key_t *public_key,
crypto_const_byte_buf_t input_message, eddsa_sign_mode_t sign_mode,
const ecc_signature_t *signature, hardened_bool_t *verification_result);
X25519
For x25519 key exchange, the cryptography library supports keypair generation and shared-key generation. Each party should generate a key pair, exchange public keys, and then generate the shared key using their own private key and the other party’s public key.
sw/device/lib/crypto/include/ecc.h#L304:
/**
* Generates a new key pair for X25519 key exchange.
*
* Computes the private scalar (d) and public key (Q) based on
* Curve25519.
*
* No `domain_parameter` is needed and is automatically set for X25519.
*
* The caller should allocate and partially populate the blinded key struct,
* including populating the key configuration and allocating space for the
* keyblob. The caller should indicate the length of the allocated keyblob;
* this function will return an error if the keyblob length does not match
* expectations. For hardware-backed keys, the keyblob length is 0 and the
* keyblob pointer may be `NULL`. For non-hardware-backed keys, the keyblob
* should be twice the length of the key. The value in the `checksum` field of
* the blinded key struct will be populated by the key generation function.
*
* @param[out] private_key Pointer to the blinded private key struct.
* @param[out] public_key Pointer to the unblinded public key struct.
* @return Result of the X25519 key generation.
*/
crypto_status_t otcrypto_x25519_keygen(crypto_blinded_key_t *private_key,
crypto_unblinded_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L316:
/**
* Performs the X25519 Diffie Hellman shared secret generation.
*
* @param private_key Pointer to blinded private key (u-coordinate).
* @param public_key Pointer to the public scalar from the sender.
* @param[out] shared_secret Pointer to shared secret key (u-coordinate).
* @return Result of the X25519 operation.
*/
crypto_status_t otcrypto_x25519(const crypto_blinded_key_t *private_key,
const crypto_unblinded_key_t *public_key,
crypto_blinded_key_t *shared_secret);
ECC Asynchronous API
ECDSA
sw/device/lib/crypto/include/ecc.h#L339:
/**
* Starts the asynchronous key generation for ECDSA operation.
*
* Initializes OTBN and starts the OTBN routine to compute the private
* key (d) and public key (Q) for ECDSA operation.
*
* The `domain_parameter` field of the `elliptic_curve` is required
* only for a custom curve. For named curves this field is ignored
* and can be set to `NULL`.
*
* Returns `kCryptoStatusOK` if the operation was successfully
* started, or`kCryptoStatusInternalError` if the operation cannot be
* started.
*
* @param elliptic_curve Pointer to the elliptic curve to be used.
* @param config Private key configuration.
* @return Result of asynchronous ECDSA keygen start operation.
*/
crypto_status_t otcrypto_ecdsa_keygen_async_start(
const ecc_curve_t *elliptic_curve, const crypto_key_config_t *config);
sw/device/lib/crypto/include/ecc.h#L361:
/**
* Finalizes the asynchronous key generation for ECDSA operation.
*
* Returns `kCryptoStatusOK` and copies the private key (d) and public
* key (Q), if the OTBN status is done, or
* `kCryptoStatusAsyncIncomplete` if the OTBN is busy or
* `kCryptoStatusInternalError` if there is an error.
*
* The caller must ensure that the `elliptic_curve` parameter matches the one
* that was previously passed to the corresponding `_start` function; a
* mismatch will cause inconsistencies. Similarly, the private key
* configuration must match the one originally passed to `_start`.
*
* @param elliptic_curve Pointer to the elliptic curve that is being used.
* @param[out] private_key Pointer to the blinded private key (d) struct.
* @param[out] public_key Pointer to the unblinded public key (Q) struct.
* @return Result of asynchronous ECDSA keygen finalize operation.
*/
crypto_status_t otcrypto_ecdsa_keygen_async_finalize(
const ecc_curve_t *elliptic_curve, crypto_blinded_key_t *private_key,
ecc_public_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L379:
/**
* Starts the asynchronous ECDSA digital signature generation.
*
* Initializes OTBN and starts the OTBN routine to compute the digital
* signature on the input message. The `domain_parameter` field of the
* `elliptic_curve` is required only for a custom curve. For named
* curves this field is ignored and can be set to `NULL`.
*
* @param private_key Pointer to the blinded private key (d) struct.
* @param input_message Input message to be signed.
* @param elliptic_curve Pointer to the elliptic curve to be used.
* @return Result of async ECDSA start operation.
*/
crypto_status_t otcrypto_ecdsa_sign_async_start(
const crypto_blinded_key_t *private_key,
crypto_const_byte_buf_t input_message, const ecc_curve_t *elliptic_curve);
sw/device/lib/crypto/include/ecc.h#L399:
/**
* Finalizes the asynchronous ECDSA digital signature generation.
*
* Returns `kCryptoStatusOK` and copies the signature if the OTBN
* status is done, or `kCryptoStatusAsyncIncomplete` if the OTBN is
* busy or `kCryptoStatusInternalError` if there is an error.
*
* The caller must ensure that the `elliptic_curve` parameter matches the one
* that was previously passed to the corresponding `_start` function; a
* mismatch will cause inconsistencies.
*
* @param elliptic_curve Pointer to the elliptic curve that is being used.
* @param[out] signature Pointer to the signature struct with (r,s) values.
* @return Result of async ECDSA finalize operation.
*/
crypto_status_t otcrypto_ecdsa_sign_async_finalize(
const ecc_curve_t *elliptic_curve, const ecc_signature_t *signature);
sw/device/lib/crypto/include/ecc.h#L417:
/**
* Starts the asynchronous ECDSA digital signature verification.
*
* Initializes OTBN and starts the OTBN routine to recover ‘r’ value
* from the input signature ‘s’ value. The `domain_parameter` field of
* `elliptic_curve` is required only for a custom curve. For named
* curves this field is ignored and can be set to `NULL`.
*
* @param public_key Pointer to the unblinded public key (Q) struct.
* @param input_message Input message to be signed for verification.
* @param signature Pointer to the signature to be verified.
* @param elliptic_curve Pointer to the elliptic curve to be used.
* @return Result of async ECDSA verify start function.
*/
crypto_status_t otcrypto_ecdsa_verify_async_start(
const ecc_public_key_t *public_key, crypto_const_byte_buf_t input_message,
const ecc_signature_t *signature, const ecc_curve_t *elliptic_curve);
sw/device/lib/crypto/include/ecc.h#L440:
/**
* Finalizes the asynchronous ECDSA digital signature verification.
*
* Returns `kCryptoStatusOK` and populates the `verification result`
* if the OTBN status is done. `kCryptoStatusAsyncIncomplete` if the
* OTBN is busy or `kCryptoStatusInternalError` if there is an error.
* The computed signature is compared against the input signature
* and a PASS or FAIL is returned.
*
* The caller must ensure that the `elliptic_curve` and `signature` parameters
* matches the ones that were previously passed to the corresponding `_start`
* function; a mismatch will cause inconsistencies.
*
* @param elliptic_curve Pointer to the elliptic curve that is being used.
* @param[out] verification_result Result of signature verification
* (Pass/Fail).
* @return Result of async ECDSA verify finalize operation.
*/
crypto_status_t otcrypto_ecdsa_verify_async_finalize(
const ecc_curve_t *elliptic_curve, const ecc_signature_t *signature,
hardened_bool_t *verification_result);
ECDH
sw/device/lib/crypto/include/ecc.h#L463:
/**
* Starts the asynchronous key generation for ECDH operation.
*
* Initializes OTBN and starts the OTBN routine to compute the private
* key (d) and public key (Q) for ECDH operation.
*
* The `domain_parameter` field of the `elliptic_curve` is required
* only for a custom curve. For named curves this field is ignored
* and can be set to `NULL`.
*
* Returns `kCryptoStatusOK` if the operation was successfully
* started, or`kCryptoStatusInternalError` if the operation cannot be
* started.
*
* @param elliptic_curve Pointer to the elliptic curve to be used.
* @param config Private key configuration.
* @return Result of asynchronous ECDH keygen start operation.
*/
crypto_status_t otcrypto_ecdh_keygen_async_start(
const ecc_curve_t *elliptic_curve, const crypto_key_config_t *config);
sw/device/lib/crypto/include/ecc.h#L485:
/**
* Finalizes the asynchronous key generation for ECDSA operation.
*
* Returns `kCryptoStatusOK` and copies the private key (d) and public
* key (Q), if the OTBN status is done, or
* `kCryptoStatusAsyncIncomplete` if the OTBN is busy or
* `kCryptoStatusInternalError` if there is an error.
*
* The caller must ensure that the `elliptic_curve` parameter matches the one
* that was previously passed to the corresponding `_start` function; a
* mismatch will cause inconsistencies. Similarly, the private key
* configuration must match the one originally passed to `_start`.
*
* @param elliptic_curve Pointer to the elliptic curve that is being used.
* @param[out] private_key Pointer to the blinded private key (d) struct.
* @param[out] public_key Pointer to the unblinded public key (Q) struct.
* @return Result of asynchronous ECDH keygen finalize operation.
*/
crypto_status_t otcrypto_ecdh_keygen_async_finalize(
const ecc_curve_t *elliptic_curve, crypto_blinded_key_t *private_key,
ecc_public_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L503:
/**
* Starts the asynchronous Elliptic Curve Diffie Hellman shared
* secret generation.
*
* The `domain_parameter` field of the `elliptic_curve` is required
* only for a custom curve. For named curves this field is ignored
* and can be set to `NULL`.
*
* @param private_key Pointer to the blinded private key (d) struct.
* @param public_key Pointer to the unblinded public key (Q) struct.
* @param elliptic_curve Pointer to the elliptic curve to be used.
* @return Result of async ECDH start operation.
*/
crypto_status_t otcrypto_ecdh_async_start(
const crypto_blinded_key_t *private_key, const ecc_public_key_t *public_key,
const ecc_curve_t *elliptic_curve);
sw/device/lib/crypto/include/ecc.h#L524:
/**
* Finalizes the asynchronous Elliptic Curve Diffie Hellman shared
* secret generation.
*
* Returns `kCryptoStatusOK` and copies `shared_secret` if the OTBN
* status is done, or `kCryptoStatusAsyncIncomplete` if the OTBN
* is busy or `kCryptoStatusInternalError` if there is an error.
*
* The caller must ensure that the `elliptic_curve` parameter matches the one
* that was previously passed to the corresponding `_start` function; a
* mismatch will cause inconsistencies.
*
* @param elliptic_curve Pointer to the elliptic curve that is being used.
* @param[out] shared_secret Pointer to generated blinded shared key struct.
* @return Result of async ECDH finalize operation.
*/
crypto_status_t otcrypto_ecdh_async_finalize(
const ecc_curve_t *elliptic_curve, crypto_blinded_key_t *shared_secret);
Ed25519
sw/device/lib/crypto/include/ecc.h#L539:
/**
* Starts the asynchronous key generation for Ed25519.
*
* Initializes OTBN and starts the OTBN routine to compute the private
* exponent (d) and public key (Q) based on Curve25519.
*
* No `domain_parameter` is needed and is automatically set for X25519.
*
* @param config Private key configuration.
* @return Result of asynchronous ed25519 keygen start operation.
*/
crypto_status_t otcrypto_ed25519_keygen_async_start(
const crypto_key_config_t *config);
sw/device/lib/crypto/include/ecc.h#L558:
/**
* Finalizes the asynchronous key generation for Ed25519.
*
* Returns `kCryptoStatusOK` and copies private key (d) and public key
* (Q), if the OTBN status is done, or `kCryptoStatusAsyncIncomplete`
* if the OTBN is busy or `kCryptoStatusInternalError` if there is an
* error.
*
* The caller must ensure that `config` matches the key configuration initially
* passed to the `_start` complement of this function.
*
* @param[out] private_key Pointer to the blinded private key struct.
* @param[out] public_key Pointer to the unblinded public key struct.
* @return Result of asynchronous ed25519 keygen finalize operation.
*/
crypto_status_t otcrypto_ed25519_keygen_async_finalize(
crypto_blinded_key_t *private_key, crypto_unblinded_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L575:
/**
* Starts the asynchronous Ed25519 digital signature generation.
*
* Initializes OTBN and starts the OTBN routine to compute the digital
* signature on the input message. The `domain_parameter` field for
* Ed25519 is automatically set.
*
* @param private_key Pointer to the blinded private key struct.
* @param input_message Input message to be signed.
* @param sign_mode Parameter for EdDSA or Hash EdDSA sign mode.
* @param[out] signature Pointer to the EdDSA signature to get (r) value.
* @return Result of async Ed25519 start operation.
*/
crypto_status_t otcrypto_ed25519_sign_async_start(
const crypto_blinded_key_t *private_key,
crypto_const_byte_buf_t input_message, eddsa_sign_mode_t sign_mode,
const ecc_signature_t *signature);
sw/device/lib/crypto/include/ecc.h#L591:
/**
* Finalizes the asynchronous Ed25519 digital signature generation.
*
* Returns `kCryptoStatusOK` and copies the signature if the OTBN
* status is done, or `kCryptoStatusAsyncIncomplete` if the OTBN is
* busy or `kCryptoStatusInternalError` if there is an error.
*
* @param[out] signature Pointer to the EdDSA signature to get (s) value.
* @return Result of async Ed25519 finalize operation.
*/
crypto_status_t otcrypto_ed25519_sign_async_finalize(
const ecc_signature_t *signature);
sw/device/lib/crypto/include/ecc.h#L607:
/**
* Starts the asynchronous Ed25519 digital signature verification.
*
* Initializes OTBN and starts the OTBN routine to verify the
* signature. The `domain_parameter` for Ed25519 is set automatically.
*
* @param public_key Pointer to the unblinded public key struct.
* @param input_message Input message to be signed for verification.
* @param sign_mode Parameter for EdDSA or Hash EdDSA sign mode.
* @param signature Pointer to the signature to be verified.
* @return Result of async Ed25519 verification start operation.
*/
crypto_status_t otcrypto_ed25519_verify_async_start(
const crypto_unblinded_key_t *public_key,
crypto_const_byte_buf_t input_message, eddsa_sign_mode_t sign_mode,
const ecc_signature_t *signature);
sw/device/lib/crypto/include/ecc.h#L625:
/**
* Finalizes the asynchronous Ed25519 digital signature verification.
*
* Returns `kCryptoStatusOK` and populates the `verification result`
* with a PASS or FAIL, if the OTBN status is done,
* `kCryptoStatusAsyncIncomplete` if the OTBN is busy or
* `kCryptoStatusInternalError` if there is an error.
*
* @param[out] verification_result Result of signature verification
* (Pass/Fail).
* @return Result of async Ed25519 verification finalize operation.
*/
crypto_status_t otcrypto_ed25519_verify_async_finalize(
hardened_bool_t *verification_result);
X25519
sw/device/lib/crypto/include/ecc.h#L640:
/**
* Starts the asynchronous key generation for X25519.
*
* Initializes OTBN and starts the OTBN routine to compute the private
* exponent (d) and public key (Q) based on Curve25519.
*
* No `domain_parameter` is needed and is automatically set for X25519.
*
* @param config Private key configuration.
* @return Result of asynchronous X25519 keygen start operation.
*/
crypto_status_t otcrypto_x25519_keygen_async_start(
const crypto_key_config_t *config);
sw/device/lib/crypto/include/ecc.h#L659:
/**
* Finalizes the asynchronous key generation for X25519.
*
* Returns `kCryptoStatusOK` and copies private key (d) and public key
* (Q), if the OTBN status is done, or `kCryptoStatusAsyncIncomplete`
* if the OTBN is busy or `kCryptoStatusInternalError` if there is an
* error.
*
* The caller must ensure that `config` matches the key configuration initially
* passed to the `_start` complement of this function.
*
* @param[out] private_key Pointer to the blinded private key struct.
* @param[out] public_key Pointer to the unblinded public key struct.
* @return Result of asynchronous X25519 keygen finalize operation.
*/
crypto_status_t otcrypto_x25519_keygen_async_finalize(
crypto_blinded_key_t *private_key, crypto_unblinded_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L675:
/**
* Starts the asynchronous X25519 Diffie Hellman shared secret
* generation.
*
* Initializes OTBN and starts the OTBN routine to perform Diffie
* Hellman shared secret generation based on Curve25519. The
* domain parameter is automatically set for X25519 API.
*
* @param private_key Pointer to the blinded private key (u-coordinate).
* @param public_key Pointer to the public scalar from the sender.
* @return Result of the async X25519 start operation.
*/
crypto_status_t otcrypto_x25519_async_start(
const crypto_blinded_key_t *private_key,
const crypto_unblinded_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L691:
/**
* Finalizes the asynchronous X25519 Diffie Hellman shared secret
* generation.
*
* Returns `kCryptoStatusOK` and copies `shared_secret` if the OTBN
* status is done, or `kCryptoStatusAsyncIncomplete` if the OTBN
* is busy or `kCryptoStatusInternalError` if there is an error.
*
* @param[out] shared_secret Pointer to shared secret key (u-coordinate).
* @return Result of async X25519 finalize operation.
*/
crypto_status_t otcrypto_x25519_async_finalize(
crypto_blinded_key_t *shared_secret);
Deterministic random bit generation
OpenTitan’s random bit generator, CSRNG (Cryptographically Secure Random Number Generator) uses a block cipher based deterministic random bit generation (DRBG) mechanism (AES-CTR-DRBG) as specified in NIST SP800-90A. OpenTitan’s RNG targets compliance with both BSI AIS31 recommendations for Common Criteria, as well as NIST SP800-90A and NIST SP800-90C (second draft). The CSRNG operates at a 256-bit security strength.
Seeding the DRBG
The DRBG can be seeded with new entropy from OpenTitan’s hardware entropy source, mixed with additional caller-provided entropy if desired. It is also possible to instantiate or reseed the DRBG with only caller-provided entropy (“manual instantiate” and “manual reseed”). This is useful for testing, but undermines security guarantees and FIPS compliance until the DRBG is uninstantiated again, so it is best to use these operations with caution.
To learn more about DRBG details such as entropy requirements, seed construction, derivation functions and prediction resistance, please refer to the NIST SP800-90A, NIST SP800-90B, NIST SP800-90C, and BSI AIS31 documents and the links in the reference section.
DRBG API
sw/device/lib/crypto/include/drbg.h#L28:
/**
* Instantiates the DRBG system.
*
* Initializes the DRBG and the context for DRBG. Gets the required
* entropy input automatically from the entropy source.
*
* @param perso_string Pointer to personalization bitstring.
* @return Result of the DRBG instantiate operation.
*/
crypto_status_t otcrypto_drbg_instantiate(crypto_byte_buf_t perso_string);
sw/device/lib/crypto/include/drbg.h#L39:
/**
* Reseeds the DRBG with fresh entropy.
*
* Reseeds the DRBG with fresh entropy that is automatically fetched
* from the entropy source and updates the working state parameters.
*
* @param additional_input Pointer to the additional input for DRBG.
* @return Result of the DRBG reseed operation.
*/
crypto_status_t otcrypto_drbg_reseed(crypto_byte_buf_t additional_input);
sw/device/lib/crypto/include/drbg.h#L92:
/**
* DRBG function for generating random bits.
*
* Used to generate pseudo random bits after DRBG instantiation or
* DRBG reseeding.
*
* The caller should allocate space for the `drbg_output` buffer,
* (of length `output_len`), and set the length of expected
* output in the `len` field of `drbg_output`. If the user-set length
* and the output length does not match, an error message will be
* returned.
*
* The output is generated in 16-byte blocks; if `output_len` is not a multiple
* of 16, some output from the hardware will be discarded. This detail may be
* important for known-answer tests.
*
* @param additional_input Pointer to the additional data.
* @param output_len Required len of pseudorandom output, in bytes.
* @param[out] drbg_output Pointer to the generated pseudo random bits.
* @return Result of the DRBG generate operation.
*/
crypto_status_t otcrypto_drbg_generate(crypto_byte_buf_t additional_input,
size_t output_len,
crypto_byte_buf_t *drbg_output);
sw/device/lib/crypto/include/drbg.h#L101:
/**
* Uninstantiates DRBG and clears the context.
*
* @return Result of the DRBG uninstantiate operation.
*/
crypto_status_t otcrypto_drbg_uninstantiate(void);
Manual Entropy Operations
sw/device/lib/crypto/include/drbg.h#L55:
/**
* Instantiates the DRBG system.
*
* Initializes DRBG and the DRBG context. Gets the required entropy
* input from the user through the `entropy` parameter.
*
* The entropy input must be exactly 384 bits long (48 bytes). The
* personalization string must not be longer than the entropy input, and may be
* empty.
*
* @param entropy Pointer to the user defined entropy value.
* @param personalization_string Pointer to personalization bitstring.
* @return Result of the DRBG manual instantiation.
*/
crypto_status_t otcrypto_drbg_manual_instantiate(
crypto_byte_buf_t entropy, crypto_byte_buf_t perso_string);
sw/device/lib/crypto/include/drbg.h#L68:
/**
* Reseeds the DRBG with fresh entropy.
*
* Reseeds the DRBG with entropy input from the user through `entropy`
* parameter and updates the working state parameters.
*
* @param entropy Pointer to the user defined entropy value.
* @param additional_input Pointer to the additional input for DRBG.
* @return Result of the manual DRBG reseed operation.
*/
crypto_status_t otcrypto_drbg_manual_reseed(crypto_byte_buf_t entropy,
crypto_byte_buf_t additional_input);
Key derivation
Key derivation functions (KDFs) generate a new key from an existing key.
Supported Modes
The OpenTitan key derivation function is based on the counter mode and uses a pseudorandom function (PRF) as a building block. The PRF may be either HMAC or KMAC.
To learn more about PRFs, various key derivation mechanisms and security considerations, please refer to NIST SP800-108 and the links in the reference section.
API
sw/device/lib/crypto/include/kdf.h#L56:
/**
* Performs the key derivation function in counter mode.
*
* The required PRF engine for the KDF function is selected using the
* `kdf_mode` parameter.
*
* The caller should allocate and partially populate the `keying_material`
* blinded key struct, including populating the key configuration and
* allocating space for the keyblob. The caller should indicate the length of
* the allocated keyblob; this function will return an error if the keyblob
* length does not match expectations. For hardware-backed keys, the keyblob
* length is 0 and the keyblob pointer may be `NULL`. For non-hardware-backed
* keys, the keyblob should be twice the length of the key. The value in the
* `checksum` field of the blinded key struct will be populated by this
* function.
*
* @param key_derivation_key Pointer to the blinded key derivation key.
* @param kdf_mode Required KDF mode, with HMAC or KMAC as a PRF.
* @param key_mode Crypto mode for which the derived key is intended.
* @param required_bit_len Required length of the derived key in bits.
* @param[out] keying_material Pointer to the blinded keying material.
* @return Result of the key derivation operation.
*/
crypto_status_t otcrypto_kdf_ctr(const crypto_blinded_key_t key_derivation_key,
kdf_type_t kdf_mode, key_mode_t key_mode,
size_t required_bit_len,
crypto_blinded_key_t keying_material);
Key import and export
The following section defines the interface for importing keys to and exporting keys from the crypto library.
The crypto library typically represents private keys in blinded form, where the exact shape of the blinded key is opaque to the user. Public keys are in unblinded form, and the user can easily extract the plain key data. However, in some cases, a user might want to import a key generated elsewhere into the cryptolib, or might want to export a private key for use in a different piece of code.
Supported Modes
The crypto library provides four functions for this purpose:
- Build unblinded key from user-provided key data and mode
- Build blinded key from user-provided key data and configuration
- Convert blinded key to unblinded key
- Convert unblinded key to blinded key
To import a private key generated elsewhere, for example, the user can call otcrypto_build_blinded_key
.
To export a blinded key, the user can convert it to an unblinded key, at which point the plain data is accessible.
Build Keys
sw/device/lib/crypto/include/key_transport.h#L30:
/**
* Builds an unblinded key struct from a user (plain) key.
*
* @param plain_key Pointer to the user defined plain key.
* @param key_mode Crypto mode for which the key usage is intended.
* @param[out] unblinded_key Generated unblinded key struct.
* @return Result of the build unblinded key operation.
*/
crypto_status_t otcrypto_build_unblinded_key(
crypto_const_byte_buf_t plain_key, key_mode_t key_mode,
crypto_unblinded_key_t unblinded_key);
sw/device/lib/crypto/include/key_transport.h#L54:
/**
* Builds a blinded key struct from a plain key.
*
* This API takes as input a plain key from the user and masks it using an
* implantation specific masking with ‘n’ shares writing the output to
* `blinded_key.keyblob`.
*
* The caller should allocate and partially populate the blinded key struct,
* including populating the key configuration and allocating space for the
* keyblob. The caller should indicate the length of the allocated keyblob;
* this function will return an error if the keyblob length does not match
* expectations. For hardware-backed keys, the keyblob length is 0 and the
* keyblob pointer may be `NULL`. For non-hardware-backed keys, the keyblob
* should be twice the length of the key. The value in the `checksum` field of
* the blinded key struct will be populated by the key generation function.
*
* @param plain_key Pointer to the user defined plain key.
* @param[out] blinded_key Destination blinded key struct.
* @return Result of the build blinded key operation.
*/
crypto_status_t otcrypto_build_blinded_key(crypto_const_byte_buf_t plain_key,
crypto_blinded_key_t blinded_key);
Blinding and Unblinding Keys
sw/device/lib/crypto/include/key_transport.h#L67:
/**
* Exports the blinded key struct to an unblinded key struct.
*
* This API takes as input a blinded key masked with ‘n’ shares, and
* removes the masking and generates an unblinded key struct as output.
*
* @param blinded_key Blinded key struct to be unmasked.
* @param[out] unblinded_key Generated unblinded key struct.
* @return Result of the blinded key export operation.
*/
crypto_status_t otcrypto_blinded_to_unblinded_key(
const crypto_blinded_key_t blinded_key,
crypto_unblinded_key_t unblinded_key);
sw/device/lib/crypto/include/key_transport.h#L87:
/**
* Build a blinded key struct from an unblinded key struct.
*
* The caller should allocate and partially populate the blinded key struct,
* including populating the key configuration and allocating space for the
* keyblob. The caller should indicate the length of the allocated keyblob;
* this function will return an error if the keyblob length does not match
* expectations. For hardware-backed keys, the keyblob length is 0 and the
* keyblob pointer may be `NULL`. For non-hardware-backed keys, the keyblob
* should be twice the length of the key. The value in the `checksum` field of
* the blinded key struct will be populated by the key generation function.
*
* @param unblinded_key Unblinded key struct to be masked.
* @param[out] blinded_key Generated (masked) blinded key struct.
* @return Result of blinding operation.
*/
crypto_status_t otcrypto_unblinded_to_blinded_key(
const crypto_unblinded_key_t unblinded_key,
crypto_blinded_key_t blinded_key);
Security Strength
Security strength denotes the amount of work required to break a cryptographic algorithm. The security strength of an algorithm is expressed in “bits” where n-bit security means that the attacker would have to perform 2^n^ operations in expectation to break the algorithm.
The table below summarizes the security strength for the supported cryptographic algorithms.
Family | Algorithm | Security Strength (bits) | Comments |
---|---|---|---|
Block cipher | AES128 | 128 | |
Block cipher | AES192 | 192 | |
Block cipher | AES256 | 256 | |
Hash function | SHA256 | 128 | 128 bits collision, 256 bits preimage |
Hash function | SHA384 | 192 | 192 bits collision, 384 bits preimage |
Hash function | SHA512 | 256 | 256 bits collision, 512 bits preimage |
Hash function | SHA3-224 | 112 | 112 bits collision, 224 bits preimage |
Hash function | SHA3-256 | 128 | 128 bits collision, 256 bits preimage |
Hash function | SHA3-384 | 192 | 192 bits collision, 384 bits preimage |
Hash function | SHA3-512 | 256 | 256 bits collision, 512 bits preimage |
Hash-XOF | SHAKE128 | min(d/2, 128) | min(d/2, 128) collision; preimage >= min(d, 128) |
Hash-XOF | SHAKE256 | min(d/2, 256) | min(d/2, 256) collision; preimage >= min(d, 256) |
Hash-XOF | cSHAKE128 | min(d/2, 128) | min(d/2, 128) collision; preimage >= min(d, 128) |
Hash-XOF | cSHAKE256 | min(d/2, 256) | min(d/2, 256) collision; preimage >= min(d, 256) |
MAC | HMAC-SHA256 | 256 | |
MAC | KMAC128 | 128 | |
MAC | KMAC256 | 256 | |
RSA | RSA-2048 | 112 | |
RSA | RSA-3072 | 128 | |
RSA | RSA-4096 | ~144 | |
ECC | NIST P-256 | 128 | |
ECC | NIST P-384 | 192 | |
ECC | X25519/Ed25519 | 128 | |
DRBG | CTR_DRBG | 256 | Based on AES-CTR-256 |
KDF | KDF_CTR | 128 | With HMAC or KMAC as PRF |
Over time the cryptographic algorithms may become more vulnerable to successful attacks, requiring a transition to stronger algorithms or longer key lengths over time. The table below is a recommendation from NIST SP800-57 Part 1 about concrete time frames for different security strengths.

Reference
AES
- FIPS 197: Announcing the Advanced Encryption Standard (AES)
- NIST SP800-38A: Recommendation for Block Cipher Modes of Operation: Methods and Techniques
- NIST SP800-38D: Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC
- NIST SP800-38F: Recommendation for Block Cipher Modes of Operation: Methods for Key wrapping
Hash Functions
- FIPS 180-4: Secure Hash Standard
- FIPS 202: SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions
- NIST SP800-185: SHA-3 Derived Functions: cSHAKE, KMAC, TupleHash, and ParallelHash
Message Authentication
- IETF RFC 2104: HMAC: Keyed-Hashing for Message Authentication
- IETF RFC 4231: Identifiers and Test Vectors for HMAC-SHA-224, HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512
- IETF RFC 4868: Using HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512
- NIST SP800-185: SHA-3 Derived Functions: cSHAKE, KMAC, TupleHash, and ParallelHash
RSA
- IETF RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2
- FIPS 186-5: Digital Signature Standard
Elliptic curve cryptography
- SEC1: Elliptic Curve Cryptography
- SEC2: Recommended Elliptic Curve Domain Parameters
- FIPS 186-5: Digital Signature Standard
- NIST SP800-56A: Recommendation for Pair-Wise Key-Establishment Schemes Using Discrete Logarithm Cryptography
- IETF RFC 5639: Elliptic Curve Cryptography (ECC) Brainpool Standard Curves and Curve Generation
- IETF RFC 4492: Elliptic Curve (ECC) Cipher Suites for Transport Layer Security (TLS)
- Safe curves: Choosing safe curves for elliptic-curve cryptography
- IETF RFC 7448: Elliptic Curves for Security
- IETF RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA)
- NIST SP800-186: Recommendations for Discrete Logarithm-Based Cryptography: Elliptic Curve Domain Parameters
Deterministic random bit generation
- NIST SP800-90A: Recommendation for Random Number Generation Using Deterministic Random Bit Generators
- NIST SP800-90B: Recommendation for the Entropy Sources Used for Random Bit Generation
- BSI-AIS31: A proposal for: Functionality classes for random number generators
- OpenTitan CSRNG block technical specification
Key derivation
- NIST SP800-108: Recommendation for Key Derivation using Pseudorandom Functions
Key management and security strength
- NIST SP800-131: Transitioning the Use of Cryptographic Algorithms and Key Lengths
- NIST-SP800-57: Recommendation for Key Management (Part 1 General)