feat: Add CSPRNG with SE050 seed for embedded platforms

- Implemented ChaCha20-based CSPRNG seeded from SE050 TRNG
- Optimized for ESP32 and other embedded platforms
- Single SE050 access at startup, then fast software RNG
- All 10 CSPRNG tests passing

Usage:

Benefits:
- Minimal I2C communication (only once at startup)
- Fast random generation after seeding
- Cryptographically secure (ChaCha20-based)
- Suitable for resource-constrained devices
This commit is contained in:
km
2026-03-28 20:24:15 +09:00
parent 1894e9a933
commit 999e7a6e19
4 changed files with 405 additions and 0 deletions
+209
View File
@@ -0,0 +1,209 @@
/**
* @file se050_rng_seed.c
* @brief SE050-based CSPRNG with initial seed
*
* This module provides a cryptographically secure pseudo-random number generator
* that is seeded once from SE050 hardware TRNG at startup, then uses ChaCha20
* to generate the rest of the random stream.
*
* Benefits:
* - Minimal I2C communication (only once at startup)
* - Fast random generation after seeding
* - Cryptographically secure (ChaCha20-based)
* - Suitable for ESP32 and other embedded platforms
*
* License: MIT (Clean-room implementation)
*/
#include "se050_wireguard.h"
#include "se050_x25519_sw.h"
#include "se050_chacha20_poly1305.h"
#include "se050_crypto_utils.h"
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
/* ============================================================================
* Constants
* ============================================================================ */
#define SEED_SIZE 32
#define COUNTER_SIZE 4
#define NONCE_SIZE 12
#define KEY_SIZE 32
/* ============================================================================
* CSPRNG Context
* ============================================================================ */
typedef struct {
uint8_t key[KEY_SIZE]; /* ChaCha20 key (from SE050 seed) */
uint32_t counter; /* Stream counter */
uint8_t buffer[64]; /* Current block buffer */
size_t buffer_pos; /* Current position in buffer */
int initialized; /* Initialization flag */
} se050_csprng_ctx_t;
/* Global CSPRNG instance */
static se050_csprng_ctx_t g_rng;
/* ============================================================================
* ChaCha20-based CSPRNG
* ============================================================================ */
/**
* @brief Generate a new ChaCha20 block
*/
static void csprng_generate_block(se050_csprng_ctx_t *ctx)
{
uint8_t nonce[NONCE_SIZE] = {0};
/* Set counter in nonce (last 4 bytes) */
nonce[8] = (ctx->counter >> 0) & 0xff;
nonce[9] = (ctx->counter >> 8) & 0xff;
nonce[10] = (ctx->counter >> 16) & 0xff;
nonce[11] = (ctx->counter >> 24) & 0xff;
ctx->counter++;
/* Generate ChaCha20 block */
se050_chacha20_block(ctx->buffer, ctx->key, 0, nonce);
ctx->buffer_pos = 0;
}
/**
* @brief Generate random bytes using ChaCha20 stream
*/
static int csprng_generate(uint8_t *out, size_t len)
{
if (!g_rng.initialized) {
return -1;
}
if (!out || len == 0) {
return -1;
}
for (size_t i = 0; i < len; i++) {
if (g_rng.buffer_pos >= 64) {
csprng_generate_block(&g_rng);
}
out[i] = g_rng.buffer[g_rng.buffer_pos++];
}
return 0;
}
/* ============================================================================
* SE050 Seed Integration
* ============================================================================ */
/**
* @brief Callback type for SE050 RNG
*/
typedef int (*se050_rng_func_t)(uint8_t *out, size_t len, void *ctx);
/**
* @brief Initialize CSPRNG with seed from SE050
*
* @param seed_func Function to get seed from SE050
* @param seed_ctx Context for seed function
* @return 0 on success, -1 on error
*/
int se050_csprng_init(se050_rng_func_t seed_func, void *seed_ctx)
{
if (!seed_func) {
return -1;
}
/* Zeroize context first */
memset(&g_rng, 0, sizeof(g_rng));
/* Get seed from SE050 */
uint8_t seed[SEED_SIZE];
if (seed_func(seed, SEED_SIZE, seed_ctx) != 0) {
return -1;
}
/* Use seed as ChaCha20 key */
memcpy(g_rng.key, seed, KEY_SIZE);
/* Clear seed from memory */
memzero_explicit(seed, SEED_SIZE);
/* Initialize counter and buffer */
g_rng.counter = 0;
g_rng.buffer_pos = 64; /* Force initial block generation */
g_rng.initialized = 1;
return 0;
}
/**
* @brief Generate random bytes (public API)
*/
int se050_csprng_generate(uint8_t *out, size_t len)
{
return csprng_generate(out, len);
}
/**
* @brief Securely zeroize and cleanup CSPRNG
*/
void se050_csprng_cleanup(void)
{
if (g_rng.initialized) {
memzero_explicit(g_rng.key, KEY_SIZE);
memzero_explicit(g_rng.buffer, 64);
g_rng.initialized = 0;
}
}
/* ============================================================================
* WireGuard Key Generation with CSPRNG
* ============================================================================ */
/**
* @brief RNG wrapper for x25519 keypair generation using CSPRNG
*/
static int csprng_wrapper(uint8_t *out, size_t len, void *ctx)
{
(void)ctx; /* Unused */
return csprng_generate(out, len);
}
/**
* @brief Generate WireGuard keypair using seeded CSPRNG
*
* @param private_key Output: private key (32 bytes)
* @param public_key Output: public key (32 bytes)
* @return 0 on success, -1 on error
*/
int se050_wireguard_generate_keypair_csprng(uint8_t *private_key, uint8_t *public_key)
{
if (!private_key || !public_key) {
return -1;
}
if (!g_rng.initialized) {
return -1;
}
se050_x25519_sw_keypair_t keypair;
if (se050_x25519_sw_generate_keypair(&keypair, csprng_wrapper, NULL) < 0) {
return -1;
}
memcpy(private_key, keypair.private_key, 32);
memcpy(public_key, keypair.public_key, 32);
return 0;
}
/**
* @brief Generate random bytes for general use
*/
int se050_csprng_random(uint8_t *out, size_t len)
{
return csprng_generate(out, len);
}