Skip to content

Commit 5abf6f5

Browse files
committed
randombytes: add example to test failure
This commit introduces a new example build which is meant to test the failure mode to the randombytes API. The randombytes_force_failure(n) function ensures that the nth call to randombytes will fail. Signed-off-by: Andreas Hatziiliou <andreas.hatziiliou@savoirfairelinux.com>
1 parent a43e40b commit 5abf6f5

File tree

9 files changed

+835
-0
lines changed

9 files changed

+835
-0
lines changed

BIBLIOGRAPHY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ source code and documentation.
342342
- Daniel J. Bernstein
343343
* URL: https://cr.yp.to/papers.html#surf
344344
* Referenced from:
345+
- [examples/basic_rng_failure/test_only_rng/notrandombytes.c](examples/basic_rng_failure/test_only_rng/notrandombytes.c)
346+
- [examples/basic_rng_failure/test_only_rng/notrandombytes.h](examples/basic_rng_failure/test_only_rng/notrandombytes.h)
345347
- [test/notrandombytes/notrandombytes.c](test/notrandombytes/notrandombytes.c)
346348
- [test/notrandombytes/notrandombytes.h](test/notrandombytes/notrandombytes.h)
347349

BIBLIOGRAPHY.md.new

Lines changed: 374 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Copyright (c) The mlkem-native project authors
2+
# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
3+
4+
.PHONY: build run clean
5+
.DEFAULT_GOAL := all
6+
7+
CC ?= gcc
8+
9+
# Adjust CFLAGS if needed
10+
CFLAGS := \
11+
-Wall \
12+
-Wextra \
13+
-Werror=unused-result \
14+
-Wpedantic \
15+
-Werror \
16+
-Wmissing-prototypes \
17+
-Wshadow \
18+
-Wpointer-arith \
19+
-Wredundant-decls \
20+
-Wconversion \
21+
-Wsign-conversion \
22+
-Wno-long-long \
23+
-Wno-unknown-pragmas \
24+
-Wno-unused-command-line-argument \
25+
-O3 \
26+
-fomit-frame-pointer \
27+
-std=c99 \
28+
-pedantic \
29+
-MMD \
30+
$(CFLAGS)
31+
32+
# If you want to use the native backends, the compiler needs to know about
33+
# the target architecture. Here, we import the default host detection from
34+
# mlkem-native's tests, but you can write your own or specialize accordingly.
35+
AUTO ?= 1
36+
include auto.mk
37+
38+
# The following only concerns the cross-compilation tests.
39+
# You can likely ignore the following for your application.
40+
#
41+
# Append cross-prefix for cross compilation
42+
# When called from the root Makefile, CROSS_PREFIX has already been added here
43+
ifeq (,$(findstring $(CROSS_PREFIX),$(CC)))
44+
CC := $(CROSS_PREFIX)$(CC)
45+
endif
46+
47+
# Part A:
48+
#
49+
# mlkem-native source and header files
50+
#
51+
# If you are not concerned about minimizing for a specific backend,
52+
# you can just include _all_ source files into your build.
53+
#
54+
# In this example, we compile the individual mlkem-native source files directly.
55+
# Alternatively, you can compile the 'monobuild' source file mlkem_native.c.
56+
# See examples/monolithic_build for that.
57+
MLK_SOURCE=$(wildcard \
58+
mlkem_native/mlkem/src/*.c \
59+
mlkem_native/mlkem/src/**/*.c \
60+
mlkem_native/mlkem/src/**/**/*.c \
61+
mlkem_native/mlkem/src/**/**/**/*.c)
62+
63+
# Part B:
64+
#
65+
# Random number generator
66+
#
67+
# !!! WARNING !!!
68+
#
69+
# The randombytes() implementation used here is for TESTING ONLY.
70+
# You MUST NOT use this implementation outside of testing.
71+
#
72+
# !!! WARNING !!!
73+
RNG_SOURCE=$(wildcard test_only_rng/*.c)
74+
75+
# Part C:
76+
#
77+
# Your application source code
78+
APP_SOURCE=$(wildcard *.c)
79+
80+
ALL_SOURCE=$(MLK_SOURCE) $(RNG_SOURCE) $(APP_SOURCE)
81+
82+
BUILD_DIR=build
83+
BIN=test_binary
84+
85+
#
86+
# Configuration adjustments
87+
#
88+
89+
# Pick prefix
90+
CFLAGS += -DMLK_CONFIG_NAMESPACE_PREFIX=mlkem
91+
92+
BINARY_NAME_FULL_512=$(BUILD_DIR)/$(BIN)512
93+
BINARY_NAME_FULL_768=$(BUILD_DIR)/$(BIN)768
94+
BINARY_NAME_FULL_1024=$(BUILD_DIR)/$(BIN)1024
95+
BINARIES_FULL=$(BINARY_NAME_FULL_512) $(BINARY_NAME_FULL_768) $(BINARY_NAME_FULL_1024)
96+
97+
$(BINARY_NAME_FULL_512): CFLAGS += -DMLK_CONFIG_PARAMETER_SET=512
98+
$(BINARY_NAME_FULL_768): CFLAGS += -DMLK_CONFIG_PARAMETER_SET=768
99+
$(BINARY_NAME_FULL_1024): CFLAGS += -DMLK_CONFIG_PARAMETER_SET=1024
100+
101+
$(BINARIES_FULL): $(ALL_SOURCE)
102+
echo "$@"
103+
mkdir -p $(BUILD_DIR)
104+
$(CC) $(CFLAGS) $^ -o $@
105+
106+
all: build
107+
108+
build: $(BINARIES_FULL)
109+
110+
run: $(BINARIES_FULL)
111+
$(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_512)
112+
$(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_768)
113+
$(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_1024)
114+
115+
clean:
116+
rm -rf $(BUILD_DIR)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
[//]: # (SPDX-License-Identifier: CC-BY-4.0)
2+
3+
# Building mlkem-native
4+
5+
This directory contains a minimal example for how to build mlkem-native and
6+
intentionally force failures in the `randombytes` provider so that you can
7+
exercise the library’s error paths.
8+
9+
## Components
10+
11+
An application using mlkem-native as-is needs to include the following components:
12+
13+
1. mlkem-native source tree, including [`mlkem/src/`](../../mlkem/src) and [`mlkem/src/fips202/`](../../mlkem/src/fips202).
14+
2. A secure pseudo random number generator, implementing [`randombytes.h`](../../mlkem/src/randombytes.h).
15+
3. The application source code
16+
17+
**WARNING:** The `randombytes()` implementation used here is for TESTING ONLY. You MUST NOT use this implementation
18+
outside of testing.
19+
20+
## Usage
21+
22+
Build this example with `make build`, run with `make run`.
23+
24+
The test binary executes three scenarios for each security level:
25+
26+
1. Force the first `randombytes` invocation (during key generation) to fail and
27+
check that `crypto_kem_keypair` returns -1.
28+
2. Allow key generation, then fail the second `randombytes` invocation (during
29+
signing) and confirm `crypto_kem_enc` returns -1.
30+
3. Disable failure injection (negative index) and exercise the full
31+
sign/verify flow, ensuring the expected deterministic signature is produced.

examples/basic_rng_failure/auto.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../test/mk/auto.mk

examples/basic_rng_failure/main.c

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* Copyright (c) The mlkem-native project authors
3+
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
4+
*/
5+
6+
#include <stdio.h>
7+
#include <string.h>
8+
9+
10+
/* Import public mlkem-native API
11+
*
12+
* This requires specifying the parameter set and namespace prefix
13+
* used for the build.
14+
*/
15+
#define MLK_CONFIG_API_PARAMETER_SET MLK_CONFIG_PARAMETER_SET
16+
#define MLK_CONFIG_API_NAMESPACE_PREFIX mlkem
17+
#include "mlkem_native/mlkem/mlkem_native.h"
18+
19+
#include "test_only_rng/notrandombytes.h"
20+
21+
int test_failures(int fail_at_call);
22+
23+
#define CHECK(x) \
24+
do \
25+
{ \
26+
int rc; \
27+
rc = (x); \
28+
if (!rc) \
29+
{ \
30+
fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \
31+
return 1; \
32+
} \
33+
} while (0)
34+
35+
int main(void)
36+
{
37+
test_failures(0);
38+
test_failures(1);
39+
test_failures(-101);
40+
return 0;
41+
}
42+
43+
int test_failures(int fail_at_call)
44+
{
45+
uint8_t pk[CRYPTO_PUBLICKEYBYTES];
46+
uint8_t sk[CRYPTO_SECRETKEYBYTES];
47+
uint8_t ct[CRYPTO_CIPHERTEXTBYTES];
48+
uint8_t key_a[CRYPTO_BYTES];
49+
uint8_t key_b[CRYPTO_BYTES];
50+
51+
/* The PCT modifies the PRNG state, so the KAT tests don't work.
52+
* We run KAT tests only for disabled PCT. */
53+
#if !defined(MLK_CONFIG_KEYGEN_PCT)
54+
#if MLK_CONFIG_PARAMETER_SET == 512
55+
const uint8_t expected_key[] = {
56+
0x77, 0x6c, 0x74, 0xdf, 0x30, 0x1f, 0x8d, 0x82, 0x52, 0x5e, 0x8e,
57+
0xbb, 0xb4, 0x00, 0x95, 0xcd, 0x2e, 0x92, 0xdf, 0x6d, 0xc9, 0x33,
58+
0xe7, 0x86, 0x62, 0x59, 0xf5, 0x31, 0xc7, 0x35, 0x0a, 0xd5};
59+
#elif MLK_CONFIG_PARAMETER_SET == 768
60+
const uint8_t expected_key[] = {
61+
0xe9, 0x13, 0x77, 0x84, 0x0e, 0x6b, 0x66, 0x94, 0xea, 0xa9, 0xf0,
62+
0x1c, 0x97, 0xff, 0x68, 0x87, 0x4e, 0x8b, 0x0c, 0x52, 0x0b, 0x00,
63+
0xc2, 0xcd, 0xe3, 0x7c, 0x4f, 0xc2, 0x39, 0x62, 0x6e, 0x70};
64+
#elif MLK_CONFIG_PARAMETER_SET == 1024
65+
const uint8_t expected_key[] = {
66+
0x5d, 0x9e, 0x23, 0x5f, 0xcc, 0xb2, 0xb3, 0x49, 0x9a, 0x5f, 0x49,
67+
0x0a, 0x56, 0xe3, 0xf0, 0xd3, 0xfd, 0x9b, 0x58, 0xbd, 0xa2, 0x8b,
68+
0x69, 0x0f, 0x91, 0xb5, 0x7b, 0x88, 0xa5, 0xa8, 0x0b, 0x90};
69+
#endif /* MLK_CONFIG_PARAMETER_SET == 1024 */
70+
#endif /* !MLK_CONFIG_KEYGEN_PCT */
71+
72+
int call_idx = 0;
73+
int expected;
74+
75+
/* WARNING: Test-only
76+
* Normally, you would want to seed a PRNG with trustworthy entropy here. */
77+
randombytes_reset();
78+
79+
printf("Generating keypair ... ");
80+
randombytes_force_failure(fail_at_call);
81+
expected = (call_idx == fail_at_call) ? -1 : 0;
82+
if (expected == -1)
83+
{
84+
CHECK(crypto_kem_keypair(pk, sk) == -1);
85+
printf("FAILED as expected \n\n");
86+
return 0;
87+
}
88+
/* Alice generates a public key */
89+
CHECK(crypto_kem_keypair(pk, sk) == 0);
90+
call_idx++;
91+
92+
printf("DONE\n");
93+
printf("Encaps... ");
94+
expected = (call_idx == fail_at_call) ? -1 : 0;
95+
if (expected == -1)
96+
{
97+
CHECK(crypto_kem_enc(ct, key_b, pk) == -1);
98+
printf("FAILED as expected \n\n");
99+
return 0;
100+
}
101+
/* Bob derives a secret key and creates a response */
102+
CHECK(crypto_kem_enc(ct, key_b, pk) == 0);
103+
call_idx++;
104+
105+
printf("DONE\n");
106+
printf("Decaps... ");
107+
108+
/* Alice uses Bobs response to get her shared key */
109+
CHECK(crypto_kem_dec(key_a, ct, sk) == 0);
110+
111+
printf("DONE\n");
112+
printf("Compare... ");
113+
114+
CHECK(memcmp(key_a, key_b, CRYPTO_BYTES) == 0);
115+
116+
printf("Shared secret: ");
117+
{
118+
size_t i;
119+
for (i = 0; i < sizeof(key_a); i++)
120+
{
121+
printf("%02x", key_a[i]);
122+
}
123+
}
124+
printf("\n");
125+
126+
#if !defined(MLK_CONFIG_KEYGEN_PCT)
127+
/* Check against hardcoded result to make sure that
128+
* we integrated custom FIPS202 correctly */
129+
CHECK(memcmp(key_a, expected_key, CRYPTO_BYTES) == 0);
130+
#else
131+
printf(
132+
"[WARNING] Skipping KAT test since PCT is enabled and modifies PRNG\n");
133+
#endif
134+
135+
printf("OK\n");
136+
return 0;
137+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../mlkem

0 commit comments

Comments
 (0)