OpenTitan Cryptography Library User Guide
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.
This page:
- Lists a quick reference for supported algorithms
- Enumerates all of the cryptolib’s data structures
- Shows and explains the interfaces for:
- Explains how asynchronous operations work
- Lists the security strength of each algorithm
- Lists references for further reading
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 |
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 otcrypto_status_t
.
This design is compatible with OpenTitan’s internal status_t
datatype.
sw/device/lib/crypto/include/datatypes.h#L41:
/**
* 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 `otcrypto_status_value` enum below.
*/
typedef status_t otcrypto_status_t;
However, the cryptolib additionally guarantees that all status codes will be bit-compatible to the otcrypto_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#L69:
/**
* Possible status values for the cryptolib.
*
* As long as the OTCRYPTO_STATUS_DEBUG define is unset, all `otcrypto_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 otcrypto_status_value {
// Status is OK; no errors.
kOtcryptoStatusValueOk = (int32_t)0x739,
// Invalid input arguments; wrong length or invalid type.
kOtcryptoStatusValueBadArgs = (int32_t)0x8000fea0 | kInvalidArgument,
// Error after which it is OK to retry (e.g. timeout).
kOtcryptoStatusValueInternalError = (int32_t)0x80005340 | kAborted,
// Error after which it is not OK to retry (e.g. integrity check).
kOtcryptoStatusValueFatalError = (int32_t)0x80006d80 | kFailedPrecondition,
// An asynchronous operation is still in progress.
kOtcryptoStatusValueAsyncIncomplete = (int32_t)0x8000ea40 | kUnavailable,
// TODO: remove all instances of this error before release; it is to track
// implementations that are not yet complete.
kOtcryptoStatusValueNotImplemented = (int32_t)0x80008d20 | kUnimplemented,
} otcrypto_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#L92:
/**
* 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 `otcrypto_byte_buf_t` is used for output. The
* crypto library will throw an error if `len` doesn't match expectations.
*/
typedef struct otcrypto_byte_buf {
// Pointer to the data.
uint8_t *data;
// Length of the data in bytes.
size_t len;
} otcrypto_byte_buf_t;
sw/device/lib/crypto/include/datatypes.h#L107:
/**
* 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 `otcrypto_byte_buf_t` because
* data pointed to by a struct does not inherit `const`, so `const
* otcrypto_byte_buf_t` would still allow data to change.
*/
typedef struct otcrypto_const_byte_buf {
// Pointer to the data.
const uint8_t *const data;
// Length of the data in bytes.
const size_t len;
} otcrypto_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#L121:
/**
* 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 `otcrypto_word32_buf_t` is used for output. The
* crypto library will throw an error if `len` doesn't match expectations.
*/
typedef struct otcrypto_word32_buf {
// Pointer to the data.
uint32_t *data;
// Length of the data in words.
size_t len;
} otcrypto_word32_buf_t;
sw/device/lib/crypto/include/datatypes.h#L136:
/**
* 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 `otcrypto_word32_buf_t`
* because data pointed to by a struct does not inherit `const`, so `const
* otcrypto_word32_buf_t` would still allow data to change.
*/
typedef struct otcrypto_const_word32_buf {
// Pointer to the data.
const uint32_t *const data;
// Length of the data in words.
const size_t len;
} otcrypto_const_word32_buf_t;
Key data structures
Keys receive extra protection from the cryptolib. Public keys are represented in plain, “unblinded” form, but include a checksum to protect them against accidental corruption. The checksum is implementation-specific and may change over time. The caller should use algorithm-specific routines to construct unblinded keys; see e.g. the ECC and RSA sections for details.
sw/device/lib/crypto/include/datatypes.h#L401:
/**
* Struct to handle unmasked key type.
*/
typedef struct otcrypto_unblinded_key {
// Mode for which the key usage is intended.
otcrypto_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;
} otcrypto_unblinded_key_t;
Secret keys are “blinded”, meaning that keys are represented by at least two “shares” the same size as the key. Blinded keys are also sometimes referred to as “masked”. 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 exact blinding method and internal representation of blinded key data is opaque to the caller and subject to change in future library versions. Lke unblinded keys, they include a checksum. Callers should use key import/export functions to generate, construct, and interpret blinded keys.
sw/device/lib/crypto/include/datatypes.h#L415:
/**
* Struct to handle masked key type.
*/
typedef struct otcrypto_blinded_key {
// Key configuration information.
const otcrypto_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;
} otcrypto_blinded_key_t;
As shown above, all secret keys have a configuration value. Once the key is created, or imported, the configuration is not expected to change; the cryptolib will never change it, and the caller would have to recompute the key checksum to change it, which is not recommended. 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#L381:
/**
* Struct to represent the configuration of a blinded key.
*/
typedef struct otcrypto_key_config {
// Crypto library version for this key.
otcrypto_lib_version_t version;
// Mode for which the key usage is intended.
otcrypto_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.
// If this is set to `true`, the keyblob must be exactly 8 words long, where
// the first word is the version and the remaining 7 words are the salt.
hardened_bool_t hw_backed;
// Whether the key can be exported (always false if `hw_backed` is true).
hardened_bool_t exportable;
// Key security level.
otcrypto_key_security_level_t security_level;
} otcrypto_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
in the key configuration.
In this case, the keyblob is the diversification input for key manager instead of the key material itself.
See the key transport section for more details.
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#L373:
/**
* 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 otcrypto_lib_version {
// Version 1.
kOtcryptoLibVersion1 = 0x7f4,
} otcrypto_lib_version_t;
The required security level for the blinded key is chosen using the enum below. At high security levels, the crypto library will prioritize protecting the key from sophisticated attacks, even at large performance costs. If the security level is low, the crypto library will still try to protect the key, but may forgo the most costly protections against it.
sw/device/lib/crypto/include/datatypes.h#L354:
/**
* Enum to denote key security level.
*
* At high security levels, the crypto library will prioritize
* protecting the key from sophisticated attacks, even at large
* performance costs. If the security level is low, the crypto
* library will still try to protect the key, but may forgo the
* most costly protections against e.g. sophisticated physical
* attacks.
*
* Values are hardened.
*/
typedef enum otcrypto_key_security_level {
// Security level low.
kOtcryptoKeySecurityLevelLow = 0x1e9,
// Security level medium.
kOtcryptoKeySecurityLevelMedium = 0xeab,
// Security level high.
kOtcryptoKeySecurityLevelHigh = 0xa7e,
} otcrypto_key_security_level_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#L148:
/**
* Enum to denote the key type of the handled key.
*
* Values are hardened.
*/
typedef enum otcrypto_key_type {
// Key type AES.
kOtcryptoKeyTypeAes = 0x8e9,
// Key type HMAC.
kOtcryptoKeyTypeHmac = 0xe3f,
// Key type KMAC.
kOtcryptoKeyTypeKmac = 0xb74,
// Key type RSA.
kOtcryptoKeyTypeRsa = 0x7ee,
// Key type ECC.
kOtcryptoKeyTypeEcc = 0x15b,
// Key type KDF.
kOtcryptoKeyTypeKdf = 0xb87,
} otcrypto_key_type_t;
sw/device/lib/crypto/include/datatypes.h#L171:
/**
* Enum to specify the AES modes that use a key.
*
* This will be used in the `otcrypto_key_mode_t` struct to indicate the mode
* for which the provided key is intended for.
*
* Values are hardened.
*/
typedef enum otcrypto_aes_key_mode {
// Mode AES ECB.
kOtcryptoAesKeyModeEcb = 0x1b6,
// Mode AES CBC.
kOtcryptoAesKeyModeCbc = 0xf3a,
// Mode AES CFB.
kOtcryptoAesKeyModeCfb = 0x0f9,
// Mode AES OFB.
kOtcryptoAesKeyModeOfb = 0xb49,
// Mode AES CTR.
kOtcryptoAesKeyModeCtr = 0x4ce,
// Mode AES GCM.
kOtcryptoAesKeyModeGcm = 0xaa5,
// Mode AES KWP.
kOtcryptoAesKeyModeKwp = 0x7d5,
} otcrypto_aes_key_mode_t;
sw/device/lib/crypto/include/datatypes.h#L196:
/**
* Enum to specify the HMAC modes that use a key.
*
* This will be used in the `otcrypto_key_mode_t` struct to indicate the mode
* for which the provided key is intended for.
*
* Values are hardened.
*/
typedef enum otcrypto_hmac_key_mode {
// Mode HMAC SHA256.
kOtcryptoHmacKeyModeSha256 = 0x7fd,
// Mode HMAC SHA384.
kOtcryptoHmacKeyModeSha384 = 0x43b,
// Mode HMAC SHA512.
kOtcryptoHmacKeyModeSha512 = 0x7a2,
} otcrypto_hmac_key_mode_t;
sw/device/lib/crypto/include/datatypes.h#L213:
/**
* Enum to specify the KMAC modes that use a key.
*
* This will be used in the `otcrypto_key_mode_t` struct to indicate the mode
* for which the provided key is intended for.
*
* Values are hardened.
*/
typedef enum otcrypto_kmac_key_mode {
// Mode KMAC128.
kOtcryptoKmacKeyModeKmac128 = 0xa56,
// Mode KMAC256.
kOtcryptoKmacKeyModeKmac256 = 0x663,
} otcrypto_kmac_key_mode_t;
sw/device/lib/crypto/include/datatypes.h#L228:
/**
* Enum to specify the RSA modes that use a key.
*
* This will be used in the `otcrypto_key_mode_t` struct to indicate the mode
* for which the provided key is intended for.
*
* Values are hardened.
*/
typedef enum otcrypto_rsa_key_mode {
// Mode RSA Sign, RSASSA-PKCS.
kOtcryptoRsaKeyModeSignPkcs = 0x3d4,
// Mode RSA Sign, RSASSA-PSS.
kOtcryptoRsaKeyModeSignPss = 0x761,
// Mode RSA Encrypt, RSAES-OAEP.
kOtcryptoRsaKeyModeEncryptOaep = 0x585,
} otcrypto_rsa_key_mode_t;
sw/device/lib/crypto/include/datatypes.h#L245:
/**
* Enum to specify the ECC modes that use a key.
*
* This will be used in the `otcrypto_key_mode_t` struct to indicate the mode
* for which the provided key is intended for.
*
* Values are hardened.
*/
typedef enum otcrypto_ecc_key_mode {
// Mode ECDSA.
kOtcryptoEccKeyModeEcdsa = 0x4e5,
// Mode ECDH.
kOtcryptoEccKeyModeEcdh = 0x6bb,
// Mode Ed25519.
kOtcryptoEccKeyModeEd25519 = 0xd32,
// Mode X25519.
kOtcryptoEccKeyModeX25519 = 0x276,
} otcrypto_ecc_key_mode_t;
sw/device/lib/crypto/include/datatypes.h#L264:
/**
* Enum to specify the KDF modes that use a key.
*
* This will be used in the `otcrypto_key_mode_t` struct to indicate the mode
* for which the provided key is intended for.
*
* Values are hardened.
*/
typedef enum otcrypto_kdf_key_mode {
// Mode KDF-CTR with HMAC as PRF.
kOtcryptoKdfKeyModeCtrHmac = 0x12f,
// Mode KDF-KMAC with KMAC128 as PRF.
kOtcryptoKdfKeyModeKmac128 = 0xe5e,
// Mode KDF-KMAC with KMAC256 as PRF.
kOtcryptoKdfKeyModeKmac256 = 0x353,
} otcrypto_kdf_key_mode_t;
sw/device/lib/crypto/include/datatypes.h#L282:
/**
* Enum for opentitan crypto modes that use a key.
*
* Denotes the crypto mode for which the provided key is to be used.
* This `otcrypto_key_mode_t` will be a parameter in the
* `otcrypto_blinded_key_t` and `otcrypto_unblinded_key_t` structs.
*
* Values are hardened.
*/
typedef enum otcrypto_key_mode {
// Key is intended for AES ECB mode.
kOtcryptoKeyModeAesEcb = kOtcryptoKeyTypeAes << 16 | kOtcryptoAesKeyModeEcb,
// Key is intended for AES CBC mode.
kOtcryptoKeyModeAesCbc = kOtcryptoKeyTypeAes << 16 | kOtcryptoAesKeyModeCbc,
// Key is intended for AES CFB mode.
kOtcryptoKeyModeAesCfb = kOtcryptoKeyTypeAes << 16 | kOtcryptoAesKeyModeCfb,
// Key is intended for AES OFB mode.
kOtcryptoKeyModeAesOfb = kOtcryptoKeyTypeAes << 16 | kOtcryptoAesKeyModeOfb,
// Key is intended for AES CTR mode.
kOtcryptoKeyModeAesCtr = kOtcryptoKeyTypeAes << 16 | kOtcryptoAesKeyModeCtr,
// Key is intended for AES GCM mode.
kOtcryptoKeyModeAesGcm = kOtcryptoKeyTypeAes << 16 | kOtcryptoAesKeyModeGcm,
// Key is intended for AES KWP mode.
kOtcryptoKeyModeAesKwp = kOtcryptoKeyTypeAes << 16 | kOtcryptoAesKeyModeKwp,
// Key is intended for HMAC SHA256 mode.
kOtcryptoKeyModeHmacSha256 =
kOtcryptoKeyTypeHmac << 16 | kOtcryptoHmacKeyModeSha256,
// Key is intended for HMAC SHA384 mode.
kOtcryptoKeyModeHmacSha384 =
kOtcryptoKeyTypeHmac << 16 | kOtcryptoHmacKeyModeSha384,
// Key is intended for HMAC SHA512 mode.
kOtcryptoKeyModeHmacSha512 =
kOtcryptoKeyTypeHmac << 16 | kOtcryptoHmacKeyModeSha512,
// Key is intended for KMAC128 mode.
kOtcryptoKeyModeKmac128 =
kOtcryptoKeyTypeKmac << 16 | kOtcryptoKmacKeyModeKmac128,
// Key is intended for KMAC256 mode.
kOtcryptoKeyModeKmac256 =
kOtcryptoKeyTypeKmac << 16 | kOtcryptoKmacKeyModeKmac256,
// Key is intended for RSA signature RSASSA-PKCS mode.
kOtcryptoKeyModeRsaSignPkcs =
kOtcryptoKeyTypeRsa << 16 | kOtcryptoRsaKeyModeSignPkcs,
// Key is intended for RSA signature RSASSA-PSS mode.
kOtcryptoKeyModeRsaSignPss =
kOtcryptoKeyTypeRsa << 16 | kOtcryptoRsaKeyModeSignPss,
// Key is intended for RSA encryption RSAES-OAEP mode.
kOtcryptoKeyModeRsaEncryptOaep =
kOtcryptoKeyTypeRsa << 16 | kOtcryptoRsaKeyModeEncryptOaep,
// Key is intended for ECDSA mode.
kOtcryptoKeyModeEcdsa = kOtcryptoKeyTypeEcc << 16 | kOtcryptoEccKeyModeEcdsa,
// Key is intended for ECDH mode.
kOtcryptoKeyModeEcdh = kOtcryptoKeyTypeEcc << 16 | kOtcryptoEccKeyModeEcdh,
// Key is intended for Ed25519 mode.
kOtcryptoKeyModeEd25519 =
kOtcryptoKeyTypeEcc << 16 | kOtcryptoEccKeyModeEd25519,
// Key is intended for X25519 mode.
kOtcryptoKeyModeX25519 =
kOtcryptoKeyTypeEcc << 16 | kOtcryptoEccKeyModeX25519,
// Key is intended for KDF-CTR with HMAC as PRF.
kOtcryptoKeyModeKdfCtrHmac =
kOtcryptoKeyTypeKdf << 16 | kOtcryptoKdfKeyModeCtrHmac,
// Key is intended for KDF with KMAC128 as PRF.
kOtcryptoKeyModeKdfKmac128 =
kOtcryptoKeyTypeKdf << 16 | kOtcryptoKdfKeyModeKmac128,
// Key is intended for KDF with KMAC256 as PRF.
kOtcryptoKeyModeKdfKmac256 =
kOtcryptoKeyTypeKdf << 16 | kOtcryptoKdfKeyModeKmac256,
} otcrypto_key_mode_t;
Algorithm-specific data structures
AES data structures
sw/device/lib/crypto/include/aes.h#L40:
/**
* Enum to define AES mode of operation.
*
* Values are hardened.
*/
typedef enum otcrypto_aes_mode {
// AES ECB mode (electronic codebook mode).
kOtcryptoAesModeEcb = 0x533,
// AES CBC mode (cipher block chaining mode).
kOtcryptoAesModeCbc = 0x45d,
// AES CFB mode (cipher feedback mode).
kOtcryptoAesModeCfb = 0xcd2,
// AES OFB mode (output feedback mode).
kOtcryptoAesModeOfb = 0x39a,
// AES CTR mode (counter mode).
kOtcryptoAesModeCtr = 0xd2c,
} otcrypto_aes_mode_t;
sw/device/lib/crypto/include/aes.h#L58:
/**
* Enum to define AES operation to be performed.
*
* Values are hardened.
*/
typedef enum otcrypto_aes_operation {
// AES operation mode encrypt.
kOtcryptoAesOperationEncrypt = 0x2b6,
// AES operation mode decrypt.
kOtcryptoAesOperationDecrypt = 0x5f0,
} otcrypto_aes_operation_t;
sw/device/lib/crypto/include/aes.h#L70:
/**
* Enum to define padding scheme for AES data.
*
* Values are hardened.
*/
typedef enum otcrypto_aes_padding {
// Pads with value same as the number of padding bytes.
kOtcryptoAesPaddingPkcs7 = 0xe7f,
// Pads with 0x80 (10000000), followed by zero bytes.
kOtcryptoAesPaddingIso9797M2 = 0xfac,
// Add no padding.
kOtcryptoAesPaddingNull = 0x8ce,
} otcrypto_aes_padding_t;
sw/device/lib/crypto/include/aes.h#L24:
/**
* Enum to denote the AES-GCM tag length.
*
* Values are hardened.
*/
typedef enum otcrypto_aes_gcm_tag_len {
// Tag length 128 bits.
kOtcryptoAesGcmTagLen128 = 0x167,
// Tag length 96 bits.
kOtcryptoAesGcmTagLen96 = 0x35a,
// Tag length 64 bits.
kOtcryptoAesGcmTagLen64 = 0x5d4,
// Tag length 32 bits.
kOtcryptoAesGcmTagLen32 = 0xf06,
} otcrypto_aes_gcm_tag_len_t;
Elliptic curve data structures
sw/device/lib/crypto/include/ecc.h#L26:
/**
* Enum to define EdDSA mode for signature.
*
* Values are hardened.
*/
typedef enum otcrypto_eddsa_sign_mode {
// Signature mode EdDSA.
kOtcryptoEddsaSignModeEddsa = 0xae1,
// Signature mode Hashed EdDSA.
kOtcryptoEddsaSignModeHashEddsa = 0x9a6,
} otcrypto_eddsa_sign_mode_t;
sw/device/lib/crypto/include/ecc.h#L36:
/**
* Struct for domain parameters of a custom Weierstrass curve.
*/
typedef struct otcrypto_ecc_domain {
// Prime P (modulus of coordinate finite field).
otcrypto_const_byte_buf_t p;
// Coefficient a.
otcrypto_const_byte_buf_t a;
// Coefficient b.
otcrypto_const_byte_buf_t b;
// q (order of G).
otcrypto_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;
} otcrypto_ecc_domain_t;
sw/device/lib/crypto/include/ecc.h#L60:
/**
* Enum to define the type of elliptic curve used for the operation.
*
* Values are hardened.
*/
typedef enum otcrypto_ecc_curve_type {
// Generic Weierstrass curve, with custom domain parameters.
kOtcryptoEccCurveTypeCustom = 0xbf7,
// Named Weierstrass curve - NIST P256.
kOtcryptoEccCurveTypeNistP256 = 0xec8,
// Named Weierstrass curve - NIST P384.
kOtcryptoEccCurveTypeNistP384 = 0x1bc,
// Named Weierstrass curve - Brainpool P256r1.
kEccCurveTypeBrainpoolP256R1 = 0xc1e,
} otcrypto_ecc_curve_type_t;
sw/device/lib/crypto/include/ecc.h#L76:
/**
* Struct for ECC curve used for ECDSA / ECDH operation.
*
* Values are hardened.
*/
typedef struct otcrypto_ecc_curve {
// Type of the Weierstrass curve, custom curve or named curve.
otcrypto_ecc_curve_type_t curve_type;
// Domain parameters for a custom Weierstrass curve. May be NULL for a named
// curve.
const otcrypto_ecc_domain_t *const domain_parameter;
} otcrypto_ecc_curve_t;
Hash data structures
sw/device/lib/crypto/include/datatypes.h#L431:
/**
* Enum to define supported hashing modes.
*
* Values are hardened.
*/
typedef enum otcrypto_hash_mode {
// SHA2-256 mode.
kOtcryptoHashModeSha256 = 0x69b,
// SHA2-384 mode.
kOtcryptoHashModeSha384 = 0x7ae,
// SHA2-512 mode.
kOtcryptoHashModeSha512 = 0x171,
// SHA3-224 mode.
kOtcryptoHashModeSha3_224 = 0x516,
// SHA3-256 mode.
kOtcryptoHashModeSha3_256 = 0x2d4,
// SHA3-384 mode.
kOtcryptoHashModeSha3_384 = 0x267,
// SHA3-512 mode.
kOtcryptoHashModeSha3_512 = 0x44d,
// Shake128 mode.
kOtcryptoHashXofModeShake128 = 0x5d8,
// Shake256 mode.
kOtcryptoHashXofModeShake256 = 0x34a,
// cShake128 mode.
kOtcryptoHashXofModeCshake128 = 0x0bd,
// cShake256 mode.
kOtcryptoHashXofModeCshake256 = 0x4e2,
} otcrypto_hash_mode_t;
sw/device/lib/crypto/include/datatypes.h#L459:
/**
* Container for a hash digest.
*/
typedef struct otcrypto_hash_digest {
// Digest type.
otcrypto_hash_mode_t mode;
// Digest data.
uint32_t *data;
// Digest length in 32-bit words.
size_t len;
} otcrypto_hash_digest_t;
Message authentication data structures
sw/device/lib/crypto/include/mac.h#L27:
/**
* Enum to define KMAC mode.
*
* Values are hardened.
*/
typedef enum otcrypto_kmac_mode {
// KMAC128 mode.
kOtcryptoKmacModeKmac128 = 0x336,
// KMAC256 mode.
kOtcryptoKmacModeKmac256 = 0xec4,
} otcrypto_kmac_mode_t;
RSA data structures
sw/device/lib/crypto/include/rsa.h#L24:
/**
* Enum to define padding scheme for RSA signature data.
*
* Values are hardened.
*/
typedef enum otcrypto_rsa_padding {
// Pads input data according to the PKCS#1 (v1.5) scheme.
kOtcryptoRsaPaddingPkcs = 0x94e,
// Pads input data according to the PKCS#1-PSS scheme. The mask generation
// function is MGF1 with the same hash function as the input message
// (supported SHA2 or SHA3 hash functions only).
kOtcryptoRsaPaddingPss = 0x6b1,
} otcrypto_rsa_padding_t;
sw/device/lib/crypto/include/rsa.h#L38:
/**
* Enum to define possible lengths of RSA (public) keys.
*
* Values are hardened.
*/
typedef enum otcrypto_rsa_size {
// 2048-bit RSA.
kOtcryptoRsaSize2048 = 0x5d1,
// 3072-bit RSA.
kOtcryptoRsaSize3072 = 0xc35,
// 4096-bit RSA.
kOtcryptoRsaSize4096 = 0x8da,
} otcrypto_rsa_size_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#L50:
/**
* Generic opaque hash context.
*
* Representation is internal to the hash implementation; initialize
* with #otcrypto_hash_init.
*/
typedef struct otcrypto_hash_context {
uint32_t data[kOtcryptoHashCtxStructWords];
} otcrypto_hash_context_t;
sw/device/lib/crypto/include/mac.h#L40:
/**
* Generic hmac context.
*
* Representation is internal to the hmac implementation; initialize
* with #otcrypto_hmac_init.
*/
typedef struct otcrypto_hmac_context {
uint32_t data[kOtcryptoHashCtxStructWords];
} otcrypto_hmac_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 otcrypto_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.
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#L102:
/**
* Get the number of blocks needed for the plaintext length and padding mode.
*
* This returns the size of the padded plaintext, which is the same as the
* ciphertext size. Returns `kOtcryptoStatusValueBadArgs` if the padding mode
* and length are incompatible (for instance, if the padding mode is "no
* padding" but the input length is not a multiple of the AES block size).
*
* @param plaintext_len Plaintext data length in bytes.
* @param aes_padding Padding scheme to be used for the data.
* @return Size of the padded input or ciphertext.
* @return Result of the operation.
*/
otcrypto_status_t otcrypto_aes_padded_plaintext_length(
size_t plaintext_len, otcrypto_aes_padding_t aes_padding,
size_t *padded_len);
sw/device/lib/crypto/include/aes.h#L131:
/**
* 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.
*/
otcrypto_status_t otcrypto_aes(const otcrypto_blinded_key_t *key,
otcrypto_word32_buf_t iv,
otcrypto_aes_mode_t aes_mode,
otcrypto_aes_operation_t aes_operation,
otcrypto_const_byte_buf_t cipher_input,
otcrypto_aes_padding_t aes_padding,
otcrypto_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.
The cryptolib offers GCM in one-shot and in streaming mode. In streaming mode, it is strongly recommended not to process the decrypted data before verifying the authentication tag.
GCM - Authenticated Encryption and Decryption
sw/device/lib/crypto/include/aes.h#L163:
/**
* 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
*/
otcrypto_status_t otcrypto_aes_gcm_encrypt(const otcrypto_blinded_key_t *key,
otcrypto_const_byte_buf_t plaintext,
otcrypto_const_word32_buf_t iv,
otcrypto_const_byte_buf_t aad,
otcrypto_aes_gcm_tag_len_t tag_len,
otcrypto_byte_buf_t ciphertext,
otcrypto_word32_buf_t auth_tag);
sw/device/lib/crypto/include/aes.h#L198:
/**
* 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
*/
otcrypto_status_t otcrypto_aes_gcm_decrypt(
const otcrypto_blinded_key_t *key, otcrypto_const_byte_buf_t ciphertext,
otcrypto_const_word32_buf_t iv, otcrypto_const_byte_buf_t aad,
otcrypto_aes_gcm_tag_len_t tag_len, otcrypto_const_word32_buf_t auth_tag,
otcrypto_byte_buf_t plaintext, hardened_bool_t *success);
sw/device/lib/crypto/include/aes.h#L226:
/**
* Initializes the AES-GCM authenticated encryption operation.
*
* The order of operations for encryption is:
* - `otcrypto_aes_gcm_encrypt_init()` called once
* - `otcrypto_aes_gcm_update_aad()` called zero or more times
* - `otcrypto_aes_gcm_update_encrypted_data()` called zero or more times
* - `otcrypto_aes_gcm_encrypt_final()` called once
*
* Associated data must be added first, before encrypted data; the caller may
* not call `otcrypto_aes_gcm_udpate_aad()` after the first call to
* `otcrypto_aes_gcm_update_encrypted_data()`.
*
* The resulting AES-GCM context will include pointers into the keyblob of the
* blinded key. It is important that the blinded key (or at least the keyblob)
* remains live as long as `ctx` is. The IV is safe to free.
*
* @param key Pointer to the blinded key struct.
* @param iv Initialization vector for the encryption function.
* @param[out] ctx Context object for the operation.
* @return Result of the initialization operation.
*/
otcrypto_status_t otcrypto_aes_gcm_encrypt_init(
const otcrypto_blinded_key_t *key, otcrypto_const_word32_buf_t iv,
otcrypto_aes_gcm_context_t *ctx);
sw/device/lib/crypto/include/aes.h#L256:
/**
* Initializes the AES-GCM authenticated decryption operation.
*
* The order of operations for decryption is:
* - `otcrypto_aes_gcm_decrypt_init()` called once
* - `otcrypto_aes_gcm_update_aad()` called zero or more times
* - `otcrypto_aes_gcm_update_encrypted_data()` called zero or more times
* - `otcrypto_aes_gcm_decrypt_final()` called once
*
* Associated data must be added first, before encrypted data; the caller may
* not call `otcrypto_aes_gcm_udpate_aad()` after the first call to
* `otcrypto_aes_gcm_update_encrypted_data()`.
*
* The resulting AES-GCM context will include pointers into the keyblob of the
* blinded key. It is important that the blinded key (or at least the keyblob)
* remains live as long as `ctx` is. The IV is safe to free.
*
* IMPORTANT: Although this routine produces decrypted data incrementally, it
* is the caller's responsibility to ensure that they do not trust the
* decrypted data until the tag check passes.
*
* @param key Pointer to the blinded key struct.
* @param iv Initialization vector for the decryption function.
* @param[out] ctx Context object for the operation.
* @return Result of the initialization operation.
*/
otcrypto_status_t otcrypto_aes_gcm_decrypt_init(
const otcrypto_blinded_key_t *key, otcrypto_const_word32_buf_t iv,
otcrypto_aes_gcm_context_t *ctx);
sw/device/lib/crypto/include/aes.h#L269:
/**
* Updates additional authenticated data for an AES-GCM operation.
*
* May be used for either encryption or decryption. Call
* `otcrypto_aes_gcm_encrypt_init` or `otcrypto_aes_gcm_decrypt_init` first.
*
* @param ctx Context object for the operation, updated in place.
* @param aad Additional authenticated data.
* @return Result of the update operation.
*/
otcrypto_status_t otcrypto_aes_gcm_update_aad(otcrypto_aes_gcm_context_t *ctx,
otcrypto_const_byte_buf_t aad);
sw/device/lib/crypto/include/aes.h#L296:
/**
* Updates authenticated-and-encrypted data for an AES-GCM operation.
*
* May be used for either encryption or decryption. Call
* `otcrypto_aes_gcm_encrypt_init` or `otcrypto_aes_gcm_decrypt_init` first.
*
* The caller should allocate space for the output and set the `len` field
* accordingly.
*
* For encryption, `input` is the plaintext and `output` is the ciphertext; for
* decryption, they are reversed. The output must always be long enough to
* store all full 128-bit blocks of encrypted data received so far minus all
* output produced so far; rounding the input length to the next 128-bit
* boundary is always enough, but if the caller knows the exact byte-length of
* input so far they can calculate it exactly. Returns an error if `output` is
* not long enough; if `output` is overly long, only the first
* `output_bytes_written` bytes will be used.
*
* @param ctx Context object for the operation, updated in place.
* @param input Plaintext for encryption, ciphertext for decryption.
* @param[out] output Ciphertext for encryption, plaintext for decryption.
* @param[out] output_bytes_written Number of bytes written to `output`.
* @return Result of the update operation.
*/
otcrypto_status_t otcrypto_aes_gcm_update_encrypted_data(
otcrypto_aes_gcm_context_t *ctx, otcrypto_const_byte_buf_t input,
otcrypto_byte_buf_t output, size_t *output_bytes_written);
sw/device/lib/crypto/include/aes.h#L319:
/**
* Finishes the AES-GCM authenticated encryption operation.
*
* Processes any remaining plaintext from the context and computes the
* authentication tag and up to 1 block of ciphertext.
*
* The caller should allocate space for the ciphertext and tag buffers and set
* the `len` fields accordingly. This function returns the
* `ciphertext_bytes_written` parameter with the number of bytes written to
* `ciphertext`, which is always either 16 or 0. This function returns an error
* if the ciphertext or tag buffer is not long enough.
*
* @param ctx Context object for the operation.
* @param tag_len Length of authentication tag to be generated.
* @param[out] ciphertext Encrypted output data.
* @param[out] ciphertext_bytes_written Number of bytes written to `ciphertext`.
* @param[out] auth_tag Generated authentication tag.
* @return Result of the final operation.
*/
otcrypto_status_t otcrypto_aes_gcm_encrypt_final(
otcrypto_aes_gcm_context_t *ctx, otcrypto_aes_gcm_tag_len_t tag_len,
otcrypto_byte_buf_t ciphertext, size_t *ciphertext_bytes_written,
otcrypto_word32_buf_t auth_tag);
sw/device/lib/crypto/include/aes.h#L347:
/**
* Finishes the AES-GCM authenticated decryption operation.
*
* Processes any remaining ciphertext from the context and computes the
* authentication tag and up to 1 block of plaintext.
*
* The caller should allocate space for the plaintext buffer and set the `len`
* field accordingly. This function returns the `ciphertext_bytes_written`
* parameter with the number of bytes written to `ciphertext`. This function
* returns an error if the plaintext buffer is not long enough.
*
* IMPORTANT: the caller must check both the returned status and the `success`
* parameter to know if the tag is valid. The returned status may be OK even if
* the tag check did not succeed, if there were no errors during processing.
*
* @param ctx Context object for the operation.
* @param auth_tag Authentication tag to check.
* @param tag_len Length of authentication tag.
* @param[out] plaintext Decrypted output data.
* @param[out] plaintext_bytes_written Number of bytes written to `plaintext`.
* @param[out] success Whether the tag passed verification.
* @return Result of the final operation.
*/
otcrypto_status_t otcrypto_aes_gcm_decrypt_final(
otcrypto_aes_gcm_context_t *ctx, otcrypto_const_word32_buf_t auth_tag,
otcrypto_aes_gcm_tag_len_t tag_len, otcrypto_byte_buf_t plaintext,
size_t *plaintext_bytes_written, hardened_bool_t *success);
AES-KWP
Key Wrap with Padding (KWP) mode is used for the protection of cryptographic keys. AES-KWP is specified in NIST SP800-38F.
sw/device/lib/crypto/include/aes.h#L359:
/**
* Returns the length that the blinded key will have once wrapped.
*
* @param config Key configuration.
* @param[out] wrapped_num_words Number of 32b words for the wrapped key.
* @return Result of the operation.
*/
otcrypto_status_t otcrypto_aes_kwp_wrapped_len(
const otcrypto_key_config_t config, size_t *wrapped_num_words);
sw/device/lib/crypto/include/aes.h#L380:
/**
* Performs the cryptographic key wrapping operation.
*
* This key wrap 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 according to
* `otcrypto_aes_kwp_wrapped_len`., and set the length of expected output
* in the `len` field of `wrapped_key`. If the user-set length and the
* output length do not match, an error message will be returned.
*
* The blinded key struct to wrap must be 32-bit aligned.
*
* @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 wrap operation.
*/
otcrypto_status_t otcrypto_aes_kwp_wrap(
const otcrypto_blinded_key_t *key_to_wrap,
const otcrypto_blinded_key_t *key_kek, otcrypto_word32_buf_t wrapped_key);
sw/device/lib/crypto/include/aes.h#L414:
/**
* Performs the cryptographic key unwrapping operation.
*
* This key unwrap function takes a wrapped key `wrapped_key` and using
* encryption key `key_kek` outputs an unwrapped key `unwrapped_key`.
*
* The caller must allocate space for the keyblob and set the keyblob-length
* and keyblob fields in `unwrapped_key` accordingly. If there is not enough
* space in the keyblob, this function will return an error. Too much space in
* the keyblob is okay; this function will write to the first part of the
* keyblob buffer and set the keyblob length field to the correct exact value
* for the unwrapped key, at which point it is safe to check the new length and
* free the remaining keyblob memory. It is always safe to allocate a keyblob
* the same size as the wrapped key; this will always be enough space by
* definition.
*
* The caller does not need to populate the blinded key configuration, since
* this information is encrypted along with the key. However, the caller may
* want to check that the configuration matches expectations.
*
* An OK status from this function does NOT necessarily mean that unwrapping
* succeeded; the caller must check both the returned status and the `success`
* parameter before reading the unwrapped key.
*
* @param wrapped_key Pointer to the input wrapped key.
* @param key_kek Input Pointer to the blinded encryption key.
* @param[out] success Whether the wrapped key was valid.
* @param[out] unwrapped_key Pointer to the output unwrapped key struct.
* @return Result of the aes-kwp unwrap operation.
*/
otcrypto_status_t otcrypto_aes_kwp_unwrap(
otcrypto_const_word32_buf_t wrapped_key,
const otcrypto_blinded_key_t *key_kek, hardened_bool_t *success,
otcrypto_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#L69:
/**
* Performs the required hash function on the input data.
*
* The caller should allocate space for the `digest` buffer and set the `mode`
* and `len` fields. If the length does not match the mode, an error message
* will be returned.
*
* This function should only be used for fixed-length hash functions (SHA-2 and
* SHA-3 families). Use `otcrypto_xof_shake` and `otcrypto_xof_cshake` for
* extendable-output functions.
*
* @param input_message Input message to be hashed.
* @param[out] digest Output digest after hashing the input message.
* @return Result of the hash operation.
*/
otcrypto_status_t otcrypto_hash(otcrypto_const_byte_buf_t input_message,
otcrypto_hash_digest_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#L84:
/**
* Performs the SHAKE extendable output function (XOF) on input data.
*
* The caller should allocate space for the `digest` buffer and set the `mode`
* and `len` fields. The `mode` parameter must be
* `kOtcryptoHashXofModeShake128` or `kOtcryptoHashXofModeShake256`; other
* values will result in errors.
*
* @param input_message Input message for extendable output function.
* @param[out] digest Output from the extendable output function.
* @return Result of the xof operation.
*/
otcrypto_status_t otcrypto_xof_shake(otcrypto_const_byte_buf_t input_message,
otcrypto_hash_digest_t digest);
sw/device/lib/crypto/include/hash.h#L106:
/**
* Performs the CSHAKE extendable output function (XOF) on 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 caller should allocate space for the `digest` buffer and set the `mode`
* and `len` fields. The `mode` parameter must be
* `kOtcryptoHashXofModeCshake128` or `kOtcryptoHashXofModeCshake256`; other
* values will result in errors.
*
* @param input_message Input message for extendable output function.
* @param function_name_string NIST Function name string.
* @param customization_string Customization string for cSHAKE.
* @param[out] digest Output from the extendable output function.
* @return Result of the xof operation.
*/
otcrypto_status_t otcrypto_xof_cshake(
otcrypto_const_byte_buf_t input_message,
otcrypto_const_byte_buf_t function_name_string,
otcrypto_const_byte_buf_t customization_string,
otcrypto_hash_digest_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#L128:
/**
* 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 `kOtcryptoHashModeSha256`,
* `kOtcryptoHashModeSha384` and `kOtcryptoHashModeSha512` 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.
*/
otcrypto_status_t otcrypto_hash_init(otcrypto_hash_context_t *const ctx,
otcrypto_hash_mode_t hash_mode);
sw/device/lib/crypto/include/hash.h#L145:
/**
* 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.
*/
otcrypto_status_t otcrypto_hash_update(otcrypto_hash_context_t *const ctx,
otcrypto_const_byte_buf_t input_message);
sw/device/lib/crypto/include/hash.h#L164:
/**
* 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 and set the `mode`
* and `len` fields. If the `mode` doesn't match the mode of the hash context,
* the function will return an error.
*
* @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.
*/
otcrypto_status_t otcrypto_hash_final(otcrypto_hash_context_t *const ctx,
otcrypto_hash_digest_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.
One-shot mode
sw/device/lib/crypto/include/mac.h#L68:
/**
* Performs the HMAC function on the input data.
*
* This function computes the HMAC function on the `input_message` using the
* `key` and returns a `tag`. The key should be at least as long as the digest
* for the chosen hash function. The hash function is determined by the key
* mode. Only SHA-2 hash functions are supported. Other modes (e.g. SHA-3) are
* not supported and will result in errors.
*
* The caller should allocate the following amount of space for the `tag`
* buffer, depending on which hash algorithm is used:
*
* SHA-256: 32 bytes
* SHA-384: 48 bytes
* SHA-512: 64 bytes
*
* The caller should also set the `len` field of `tag` to the equivalent number
* of 32-bit words (e.g. 8 for SHA-256).
*
* @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.
*/
otcrypto_status_t otcrypto_hmac(const otcrypto_blinded_key_t *key,
otcrypto_const_byte_buf_t input_message,
otcrypto_word32_buf_t tag);
sw/device/lib/crypto/include/mac.h#L99:
/**
* 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 be left empty (by settings its `data` to NULL and `length` to 0).
*
* The caller should set the `key_length` field of `key.config` to the number
* of bytes in the key. Only the following key sizes (in bytes) are supported:
* [16, 24, 32, 48, 64]. If any other size is given, the function will return
* an error.
*
* 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.
*/
otcrypto_status_t otcrypto_kmac(const otcrypto_blinded_key_t *key,
otcrypto_const_byte_buf_t input_message,
otcrypto_kmac_mode_t kmac_mode,
otcrypto_const_byte_buf_t customization_string,
size_t required_output_len,
otcrypto_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#L119:
/**
* Performs the INIT operation for HMAC.
*
* Initializes the HMAC context. The key should be at least as long as the
* digest for the chosen hash function. The hash function is determined by the
* key mode. Only SHA-2 hash functions are are supported. Other modes (e.g.
* SHA-3) are not supported and will result in errors.
*
* @param[out] ctx Pointer to the generic HMAC context struct.
* @param key Pointer to the blinded HMAC key struct.
* @param hash_mode Hash function to use.
* @return Result of the HMAC init operation.
*/
otcrypto_status_t otcrypto_hmac_init(otcrypto_hmac_context_t *ctx,
const otcrypto_blinded_key_t *key);
sw/device/lib/crypto/include/mac.h#L136:
/**
* 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.
*/
otcrypto_status_t otcrypto_hmac_update(otcrypto_hmac_context_t *const ctx,
otcrypto_const_byte_buf_t input_message);
sw/device/lib/crypto/include/mac.h#L156:
/**
* 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, (the length should
* match the hash function digest size), 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.
*/
otcrypto_status_t otcrypto_hmac_final(otcrypto_hmac_context_t *const ctx,
otcrypto_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 otcrypto_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.
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#L101:
/**
* Performs the RSA key generation.
*
* Computes RSA private key (d) and RSA public key exponent (e) and
* modulus (n).
*
* The caller should allocate space for the public key and set the `key` and
* `key_length` fields accordingly.
*
* The caller should fully populate the blinded key configuration and allocate
* space for the keyblob, setting `config.key_length` and `keyblob_length`
* accordingly.
*
* The value in the `checksum` field of key structs is not checked here and
* will be populated by the key generation function.
*
* @param size RSA size parameter.
* @param[out] public_key Pointer to public key struct.
* @param[out] private_key Pointer to blinded private key struct.
* @return Result of the RSA key generation.
*/
otcrypto_status_t otcrypto_rsa_keygen(otcrypto_rsa_size_t size,
otcrypto_unblinded_key_t *public_key,
otcrypto_blinded_key_t *private_key);
sw/device/lib/crypto/include/rsa.h#L117:
/**
* Constructs an RSA public key from the modulus and public exponent.
*
* The caller should allocate space for the public key and set the `key` and
* `key_length` fields accordingly.
*
* @param size RSA size parameter.
* @param modulus RSA modulus (n).
* @param exponent RSA public exponent (e).
* @param[out] public_key Destination public key struct.
* @return Result of the RSA key construction.
*/
otcrypto_status_t otcrypto_rsa_public_key_construct(
otcrypto_rsa_size_t size, otcrypto_const_word32_buf_t modulus,
uint32_t exponent, otcrypto_unblinded_key_t *public_key);
sw/device/lib/crypto/include/rsa.h#L135:
/**
* Constructs an RSA private key from the modulus and public/private exponents.
*
* The caller should allocate space for the private key and set the `keyblob`,
* `keyblob_length`, and `key_length` fields accordingly.
*
* @param size RSA size parameter.
* @param modulus RSA modulus (n).
* @param exponent RSA public exponent (e).
* @param d_share0 First share of the RSA private exponent d.
* @param d_share1 Second share of the RSA private exponent d.
* @param[out] public_key Destination public key struct.
* @return Result of the RSA key construction.
*/
otcrypto_status_t otcrypto_rsa_private_key_from_exponents(
otcrypto_rsa_size_t size, otcrypto_const_word32_buf_t modulus, uint32_t e,
otcrypto_const_word32_buf_t d_share0, otcrypto_const_word32_buf_t d_share1,
otcrypto_blinded_key_t *private_key);
sw/device/lib/crypto/include/rsa.h#L177:
/**
* Computes the digital signature on the input message data.
*
* The caller should allocate space for the `signature` buffer
* 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 private_key Pointer to blinded private key struct.
* @param message_digest Message digest to be signed (pre-hashed).
* @param padding_mode Padding scheme to be used for the data.
* @param[out] signature Pointer to the generated signature struct.
* @return The result of the RSA signature generation.
*/
otcrypto_status_t otcrypto_rsa_sign(const otcrypto_blinded_key_t *private_key,
const otcrypto_hash_digest_t message_digest,
otcrypto_rsa_padding_t padding_mode,
otcrypto_word32_buf_t signature);
sw/device/lib/crypto/include/rsa.h#L196:
/**
* Verifies the authenticity of the input signature.
*
* An "OK" status code does not mean that the signature passed verification;
* the caller must check both the returned status and `verification_result`
* before trusting the signature.
*
* @param public_key Pointer to public key struct.
* @param message_digest Message digest to be verified (pre-hashed).
* @param padding_mode Padding scheme to be used for the data.
* @param signature Pointer to the input signature to be verified.
* @param[out] verification_result Result of signature verification.
* @return Result of the RSA verify operation.
*/
otcrypto_status_t otcrypto_rsa_verify(
const otcrypto_unblinded_key_t *public_key,
const otcrypto_hash_digest_t message_digest,
otcrypto_rsa_padding_t padding_mode, otcrypto_const_word32_buf_t signature,
hardened_bool_t *verification_result);
RSA Asynchronous API
sw/device/lib/crypto/include/rsa.h#L282:
/**
* 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).
*
* @param size RSA size parameter.
* @return Result of async RSA keygen start operation.
*/
otcrypto_status_t otcrypto_rsa_keygen_async_start(otcrypto_rsa_size_t size);
sw/device/lib/crypto/include/rsa.h#L294:
/**
* Finalizes the asynchronous RSA key generation function.
*
* See `otcrypto_rsa_keygen` for details on the requirements for `public_key`
* and `private_key`.
*
* @param[out] public_key Pointer to public key struct.
* @param[out] private_key Pointer to blinded private key struct.
* @return Result of asynchronous RSA keygen finalize operation.
*/
otcrypto_status_t otcrypto_rsa_keygen_async_finalize(
otcrypto_unblinded_key_t *public_key, otcrypto_blinded_key_t *private_key);
sw/device/lib/crypto/include/rsa.h#L345:
/**
* Starts the asynchronous digital signature generation function.
*
* Initializes OTBN and starts the OTBN routine to compute the digital
* signature on the input message.
*
* @param private_key Pointer to blinded private key struct.
* @param message_digest Message digest to be signed (pre-hashed).
* @param padding_mode Padding scheme to be used for the data.
* @return Result of async RSA sign start operation.
*/
otcrypto_status_t otcrypto_rsa_sign_async_start(
const otcrypto_blinded_key_t *private_key,
const otcrypto_hash_digest_t message_digest,
otcrypto_rsa_padding_t padding_mode);
sw/device/lib/crypto/include/rsa.h#L358:
/**
* Finalizes the asynchronous digital signature generation function.
*
* See `otcrypto_rsa_sign` for details on the requirements for `signature`.
*
* @param[out] signature Pointer to generated signature struct.
* @return Result of async RSA sign finalize operation.
*/
otcrypto_status_t otcrypto_rsa_sign_async_finalize(
otcrypto_word32_buf_t signature);
sw/device/lib/crypto/include/rsa.h#L371:
/**
* Starts the asynchronous signature verification function.
*
* Initializes OTBN and starts the OTBN routine to recover the message
* from the input signature.
*
* @param public_key Pointer to public key struct.
* @param signature Pointer to the input signature to be verified.
* @return Result of async RSA verify start operation.
*/
otcrypto_status_t otcrypto_rsa_verify_async_start(
const otcrypto_unblinded_key_t *public_key,
otcrypto_const_word32_buf_t signature);
sw/device/lib/crypto/include/rsa.h#L387:
/**
* Finalizes the asynchronous signature verification function.
*
* An "OK" status code does not mean that the signature passed verification;
* the caller must check both the returned status and `verification_result`
* before trusting the signature.
*
* @param message_digest Message digest to be verified (pre-hashed).
* @param padding_mode Padding scheme to be used for the data.
* @param[out] verification_result Result of signature verification.
* @return Result of async RSA verify finalize operation.
*/
otcrypto_status_t otcrypto_rsa_verify_async_finalize(
const otcrypto_hash_digest_t message_digest,
otcrypto_rsa_padding_t padding_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#L109:
/**
* 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. If the key is hardware-backed, the caller should pass a fully
* populated private key handle as returned by `otcrypto_hw_backed_key`. 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.
*/
otcrypto_status_t otcrypto_ecdsa_keygen(
const otcrypto_ecc_curve_t *elliptic_curve,
otcrypto_blinded_key_t *private_key, otcrypto_unblinded_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L133:
/**
* 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`.
*
* The message digest must be exactly the right length for the curve in use
* (e.g. 256 bits for P-256), but may use any hash mode. The caller is
* responsible for ensuring that the security strength of the hash function is
* at least equal to the security strength of the curve. See FIPS 186-5 for
* details.
*
* @param private_key Pointer to the blinded private key (d) struct.
* @param message_digest Message digest to be signed (pre-hashed).
* @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.
*/
otcrypto_status_t otcrypto_ecdsa_sign(
const otcrypto_blinded_key_t *private_key,
const otcrypto_hash_digest_t message_digest,
const otcrypto_ecc_curve_t *elliptic_curve,
otcrypto_word32_buf_t signature);
sw/device/lib/crypto/include/ecc.h#L161:
/**
* 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`.
*
* The message digest must be exactly the right length for the curve in use
* (e.g. 256 bits for P-256), but may use any hash mode. The caller is
* responsible for ensuring that the security strength of the hash function is
* at least equal to the security strength of the curve. See FIPS 186-5 for
* details.
*
* @param public_key Pointer to the unblinded public key (Q) struct.
* @param message_digest Message digest to be verified (pre-hashed).
* @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.
*/
otcrypto_status_t otcrypto_ecdsa_verify(
const otcrypto_unblinded_key_t *public_key,
const otcrypto_hash_digest_t message_digest,
otcrypto_const_word32_buf_t signature,
const otcrypto_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#L193:
/**
* 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. If the key is hardware-backed, the caller should pass a fully
* populated private key handle as returned by `otcrypto_hw_backed_key`. 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.
*/
otcrypto_status_t otcrypto_ecdh_keygen(
const otcrypto_ecc_curve_t *elliptic_curve,
otcrypto_blinded_key_t *private_key, otcrypto_unblinded_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L211:
/**
* 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.
*/
otcrypto_status_t otcrypto_ecdh(const otcrypto_blinded_key_t *private_key,
const otcrypto_unblinded_key_t *public_key,
const otcrypto_ecc_curve_t *elliptic_curve,
otcrypto_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#L239:
/**
* 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. If the key is hardware-backed, the caller should pass a fully
* populated private key handle as returned by `otcrypto_hw_backed_key`. 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.
*/
otcrypto_status_t otcrypto_ed25519_keygen(otcrypto_blinded_key_t *private_key,
otcrypto_unblinded_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L252:
/**
* 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.
*/
otcrypto_status_t otcrypto_ed25519_sign(
const otcrypto_blinded_key_t *private_key,
otcrypto_const_byte_buf_t input_message,
otcrypto_eddsa_sign_mode_t sign_mode, otcrypto_word32_buf_t signature);
sw/device/lib/crypto/include/ecc.h#L269:
/**
* 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.
*/
otcrypto_status_t otcrypto_ed25519_verify(
const otcrypto_unblinded_key_t *public_key,
otcrypto_const_byte_buf_t input_message,
otcrypto_eddsa_sign_mode_t sign_mode, otcrypto_const_word32_buf_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#L298:
/**
* 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. If the key is hardware-backed, the caller should pass a fully
* populated private key handle as returned by `otcrypto_hw_backed_key`. 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.
*/
otcrypto_status_t otcrypto_x25519_keygen(otcrypto_blinded_key_t *private_key,
otcrypto_unblinded_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L310:
/**
* 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.
*/
otcrypto_status_t otcrypto_x25519(const otcrypto_blinded_key_t *private_key,
const otcrypto_unblinded_key_t *public_key,
otcrypto_blinded_key_t *shared_secret);
ECC Asynchronous API
ECDSA
sw/device/lib/crypto/include/ecc.h#L336:
/**
* Starts the asynchronous key generation for ECDSA operation.
*
* Initializes OTBN and begins generating an ECDSA key pair. The caller should
* set the `config` field of `private_key` with their desired key configuration
* options. If the key is hardware-backed, the caller should pass a fully
* populated private key handle such as the kind returned by
* `otcrypto_hw_backed_key`.
*
* 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 `kOtcryptoStatusValueOk` if the operation was successfully
* started, or`kOtcryptoStatusValueInternalError` if the operation cannot be
* started.
*
* @param elliptic_curve Pointer to the elliptic curve to be used.
* @param private_key Destination structure for private key, or key handle.
* @return Result of asynchronous ECDSA keygen start operation.
*/
otcrypto_status_t otcrypto_ecdsa_keygen_async_start(
const otcrypto_ecc_curve_t *elliptic_curve,
const otcrypto_blinded_key_t *private_key);
sw/device/lib/crypto/include/ecc.h#L359:
/**
* Finalizes the asynchronous key generation for ECDSA operation.
*
* Returns `kOtcryptoStatusValueOk` and copies the private key (d) and public
* key (Q), if the OTBN status is done, or
* `kOtcryptoStatusValueAsyncIncomplete` if the OTBN is busy or
* `kOtcryptoStatusValueInternalError` 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.
*/
otcrypto_status_t otcrypto_ecdsa_keygen_async_finalize(
const otcrypto_ecc_curve_t *elliptic_curve,
otcrypto_blinded_key_t *private_key, otcrypto_unblinded_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L377:
/**
* 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 message_digest Message digest to be signed (pre-hashed).
* @param elliptic_curve Pointer to the elliptic curve to be used.
* @return Result of async ECDSA start operation.
*/
otcrypto_status_t otcrypto_ecdsa_sign_async_start(
const otcrypto_blinded_key_t *private_key,
const otcrypto_hash_digest_t message_digest,
const otcrypto_ecc_curve_t *elliptic_curve);
sw/device/lib/crypto/include/ecc.h#L398:
/**
* Finalizes the asynchronous ECDSA digital signature generation.
*
* Returns `kOtcryptoStatusValueOk` and copies the signature if the OTBN
* status is done, or `kOtcryptoStatusValueAsyncIncomplete` if the OTBN is
* busy or `kOtcryptoStatusValueInternalError` 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.
*/
otcrypto_status_t otcrypto_ecdsa_sign_async_finalize(
const otcrypto_ecc_curve_t *elliptic_curve,
otcrypto_word32_buf_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 message_digest Message digest to be verified (pre-hashed).
* @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.
*/
otcrypto_status_t otcrypto_ecdsa_verify_async_start(
const otcrypto_unblinded_key_t *public_key,
const otcrypto_hash_digest_t message_digest,
otcrypto_const_word32_buf_t signature,
const otcrypto_ecc_curve_t *elliptic_curve);
sw/device/lib/crypto/include/ecc.h#L442:
/**
* Finalizes the asynchronous ECDSA digital signature verification.
*
* Returns `kOtcryptoStatusValueOk` and populates the `verification result`
* if the OTBN status is done. `kOtcryptoStatusValueAsyncIncomplete` if the
* OTBN is busy or `kOtcryptoStatusValueInternalError` 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.
*/
otcrypto_status_t otcrypto_ecdsa_verify_async_finalize(
const otcrypto_ecc_curve_t *elliptic_curve,
otcrypto_const_word32_buf_t signature,
hardened_bool_t *verification_result);
ECDH
sw/device/lib/crypto/include/ecc.h#L469:
/**
* Starts the asynchronous key generation for ECDH operation.
*
* Initializes OTBN and begins generating an ECDH key pair. The caller should
* set the `config` field of `private_key` with their desired key configuration
* options. If the key is hardware-backed, the caller should pass a fully
* populated private key handle such as the kind returned by
* `otcrypto_hw_backed_key`.
*
* 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 `kOtcryptoStatusValueOk` if the operation was successfully
* started, or`kOtcryptoStatusValueInternalError` if the operation cannot be
* started.
*
* @param elliptic_curve Pointer to the elliptic curve to be used.
* @param private_key Destination structure for private key, or key handle.
* @return Result of asynchronous ECDH keygen start operation.
*/
otcrypto_status_t otcrypto_ecdh_keygen_async_start(
const otcrypto_ecc_curve_t *elliptic_curve,
const otcrypto_blinded_key_t *private_key);
sw/device/lib/crypto/include/ecc.h#L492:
/**
* Finalizes the asynchronous key generation for ECDSA operation.
*
* Returns `kOtcryptoStatusValueOk` and copies the private key (d) and public
* key (Q), if the OTBN status is done, or
* `kOtcryptoStatusValueAsyncIncomplete` if the OTBN is busy or
* `kOtcryptoStatusValueInternalError` 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.
*/
otcrypto_status_t otcrypto_ecdh_keygen_async_finalize(
const otcrypto_ecc_curve_t *elliptic_curve,
otcrypto_blinded_key_t *private_key, otcrypto_unblinded_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L510:
/**
* 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.
*/
otcrypto_status_t otcrypto_ecdh_async_start(
const otcrypto_blinded_key_t *private_key,
const otcrypto_unblinded_key_t *public_key,
const otcrypto_ecc_curve_t *elliptic_curve);
sw/device/lib/crypto/include/ecc.h#L532:
/**
* Finalizes the asynchronous Elliptic Curve Diffie Hellman shared
* secret generation.
*
* Returns `kOtcryptoStatusValueOk` and copies `shared_secret` if the OTBN
* status is done, or `kOtcryptoStatusValueAsyncIncomplete` if the OTBN
* is busy or `kOtcryptoStatusValueInternalError` 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.
*/
otcrypto_status_t otcrypto_ecdh_async_finalize(
const otcrypto_ecc_curve_t *elliptic_curve,
otcrypto_blinded_key_t *shared_secret);
Ed25519
sw/device/lib/crypto/include/ecc.h#L551:
/**
* Starts the asynchronous key generation for Ed25519.
*
* Initializes OTBN and begins generating an Ed25519 key pair. The caller
* should set the `config` field of `private_key` with their desired key
* configuration options. If the key is hardware-backed, the caller should pass
* a fully populated private key handle such as the kind returned by
* `otcrypto_hw_backed_key`.
*
* No `domain_parameter` is needed and is automatically set for X25519.
*
* @param private_key Destination structure for private key, or key handle.
* @return Result of asynchronous ed25519 keygen start operation.
*/
otcrypto_status_t otcrypto_ed25519_keygen_async_start(
const otcrypto_blinded_key_t *private_key);
sw/device/lib/crypto/include/ecc.h#L570:
/**
* Finalizes the asynchronous key generation for Ed25519.
*
* Returns `kOtcryptoStatusValueOk` and copies private key (d) and public key
* (Q), if the OTBN status is done, or `kOtcryptoStatusValueAsyncIncomplete`
* if the OTBN is busy or `kOtcryptoStatusValueInternalError` 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.
*/
otcrypto_status_t otcrypto_ed25519_keygen_async_finalize(
otcrypto_blinded_key_t *private_key, otcrypto_unblinded_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L587:
/**
* 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.
*/
otcrypto_status_t otcrypto_ed25519_sign_async_start(
const otcrypto_blinded_key_t *private_key,
otcrypto_const_byte_buf_t input_message,
otcrypto_eddsa_sign_mode_t sign_mode, otcrypto_word32_buf_t signature);
sw/device/lib/crypto/include/ecc.h#L603:
/**
* Finalizes the asynchronous Ed25519 digital signature generation.
*
* Returns `kOtcryptoStatusValueOk` and copies the signature if the OTBN
* status is done, or `kOtcryptoStatusValueAsyncIncomplete` if the OTBN is
* busy or `kOtcryptoStatusValueInternalError` if there is an error.
*
* @param[out] signature Pointer to the EdDSA signature to get (s) value.
* @return Result of async Ed25519 finalize operation.
*/
otcrypto_status_t otcrypto_ed25519_sign_async_finalize(
otcrypto_word32_buf_t signature);
sw/device/lib/crypto/include/ecc.h#L619:
/**
* 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.
*/
otcrypto_status_t otcrypto_ed25519_verify_async_start(
const otcrypto_unblinded_key_t *public_key,
otcrypto_const_byte_buf_t input_message,
otcrypto_eddsa_sign_mode_t sign_mode,
otcrypto_const_word32_buf_t signature);
sw/device/lib/crypto/include/ecc.h#L638:
/**
* Finalizes the asynchronous Ed25519 digital signature verification.
*
* Returns `kOtcryptoStatusValueOk` and populates the `verification result`
* with a PASS or FAIL, if the OTBN status is done,
* `kOtcryptoStatusValueAsyncIncomplete` if the OTBN is busy or
* `kOtcryptoStatusValueInternalError` if there is an error.
*
* @param[out] verification_result Result of signature verification
* (Pass/Fail).
* @return Result of async Ed25519 verification finalize operation.
*/
otcrypto_status_t otcrypto_ed25519_verify_async_finalize(
hardened_bool_t *verification_result);
X25519
sw/device/lib/crypto/include/ecc.h#L656:
/**
* Starts the asynchronous key generation for X25519.
*
* Initializes OTBN and begins generating an X25519 key pair. The caller
* should set the `config` field of `private_key` with their desired key
* configuration options. If the key is hardware-backed, the caller should pass
* a fully populated private key handle such as the kind returned by
* `otcrypto_hw_backed_key`.
*
* No `domain_parameter` is needed and is automatically set for X25519.
*
* @param private_key Destination structure for private key, or key handle.
* @return Result of asynchronous X25519 keygen start operation.
*/
otcrypto_status_t otcrypto_x25519_keygen_async_start(
const otcrypto_blinded_key_t *private_key);
sw/device/lib/crypto/include/ecc.h#L675:
/**
* Finalizes the asynchronous key generation for X25519.
*
* Returns `kOtcryptoStatusValueOk` and copies private key (d) and public key
* (Q), if the OTBN status is done, or `kOtcryptoStatusValueAsyncIncomplete`
* if the OTBN is busy or `kOtcryptoStatusValueInternalError` 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.
*/
otcrypto_status_t otcrypto_x25519_keygen_async_finalize(
otcrypto_blinded_key_t *private_key, otcrypto_unblinded_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L691:
/**
* 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.
*/
otcrypto_status_t otcrypto_x25519_async_start(
const otcrypto_blinded_key_t *private_key,
const otcrypto_unblinded_key_t *public_key);
sw/device/lib/crypto/include/ecc.h#L707:
/**
* Finalizes the asynchronous X25519 Diffie Hellman shared secret
* generation.
*
* Returns `kOtcryptoStatusValueOk` and copies `shared_secret` if the OTBN
* status is done, or `kOtcryptoStatusValueAsyncIncomplete` if the OTBN
* is busy or `kOtcryptoStatusValueInternalError` if there is an error.
*
* @param[out] shared_secret Pointer to shared secret key (u-coordinate).
* @return Result of async X25519 finalize operation.
*/
otcrypto_status_t otcrypto_x25519_async_finalize(
otcrypto_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#L31:
/**
* Instantiates the DRBG system.
*
* Initializes the DRBG and the context for DRBG. Gets the required entropy
* input automatically from the entropy source.
*
* The personalization string may empty, and may be up to 48 bytes long; any
* longer will result in an error.
*
* @param perso_string Pointer to personalization bitstring.
* @return Result of the DRBG instantiate operation.
*/
otcrypto_status_t otcrypto_drbg_instantiate(
otcrypto_const_byte_buf_t perso_string);
sw/device/lib/crypto/include/drbg.h#L43:
/**
* 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.
*/
otcrypto_status_t otcrypto_drbg_reseed(
otcrypto_const_byte_buf_t additional_input);
sw/device/lib/crypto/include/drbg.h#L97:
/**
* DRBG function for generating random bits.
*
* This function checks the hardware flags for FIPS compatibility of the
* generated bits, so it will fail after `otcrypto_drbg_manual_instantiate` or
* `otcrypto_drbg_manual_reseed`.
*
* The caller should allocate space for the `drbg_output` buffer and set the
* length of expected output in the `len` field.
*
* The output is generated in 16-byte blocks; if `drbg_output->len` is not a
* multiple of 4, 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[out] drbg_output Pointer to the generated pseudo random bits.
* @return Result of the DRBG generate operation.
*/
otcrypto_status_t otcrypto_drbg_generate(
otcrypto_const_byte_buf_t additional_input,
otcrypto_word32_buf_t drbg_output);
sw/device/lib/crypto/include/drbg.h#L128:
/**
* Uninstantiates DRBG and clears the context.
*
* @return Result of the DRBG uninstantiate operation.
*/
otcrypto_status_t otcrypto_drbg_uninstantiate(void);
Manual Entropy Operations
sw/device/lib/crypto/include/drbg.h#L61:
/**
* Instantiates the DRBG system.
*
* Initializes DRBG and the DRBG context. Gets the required entropy input from
* the user through the `entropy` parameter. Calling this function breaks FIPS
* compliance until the DRBG is uninstantiated.
*
* 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.
*/
otcrypto_status_t otcrypto_drbg_manual_instantiate(
otcrypto_const_byte_buf_t entropy, otcrypto_const_byte_buf_t perso_string);
sw/device/lib/crypto/include/drbg.h#L75:
/**
* Reseeds the DRBG with fresh entropy.
*
* Reseeds the DRBG with entropy input from the user through the `entropy`
* parameter and updates the working state parameters. Calling this function
* breaks FIPS compliance until the DRBG is uninstantiated.
*
* @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.
*/
otcrypto_status_t otcrypto_drbg_manual_reseed(
otcrypto_const_byte_buf_t entropy,
otcrypto_const_byte_buf_t additional_input);
Key derivation
Key derivation functions (KDFs) generate a new key from an existing key.
Supported Modes
OpenTitan supports two different key derivation methods:
- KDF-CTR following NIST SP800-108 with HMAC or KMAC as the PRF
- HKDF following IETF RFC 5869, which is special case of NIST SP800-56C
To learn more about PRFs, various key derivation mechanisms and security considerations, please refer to the links in the reference section.
API
KDF-CTR
sw/device/lib/crypto/include/kdf.h#L48:
/**
* Performs the key derivation function in counter mode wtih HMAC according to
* NIST SP 800-108r1.
*
* The supported PRF engine for the KDF function is HMAC (since KMAC does not
* use the counter mode).
*
* 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
* expectations. If the key is hardware-backed, the caller should pass a fully
* populated private key handle such as the kind returned by
* `otcrypto_hw_backed_key`. 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 Blinded key derivation key.
* @param kdf_label Label string according to SP 800-108r1.
* @param kdf_context Context string according to SP 800-108r1.
* @param required_byte_len Required length of the derived key in bytes.
* @param[out] keying_material Pointer to the blinded keying material to be
* populated by this function.
* @return Result of the key derivation operation.
*/
otcrypto_status_t otcrypto_kdf_hmac_ctr(
const otcrypto_blinded_key_t key_derivation_key,
const otcrypto_const_byte_buf_t kdf_label,
const otcrypto_const_byte_buf_t kdf_context, size_t required_byte_len,
otcrypto_blinded_key_t *keying_material);
sw/device/lib/crypto/include/kdf.h#L94:
/**
* Performs the key derivation function with single KMAC invocation according to
* NIST SP 800-108r1.
*
* This function initially validates the `key_derivation_key` struct, by
* checking for NULL pointers, checking whether key length and its
* keyblob_length match each other, verifying its checksum etc. Moreover, its
* `hw_backed` field is used to determine whether the derivation key comes from
* Keymgr. In that case, this function requests Keymgr to generate the key
* according to diversification values passed in keyblob.
* (see `keyblob_buffer_to_keymgr_diversification` function in `keyblob.h`).
* For non-hardware-backed keys, the keyblob should be twice the length of the
* key.
*
* `kmac_mode` input argument is used to decide whether KMAC128 or KMAC256 is
* used and it is also checked against `key_mode` from `key_derivation_key`.
*
* The produced key is returned in the `keying_material` blinded key struct.
* The caller should allocate and partially populate `keying_material`,
* including populating the key configuration and allocating space for the
* keyblob. The key length is also checked against `required_byte_len`. The
* value in the `checksum` field of the blinded key struct will be populated
* by this function. The use case where `keying_material` needs to be hw-backed
* is not supported by this function, hence `hw_backed` must be set tofalse.
* See `otcrypto_hw_backed_key` from `key_transport` for that specific use case.
*
* Note that it is the responsibility of the user of `keying_material` to
* further validate the key configuration. While populating the key, this
* function ignores `exportable`, `key_mode`, and `security_level` fields
* therefore the users must validate their `keying_material` config before use.
*
* @param key_derivation_key Blinded key derivation key.
* @param kmac_mode Either KMAC128 or KMAC256 as PRF.
* @param kdf_label Label string according to SP 800-108r1.
* @param kdf_context Context string according to SP 800-108r1.
* @param required_byte_len Required length of the derived key in bytes.
* @param[out] keying_material Pointer to the blinded keying material to be
* populated by this function.
* @return Result of the key derivation operation.
*/
otcrypto_status_t otcrypto_kdf_kmac(
const otcrypto_blinded_key_t key_derivation_key,
otcrypto_kmac_mode_t kmac_mode, const otcrypto_const_byte_buf_t kdf_label,
const otcrypto_const_byte_buf_t kdf_context, size_t required_byte_len,
otcrypto_blinded_key_t *keying_material);
HKDF
sw/device/lib/crypto/include/kdf.h#L127:
/**
* Performs HKDF in one shot, both expand and extract stages.
*
* HKDF is defined in IETF RFC 5869 and is based on HMAC. The HMAC hash
* function is determined by the mode of the key derivation key, e.g. the key
* mode `kOtcryptoKeyModeHmacSha256` results in HMAC with SHA-256. The key mode
* for the output pseudo-random key (PRK) should match the key mode for the
* input key derivation key.
*
* The caller should allocate and partially populate the `prk` blinded key
* struct, including populating the key configuration and allocating space for
* the keyblob. The PRK configuration may not indicate a hardware-backed key.
* The allocated keyblob length should be twice the length of the hash function
* digest length.
* The caller should allocate and partially populate the `derived_key` blinded
* key struct, including populating the key configuration and allocating space
* for the keyblob. The key configuration may not indicate a hardware-backed
* key. The allocated keyblob length should be twice the key length indicated
* in the key configuration, and this key length must not be longer than
* 255*<length of hash digest> as per the RFC.
*
* @param key_derivation_key Blinded key derivation key.
* @param salt Salt value (optional, may be empty).
* @param info Context-specific string (optional, may be empty).
* @param[out] derived_key Derived keying material.
* @return Result of the key derivation operation.
*/
otcrypto_status_t otcrypto_kdf_hkdf(
const otcrypto_blinded_key_t key_derivation_key,
otcrypto_const_byte_buf_t salt, otcrypto_const_byte_buf_t info,
otcrypto_blinded_key_t *derived_key);
sw/device/lib/crypto/include/kdf.h#L156:
/**
* Performs the "extract" step of HKDF.
*
* HKDF is defined in IETF RFC 5869 and is based on HMAC. The HMAC hash
* function is determined by the mode of the key derivation key, e.g. the key
* mode `kOtcryptoKeyModeHmacSha256` results in HMAC with SHA-256. The key mode
* for the output pseudo-random key (PRK) should match the key mode for the
* input key derivation key.
*
* The resulting pseudo-random key is then input for the "expand" step of HKDF.
* The length of PRK is the same as the digest length for the specified hash
* function (e.g. 256 bits for SHA-256).
*
* The caller should allocate and partially populate the `prk` blinded key
* struct, including populating the key configuration and allocating space for
* the keyblob. The PRK configuration may not indicate a hardware-backed key.
* The allocated keyblob length should be twice the length of the hash function
* digest length.
*
* @param ikm Blinded input key material.
* @param salt Salt value (optional, may be empty).
* @param[out] prk Extracted pseudo-random key.
* @return Result of the key derivation operation.
*/
otcrypto_status_t otcrypto_kdf_hkdf_extract(const otcrypto_blinded_key_t ikm,
otcrypto_const_byte_buf_t salt,
otcrypto_blinded_key_t *prk);
sw/device/lib/crypto/include/kdf.h#L182:
/**
* Performs the "expand" step of HKDF.
*
* HKDF is defined in IETF RFC 5869 and is based on HMAC. The HMAC hash
* function is inferred from the key mode of the pseudo-random key (PRK).
*
* The input pseudo-random key should be generated from the "extract" step of
* HKDF. Its length should always be the same as the digest length of the hash
* function.
*
* The caller should allocate and partially populate the `okm` blinded key
* struct, including populating the key configuration and allocating space for
* the keyblob. The key configuration may not indicate a hardware-backed key.
* The allocated keyblob length should be twice the key length indicated in the
* key configuration, and this key length must not be longer than 255*<length
* of hash digest> as per the RFC.
*
* @param prk Pseudo-random key from HKDF-extract.
* @param info Context-specific string (optional).
* @param[out] okm Blinded output key material.
* @return Result of the key derivation operation.
*/
otcrypto_status_t otcrypto_kdf_hkdf_expand(const otcrypto_blinded_key_t prk,
otcrypto_const_byte_buf_t info,
otcrypto_blinded_key_t *okm);
Key transport
This is the interface for generating, importing, and exporting crypto library symmetric keys. Asymmetric schemes (e.g. RSA or elliptic-curve cryptography) use algorithm-specific routines for key generation; refer to the RSA and ECC sections instead to generate, import, or export asymmetric keys.
The crypto library represents private keys in masked form (“blinded keys”). The internal structure of blinded keys is opaque to the user and may change in subsequent versions of the crypto library. The caller can control certain characteristics of the generated key via the key configuration. See the key data structures section for more details.
Generate random keys
sw/device/lib/crypto/include/key_transport.h#L49:
/**
* Generates a new, random symmetric key.
*
* Use this only for symmetric algorithms (e.g. AES, HMAC, KMAC). Asymmetric
* algorithms (e.g. ECDSA, RSA) have their own specialized key-generation
* routines. Cannot be used for hardware-backed keys; use
* `otcrypto_hw_backed_key` instead to generate these.
*
* The caller should allocate space for the keyblob and populate the blinded
* key struct with the length of the keyblob, the pointer to the keyblob
* buffer, and the key configuration. The value in the `checksum` field of
* the blinded key struct will be populated by the key generation function.
* The keyblob should be twice the length of the unblinded key. This function
* will return an error if the keyblob length does not match expectations based
* on the key mode and configuration.
*
* The keyblob should be twice the length of the key. The caller only needs to
* allocate the keyblob, not populate it.
*
* The personalization string may empty, and may be up to 48 bytes long; any
* longer will result in an error. It is passed as an extra seed input to the
* DRBG, in addition to the hardware TRNG.
*
* @param perso_string Optional personalization string to be passed to DRBG.
* @param[out] key Destination blinded key struct.
* @return The result of the operation.
*/
otcrypto_status_t otcrypto_symmetric_keygen(
otcrypto_const_byte_buf_t perso_string, otcrypto_blinded_key_t *key);
Package hardware-backed keys
sw/device/lib/crypto/include/key_transport.h#L74:
/**
* Creates a handle for a hardware-backed key.
*
* This routine may be used for both symmetric and asymmetric algorithms, since
* conceptually it only creates some data that the key manager can use to
* generate key material at the time of use. However, not all algorithms are
* suitable for hardware-backed keys (for example, RSA is not suitable), so
* some choices of algorithm may result in errors.
*
* The caller should partially populate the blinded key struct; they should set
* the full key configuration and the keyblob length (always 32 bytes), and
* then allocate 32 bytes of space for the keyblob and set the keyblob pointer.
*
* This function will populate the `checksum` field and copy the salt/version
* data into the keyblob buffer in the specific order that the rest of
* cryptolib expects.
*
* @param version Key version.
* @param salt Key salt (diversification data for KDF).
* @param[out] key Destination blinded key struct.
* @return The result of the operation.
*/
otcrypto_status_t otcrypto_hw_backed_key(uint32_t version,
const uint32_t salt[7],
otcrypto_blinded_key_t *key);
Import Symmetric Keys
sw/device/lib/crypto/include/key_transport.h#L95:
/**
* Creates a blinded key struct from masked key material.
*
* The caller should allocate and partially populate the blinded key struct,
* including populating the key configuration and allocating space for the
* keyblob. The keyblob should be twice the length of the user key.
* Hardware-backed and asymmetric (ECC or RSA) keys cannot be imported this
* way. For asymmetric keys, use algorithm-specific key construction methods.
*
* This function will copy the data from the shares into the keyblob; it is
* safe to free `key_share0` and `key_share1` after this call.
*
* @param key_share0 First share of the user provided key.
* @param key_share1 Second share of the user provided key.
* @param[out] blinded_key Generated blinded key struct.
* @return Result of the blinded key import operation.
*/
otcrypto_status_t otcrypto_import_blinded_key(
const otcrypto_const_word32_buf_t key_share0,
const otcrypto_const_word32_buf_t key_share1,
otcrypto_blinded_key_t *blinded_key);
Export Symmetric Keys
sw/device/lib/crypto/include/key_transport.h#L115:
/**
* Exports a blinded key to the user provided key buffer, in shares.
*
* This function will copy data from the keyblob into the shares; after the
* call, it is safe to free the blinded key and the data pointed to by
* `blinded_key.keyblob`.
*
* Hardware-backed, non-exportable, and asymmetric (ECC or RSA) keys cannot be
* exported this way. For asymmetric keys, use an algorithm-specific funtion.
*
* @param blinded_key Blinded key struct to be exported.
* @param[out] key_share0 First share of the blinded key.
* @param[out] key_share1 Second share of the blinded key.
* @return Result of the blinded key export operation.
*/
otcrypto_status_t otcrypto_export_blinded_key(
const otcrypto_blinded_key_t blinded_key, otcrypto_word32_buf_t key_share0,
otcrypto_word32_buf_t key_share1);
Some blinded keys are marked as non-exportable in their configurations. The crypto library will always refuse to export these keys.
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 |
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
- NIST SP800-56C: Recommendation for Key-Derivation Methods in Key-Establishment Schemes
- RFC 5869: HMAC-based Extract-and-Expand Key Derivation Function (HKDF)
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)