Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions BIBLIOGRAPHY.md
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@ source code and documentation.
- Daniel J. Bernstein
* URL: https://cr.yp.to/papers.html#surf
* Referenced from:
- [examples/basic_rng_failure/test_only_rng/notrandombytes.c](examples/basic_rng_failure/test_only_rng/notrandombytes.c)
- [examples/basic_rng_failure/test_only_rng/notrandombytes.h](examples/basic_rng_failure/test_only_rng/notrandombytes.h)
- [test/notrandombytes/notrandombytes.c](test/notrandombytes/notrandombytes.c)
- [test/notrandombytes/notrandombytes.h](test/notrandombytes/notrandombytes.h)

Expand Down
374 changes: 374 additions & 0 deletions BIBLIOGRAPHY.md.new

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@
* consumer.
*
* If this option is not set, mlkem-native expects a function
* void randombytes(uint8_t *out, size_t outlen).
* int randombytes(uint8_t *out, size_t outlen).
*
* Set this option and define `mlk_randombytes` if you want to
* use a custom method to sample randombytes with a different name
Expand All @@ -321,7 +321,7 @@
#if !defined(__ASSEMBLER__)
#include <stdint.h>
#include "sys.h"
static MLK_INLINE void mlk_randombytes(uint8_t *ptr, size_t len)
static MLK_INLINE int mlk_randombytes(uint8_t *ptr, size_t len)
{
... your implementation ...
}
Expand Down
116 changes: 116 additions & 0 deletions examples/basic_rng_failure/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Copyright (c) The mlkem-native project authors
# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT

.PHONY: build run clean
.DEFAULT_GOAL := all

CC ?= gcc

# Adjust CFLAGS if needed
CFLAGS := \
-Wall \
-Wextra \
-Werror=unused-result \
-Wpedantic \
-Werror \
-Wmissing-prototypes \
-Wshadow \
-Wpointer-arith \
-Wredundant-decls \
-Wconversion \
-Wsign-conversion \
-Wno-long-long \
-Wno-unknown-pragmas \
-Wno-unused-command-line-argument \
-O3 \
-fomit-frame-pointer \
-std=c99 \
-pedantic \
-MMD \
$(CFLAGS)

# If you want to use the native backends, the compiler needs to know about
# the target architecture. Here, we import the default host detection from
# mlkem-native's tests, but you can write your own or specialize accordingly.
AUTO ?= 1
include auto.mk

# The following only concerns the cross-compilation tests.
# You can likely ignore the following for your application.
#
# Append cross-prefix for cross compilation
# When called from the root Makefile, CROSS_PREFIX has already been added here
ifeq (,$(findstring $(CROSS_PREFIX),$(CC)))
CC := $(CROSS_PREFIX)$(CC)
endif

# Part A:
#
# mlkem-native source and header files
#
# If you are not concerned about minimizing for a specific backend,
# you can just include _all_ source files into your build.
#
# In this example, we compile the individual mlkem-native source files directly.
# Alternatively, you can compile the 'monobuild' source file mlkem_native.c.
# See examples/monolithic_build for that.
MLK_SOURCE=$(wildcard \
mlkem_native/mlkem/src/*.c \
mlkem_native/mlkem/src/**/*.c \
mlkem_native/mlkem/src/**/**/*.c \
mlkem_native/mlkem/src/**/**/**/*.c)

# Part B:
#
# Random number generator
#
# !!! WARNING !!!
#
# The randombytes() implementation used here is for TESTING ONLY.
# You MUST NOT use this implementation outside of testing.
#
# !!! WARNING !!!
RNG_SOURCE=$(wildcard test_only_rng/*.c)

# Part C:
#
# Your application source code
APP_SOURCE=$(wildcard *.c)

ALL_SOURCE=$(MLK_SOURCE) $(RNG_SOURCE) $(APP_SOURCE)

BUILD_DIR=build
BIN=test_binary

#
# Configuration adjustments
#

# Pick prefix
CFLAGS += -DMLK_CONFIG_NAMESPACE_PREFIX=mlkem

BINARY_NAME_FULL_512=$(BUILD_DIR)/$(BIN)512
BINARY_NAME_FULL_768=$(BUILD_DIR)/$(BIN)768
BINARY_NAME_FULL_1024=$(BUILD_DIR)/$(BIN)1024
BINARIES_FULL=$(BINARY_NAME_FULL_512) $(BINARY_NAME_FULL_768) $(BINARY_NAME_FULL_1024)

$(BINARY_NAME_FULL_512): CFLAGS += -DMLK_CONFIG_PARAMETER_SET=512
$(BINARY_NAME_FULL_768): CFLAGS += -DMLK_CONFIG_PARAMETER_SET=768
$(BINARY_NAME_FULL_1024): CFLAGS += -DMLK_CONFIG_PARAMETER_SET=1024

$(BINARIES_FULL): $(ALL_SOURCE)
echo "$@"
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) $^ -o $@

all: build

build: $(BINARIES_FULL)

run: $(BINARIES_FULL)
$(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_512)
$(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_768)
$(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_1024)

clean:
rm -rf $(BUILD_DIR)
31 changes: 31 additions & 0 deletions examples/basic_rng_failure/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[//]: # (SPDX-License-Identifier: CC-BY-4.0)

# Building mlkem-native

This directory contains a minimal example for how to build mlkem-native and
intentionally force failures in the `randombytes` provider so that you can
exercise the library’s error paths.

## Components

An application using mlkem-native as-is needs to include the following components:

1. mlkem-native source tree, including [`mlkem/src/`](../../mlkem/src) and [`mlkem/src/fips202/`](../../mlkem/src/fips202).
2. A secure pseudo random number generator, implementing [`randombytes.h`](../../mlkem/src/randombytes.h).
3. The application source code

**WARNING:** The `randombytes()` implementation used here is for TESTING ONLY. You MUST NOT use this implementation
outside of testing.

## Usage

Build this example with `make build`, run with `make run`.

The test binary executes three scenarios for each security level:

1. Force the first `randombytes` invocation (during key generation) to fail and
check that `crypto_kem_keypair` returns -1.
2. Allow key generation, then fail the second `randombytes` invocation (during
signing) and confirm `crypto_kem_enc` returns -1.
3. Disable failure injection (negative index) and exercise the full
sign/verify flow, ensuring the expected deterministic signature is produced.
1 change: 1 addition & 0 deletions examples/basic_rng_failure/auto.mk
137 changes: 137 additions & 0 deletions examples/basic_rng_failure/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Copyright (c) The mlkem-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/

#include <stdio.h>
#include <string.h>


/* Import public mlkem-native API
*
* This requires specifying the parameter set and namespace prefix
* used for the build.
*/
#define MLK_CONFIG_API_PARAMETER_SET MLK_CONFIG_PARAMETER_SET
#define MLK_CONFIG_API_NAMESPACE_PREFIX mlkem
#include "mlkem_native/mlkem/mlkem_native.h"

#include "test_only_rng/notrandombytes.h"

int test_failures(int fail_at_call);

#define CHECK(x) \
do \
{ \
int rc; \
rc = (x); \
if (!rc) \
{ \
fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \
return 1; \
} \
} while (0)

int main(void)
{
test_failures(0);
test_failures(1);
test_failures(-101);
return 0;
}

int test_failures(int fail_at_call)
{
uint8_t pk[CRYPTO_PUBLICKEYBYTES];
uint8_t sk[CRYPTO_SECRETKEYBYTES];
uint8_t ct[CRYPTO_CIPHERTEXTBYTES];
uint8_t key_a[CRYPTO_BYTES];
uint8_t key_b[CRYPTO_BYTES];

/* The PCT modifies the PRNG state, so the KAT tests don't work.
* We run KAT tests only for disabled PCT. */
#if !defined(MLK_CONFIG_KEYGEN_PCT)
#if MLK_CONFIG_PARAMETER_SET == 512
const uint8_t expected_key[] = {
0x77, 0x6c, 0x74, 0xdf, 0x30, 0x1f, 0x8d, 0x82, 0x52, 0x5e, 0x8e,
0xbb, 0xb4, 0x00, 0x95, 0xcd, 0x2e, 0x92, 0xdf, 0x6d, 0xc9, 0x33,
0xe7, 0x86, 0x62, 0x59, 0xf5, 0x31, 0xc7, 0x35, 0x0a, 0xd5};
#elif MLK_CONFIG_PARAMETER_SET == 768
const uint8_t expected_key[] = {
0xe9, 0x13, 0x77, 0x84, 0x0e, 0x6b, 0x66, 0x94, 0xea, 0xa9, 0xf0,
0x1c, 0x97, 0xff, 0x68, 0x87, 0x4e, 0x8b, 0x0c, 0x52, 0x0b, 0x00,
0xc2, 0xcd, 0xe3, 0x7c, 0x4f, 0xc2, 0x39, 0x62, 0x6e, 0x70};
#elif MLK_CONFIG_PARAMETER_SET == 1024
const uint8_t expected_key[] = {
0x5d, 0x9e, 0x23, 0x5f, 0xcc, 0xb2, 0xb3, 0x49, 0x9a, 0x5f, 0x49,
0x0a, 0x56, 0xe3, 0xf0, 0xd3, 0xfd, 0x9b, 0x58, 0xbd, 0xa2, 0x8b,
0x69, 0x0f, 0x91, 0xb5, 0x7b, 0x88, 0xa5, 0xa8, 0x0b, 0x90};
#endif /* MLK_CONFIG_PARAMETER_SET == 1024 */
#endif /* !MLK_CONFIG_KEYGEN_PCT */

int call_idx = 0;
int expected;

/* WARNING: Test-only
* Normally, you would want to seed a PRNG with trustworthy entropy here. */
randombytes_reset();

printf("Generating keypair ... ");
randombytes_force_failure(fail_at_call);
expected = (call_idx == fail_at_call) ? -1 : 0;
if (expected == -1)
{
CHECK(crypto_kem_keypair(pk, sk) == -1);
printf("FAILED as expected \n\n");
return 0;
}
/* Alice generates a public key */
CHECK(crypto_kem_keypair(pk, sk) == 0);
call_idx++;

printf("DONE\n");
printf("Encaps... ");
expected = (call_idx == fail_at_call) ? -1 : 0;
if (expected == -1)
{
CHECK(crypto_kem_enc(ct, key_b, pk) == -1);
printf("FAILED as expected \n\n");
return 0;
}
/* Bob derives a secret key and creates a response */
CHECK(crypto_kem_enc(ct, key_b, pk) == 0);
call_idx++;

printf("DONE\n");
printf("Decaps... ");

/* Alice uses Bobs response to get her shared key */
CHECK(crypto_kem_dec(key_a, ct, sk) == 0);

printf("DONE\n");
printf("Compare... ");

CHECK(memcmp(key_a, key_b, CRYPTO_BYTES) == 0);

printf("Shared secret: ");
{
size_t i;
for (i = 0; i < sizeof(key_a); i++)
{
printf("%02x", key_a[i]);
}
}
printf("\n");

#if !defined(MLK_CONFIG_KEYGEN_PCT)
/* Check against hardcoded result to make sure that
* we integrated custom FIPS202 correctly */
CHECK(memcmp(key_a, expected_key, CRYPTO_BYTES) == 0);
#else
printf(
"[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n");
#endif

printf("OK\n");
return 0;
}
1 change: 1 addition & 0 deletions examples/basic_rng_failure/mlkem_native/mlkem
Loading
Loading