Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
afe5015
[pentest] Add masking
siemen11 May 21, 2026
cc18d9f
[crypto/doc] Add info on the FIPS build
siemen11 May 21, 2026
255b75c
[crypto] Add transitive feature to binary blob
siemen11 May 21, 2026
688732b
[crypto/kat] Add ed25519
siemen11 May 21, 2026
b2a80dd
[crypto/otbn] Split a2b and b2a p256 in separate files
siemen11 May 20, 2026
02fa995
[crypto/25519] Propagate the masking in x25519
siemen11 May 11, 2026
fded299
[crypto/aes] Cleanup on failures
siemen11 May 22, 2026
a99cf73
[crypto] Cast `hw_cleanup_guard` to void to avoid compiler error
nasahlpa Jun 3, 2026
98baa8f
[crypto/hmac/kmac] Clean HW upon bad status
siemen11 May 23, 2026
b7b1c21
[crypto] Switch KMAC.c to device tree approach
nasahlpa Jun 3, 2026
efbd50d
[crypto] Cast `hw_cleanup_guard` to void to avoid compiler errors
nasahlpa Jun 3, 2026
14b6480
[cryptotest] Add hashing handler to ECDSA
nasahlpa May 22, 2026
bd63c84
[cryptotest] Add ECDSA ACVP sigVer testing
nasahlpa May 22, 2026
c4f107b
[cryptotest] Fix ECDSA hash mode values
nasahlpa May 22, 2026
8afd79f
[cryptotest] Add keygen to ECDSA fw handler
nasahlpa May 22, 2026
8b17c58
[cryptotest] Add ACVP ECDSA SigGen testing
nasahlpa May 22, 2026
3d38cfb
[cryptotest] ECDSA keygen returns unshared d
nasahlpa May 22, 2026
b9d9329
[cryptotest] Add ACVP ECDSA keygen testing
nasahlpa May 22, 2026
5e87c49
[crypto] Add self-integrity check to init
siemen11 May 23, 2026
d93b02e
[cryptotest] Add AES ACVP test vectors
nasahlpa May 26, 2026
f03c440
[cryptotest] Add AES-GCM ACVP test vectors
nasahlpa May 26, 2026
0d6d7fc
[cryptotest] Add AES ACVP host harness
nasahlpa May 26, 2026
4bdd056
[cryptotest] Restructure ACVP parsing
nasahlpa May 26, 2026
87fd424
[crypto/25519] Add comments
siemen11 May 26, 2026
1e63003
[crypto/gcm] Propagate integrity buffers
siemen11 May 26, 2026
6d03291
[cryptotest] Add KMAC ACVP test vectors
nasahlpa May 26, 2026
9eb6b8a
[cryptotest] Enable KMAC ACVP testing
nasahlpa May 26, 2026
346052e
[crypto] Add minsize for fips blob
siemen11 May 26, 2026
96f4744
[crypto] Propagate the minsize to the shifted blob
siemen11 May 27, 2026
20ddba4
[cryptotest] Add SHA2 ACVP test vectors
nasahlpa May 27, 2026
81214ce
[cryptotest] Add SHA cryptotest handler
nasahlpa May 27, 2026
8099174
[cryptotest] Add SHA3 ACVP test vectors
nasahlpa May 27, 2026
ec15d26
[cryptotest] Add SHA ACVP host harness
nasahlpa May 27, 2026
c9f229d
[cryptotest] Add SHAKE-128/256 ACVP test vectors
nasahlpa May 27, 2026
3df9e99
[cryptotest] Add SHAKE-128/256 to cryptotest firmware
nasahlpa May 27, 2026
a1dca5c
[cryptotest] Add SHAKE-128/256 ACVP host harness
nasahlpa May 27, 2026
ddc94ed
[cryptotest] Fix clippy RUST error
nasahlpa Jun 8, 2026
b33b665
[cryptotest] Add module name for SHA
nasahlpa Jun 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions doc/security/cryptolib/cryptolib_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ 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](#supported-algorithms)
- Enumerates all of the cryptolib's [data structures](#data-structures)
Expand Down Expand Up @@ -66,6 +64,32 @@ You can activate these settings during the build process by passing `--define=<s
| `disable_null_checks` | `OTCRYPTO_DISABLE_NULL_CHECKS` | Removes `NULL` pointer checks on API inputs throughout the library (e.g., AES-GCM operations). This saves code size, but strictly requires the caller to guarantee no `NULL` pointers are passed. |
| `disable_buf_integrity_checks` | `OTCRYPTO_DISABLE_BUF_INTEGRITY_CHECKS` | Disables runtime integrity verification for data buffers. This bypasses `verify_buf_integrity`, removing the check that compares `ptr_checksum` against the data's calculated checksum. |

## FIPS Build & Position-Independent Code (PIC)

In addition to the default development build (`crypto_dev` which builds a standard static library), the cryptolib can be built as a **position-independent binary blob** for FIPS compliance.
This specialized target hashes the library's contents and fuses the hash onto the binary boundary.

You can trigger this build using the `--config=crypto_fips_all` Bazel flag.
The exact functions included in this blob are strictly governed by an allowlist configuration file located in `//sw/device/lib/crypto/configs`.

Because the FIPS blob is relocatable and contiguous, developers contributing to the cryptolib must adhere to strict memory and structural constraints:

* **No `.bss` or `.data` Sections:** The linker script enforces that the `.bss`, `.sbss`, `.data`, and `.sdata2` sections have a size of exactly 0. You **cannot** use static (non-const) variables or uninitialized global variables. All data must reside in `.text`, `.rodata`, or `.srodata`.
* **Strict Position Independence:** Code must be completely position-independent (PIC) and cannot rely on a Global Offset Table (GOT).
* **No Jump Tables:** The library is explicitly compiled with `-fno-jump-tables`. This forces the compiler to handle `switch` statements without generating position-dependent jump tables.

### Testing PIC Compliance

If you suspect position-dependent code has been introduced, you can run the dedicated PIC compliance test:

```bash
bazel test //sw/device/tests/crypto:otcrypto_pic_test
```

This test ensures there are no absolute addresses in the blob.
It does this by compiling the library at two different base memory offsets, extracting the pure binary, and comparing them byte-by-byte.
If differences are found, the test traces them back to the violating symbols, failing the run and printing the exact functions or variables that need manual inspection in the disassembly.

## Cryptolib Usage Examples

Examples of how to use the cryptolib API are provided in the [cryptolib test directory][crypto-tests].
Expand Down
5 changes: 5 additions & 0 deletions rules/opentitan/cc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -708,8 +708,13 @@ opentitan_binary_blob = rv_rule(
),
"deps_blob": attr.label_list(
providers = [CcInfo],
cfg = _transitive_feature_transition,
doc = "The list of other libraries to be for the creation of the binary blob.",
),
"transitive_features": attr.string_list(
default = [],
doc = "Features to apply transitively to all dependencies.",
),
"_linker_script_template": attr.label(
default = Label("//sw/device/lib/crypto/configs:otcrypto_blob.ld"),
allow_single_file = True,
Expand Down
6 changes: 6 additions & 0 deletions sw/device/lib/crypto/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ opentitan_binary_blob(
"//sw/device/lib/crypto/configs:crypto_fips_all": [],
"//conditions:default": ["@platforms//:incompatible"],
}),
# We add the compiler option -fno-jump-tables to prevent the compiler making the code position dependent.
# Minsize is added to reduce code size.
transitive_features = [
"no_jump_tables",
"minsize",
],
deps = [
"//hw/top_earlgrey/sw/autogen:top_earlgrey",
"//sw/device/lib/crypto/include:crypto_hdrs",
Expand Down
2 changes: 0 additions & 2 deletions sw/device/lib/crypto/drivers/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ dual_cc_library(
hdrs = [
"alert.h",
],
# We add the compiler option -fno-jump-tables to prevent the compiler making the code position dependent.
features = ["no_jump_tables"],
deps = dual_inputs(
device = [
"//hw/top:alert_handler_c_regs",
Expand Down
4 changes: 4 additions & 0 deletions sw/device/lib/crypto/drivers/aes.c
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,10 @@ status_t aes_end(aes_block_t *iv) {
HARDENED_CHECK_EQ(i, ARRAYSIZE(iv->data));
}

return spin_until(AES_STATUS_IDLE_BIT);
}

status_t aes_clear(void) {
uint32_t trigger_reg = 0;
trigger_reg = bitfield_bit32_write(
trigger_reg, AES_TRIGGER_KEY_IV_DATA_IN_CLEAR_BIT, true);
Expand Down
8 changes: 8 additions & 0 deletions sw/device/lib/crypto/drivers/aes.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,14 @@ status_t aes_update(aes_block_t *dest, const aes_block_t *src);
OT_WARN_UNUSED_RESULT
status_t aes_end(aes_block_t *iv);

/**
* Clears the AES hardware data registers and triggers.
*
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
status_t aes_clear(void);

/**
* Compute the checksum of an AES key.
*
Expand Down
22 changes: 17 additions & 5 deletions sw/device/lib/crypto/drivers/hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ static status_t clear(void) {
return LAUNDERED_OTCRYPTO_OK;
}

/**
* Hardware wipe guard.
*/
static void hmac_wipe_guard(uint32_t *dummy) { (void)clear(); }

/**
* Write given key to HMAC HWIP.
*
Expand Down Expand Up @@ -405,6 +410,9 @@ static status_t ensure_idle(void) {
static status_t oneshot(const uint32_t cfg, const hmac_key_t *key,
const otcrypto_const_byte_buf_t *msg,
size_t digest_wordlen, uint32_t *digest) {
uint32_t hw_cleanup_guard __attribute__((cleanup(hmac_wipe_guard))) = 1;
(void)hw_cleanup_guard;

// Check that the block is idle.
HARDENED_TRY(ensure_idle());

Expand Down Expand Up @@ -439,7 +447,7 @@ static status_t oneshot(const uint32_t cfg, const hmac_key_t *key,

HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(msg));

return clear();
return OTCRYPTO_OK;
}

/**
Expand Down Expand Up @@ -788,6 +796,9 @@ hardened_bool_t hmac_key_integrity_checksum_check(const hmac_key_t *key) {
}

status_t hmac_update(hmac_ctx_t *ctx, const otcrypto_const_byte_buf_t *data) {
uint32_t hw_cleanup_guard __attribute__((cleanup(hmac_wipe_guard))) = 1;
(void)hw_cleanup_guard;

// If we don't have enough new bytes to fill a block, just update the partial
// block and return.
size_t block_bytelen = ctx->msg_block_wordlen * sizeof(uint32_t);
Expand Down Expand Up @@ -830,11 +841,13 @@ status_t hmac_update(hmac_ctx_t *ctx, const otcrypto_const_byte_buf_t *data) {

HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(data));

// Clean up.
return clear();
return OTCRYPTO_OK;
}

status_t hmac_final(hmac_ctx_t *ctx, otcrypto_word32_buf_t *digest) {
uint32_t hw_cleanup_guard __attribute__((cleanup(hmac_wipe_guard))) = 1;
(void)hw_cleanup_guard;

// Restore context will restore the context and also hit start or continue
// button as necessary.
HARDENED_TRY(context_restore(ctx));
Expand All @@ -860,6 +873,5 @@ status_t hmac_final(hmac_ctx_t *ctx, otcrypto_word32_buf_t *digest) {

HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(digest));

// Clean up.
return clear();
return OTCRYPTO_OK;
}
20 changes: 14 additions & 6 deletions sw/device/lib/crypto/drivers/kmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,16 @@ OT_ASSERT_ENUM_VALUE(ARRAYSIZE(prefix_offsets), KMAC_PREFIX_MULTIREG_COUNT);
// Ensure each PREFIX register is 4 bytes
OT_ASSERT_ENUM_VALUE(32, KMAC_PREFIX_PREFIX_FIELD_WIDTH);

/**
* Hardware wipe guard.
*/
static void kmac_wipe_guard(uint32_t *dummy) {
uint32_t cmd_reg = KMAC_CMD_REG_RESVAL;
cmd_reg = bitfield_field32_write(cmd_reg, KMAC_CMD_CMD_FIELD,
KMAC_CMD_CMD_VALUE_DONE);
abs_mmio_write32(kmac_base() + KMAC_CMD_REG_OFFSET, cmd_reg);
}

/**
* Return the rate (in bytes) for given security strength.
*
Expand Down Expand Up @@ -617,6 +627,10 @@ OT_WARN_UNUSED_RESULT
static status_t kmac_process_msg_blocks(
kmac_operation_t operation, const otcrypto_const_byte_buf_t *message,
uint32_t *digest, size_t digest_len_bytes, hardened_bool_t masked_digest) {
// This variable guarantees kmac_wipe_guard() is called on exit.
uint32_t hw_cleanup_guard __attribute__((cleanup(kmac_wipe_guard))) = 1;
(void)hw_cleanup_guard;

// Block until KMAC is idle.
HARDENED_TRY(wait_status_bit(KMAC_STATUS_SHA3_IDLE_BIT, 1));

Expand Down Expand Up @@ -755,12 +769,6 @@ static status_t kmac_process_msg_blocks(
// Poll the status register until in the 'squeeze' state.
HARDENED_TRY(wait_status_bit(KMAC_STATUS_SHA3_SQUEEZE_BIT, 1));

// Release the KMAC core, so that it goes back to idle mode
cmd_reg = KMAC_CMD_REG_RESVAL;
cmd_reg = bitfield_field32_write(cmd_reg, KMAC_CMD_CMD_FIELD,
KMAC_CMD_CMD_VALUE_DONE);
abs_mmio_write32(kBase + KMAC_CMD_REG_OFFSET, cmd_reg);

// Zero out the trailing bytes in the final word.
size_t remainder_bytes = digest_len_bytes % sizeof(uint32_t);
if (remainder_bytes > 0) {
Expand Down
2 changes: 2 additions & 0 deletions sw/device/lib/crypto/impl/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ cc_library(
":aes_gcm",
":config",
":drbg",
":ecc_curve25519",
":ecc_p256",
":ecc_p384",
":entropy_src",
Expand Down Expand Up @@ -317,6 +318,7 @@ cc_library(
":status",
"//sw/device/lib/base:hardened_memory",
"//sw/device/lib/base:math",
"//sw/device/lib/crypto/drivers:keymgr",
"//sw/device/lib/crypto/drivers:kmac",
"//sw/device/lib/crypto/drivers:rv_core_ibex",
"//sw/device/lib/crypto/include:datatypes",
Expand Down
15 changes: 13 additions & 2 deletions sw/device/lib/crypto/impl/aes.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,14 @@ otcrypto_status_t otcrypto_aes_padded_plaintext_length(
return OTCRYPTO_OK;
}

/**
* Hardware cleanup guard.
*/
static void hw_wipe_guard(uint32_t *dummy) {
(void)aes_clear();
(void)keymgr_sideload_clear_aes();
}

/**
* Performs the AES operation.
*
Expand All @@ -297,6 +305,10 @@ static otcrypto_status_t otcrypto_aes_impl(
otcrypto_aes_mode_t aes_mode, otcrypto_aes_operation_t aes_operation,
const otcrypto_const_byte_buf_t *cipher_input,
otcrypto_aes_padding_t aes_padding, otcrypto_byte_buf_t *cipher_output) {
// Guarantees hw_wipe_guard() is called on exit.
uint32_t hw_cleanup_guard __attribute__((cleanup(hw_wipe_guard))) = 1;
(void)hw_cleanup_guard;

// Calculate the number of blocks for the input, including the padding for
// encryption.
size_t input_nblocks;
Expand Down Expand Up @@ -450,8 +462,7 @@ static otcrypto_status_t otcrypto_aes_impl(
HARDENED_TRY(hardened_memcpy(iv->data, aes_iv.data, kAesBlockNumWords));
}

// In case the key was sideloaded, clear it.
return otcrypto_eval_exit(keymgr_sideload_clear_aes());
return otcrypto_eval_exit(OTCRYPTO_OK);
}

otcrypto_status_t otcrypto_aes_padding_strip(
Expand Down
Loading