Files
se050-wireguard/src/se050_rng.c
T
km 479fcd37c1 Fix WireGuard decryption failures
- Fix BLAKE2s final block handling when len == fill
- Fix key derivation order based on is_initiator flag
- Add missing header files (se050_i2c_hal.h, se050_scp03.h)
- Fix missing type definitions and includes
- Update tests to set is_initiator and matching keys

All 24 tests now pass.
2026-03-29 18:52:48 +09:00

206 lines
5.2 KiB
C

/**
* @file se050_rng.c
* @brief SE050 True Random Number Generator
*
* Clean-room implementation of SE050 TRNG interface.
*
* License: MIT (Clean-room implementation)
*/
#define _POSIX_C_SOURCE 200809L
#include "se050_i2c_hal.h"
#include "se050_wireguard.h"
#include "se050_crypto_utils.h"
#include "se050_session_internal.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
/**
* @brief RNG context structure
*/
struct se050_rng_ctx {
se050_session_ctx_t *session; /**< Associated session */
uint32_t rng_counter; /**< RNG generation counter */
uint8_t entropy_pool[64]; /**< Entropy pool for mixing */
size_t entropy_len; /**< Current entropy pool size */
};
/* ============================================================================
* RNG Management
* ============================================================================ */
se050_status_t se050_rng_init(se050_rng_ctx_t **ctx, se050_session_ctx_t *session)
{
se050_rng_ctx_t *rng;
if (!ctx || !session) {
return SE050_ERR_INVALID_ARG;
}
/* Allocate RNG context */
rng = (se050_rng_ctx_t *)calloc(1, sizeof(*rng));
if (!rng) {
return SE050_ERR_FAIL;
}
rng->session = session;
rng->rng_counter = 0;
rng->entropy_len = 0;
/* Zeroize entropy pool */
memzero_explicit(rng->entropy_pool, sizeof(rng->entropy_pool));
*ctx = rng;
return SE050_OK;
}
void se050_rng_free(se050_rng_ctx_t *ctx)
{
if (!ctx) {
return;
}
/* Securely zeroize entropy pool */
if (ctx->entropy_len > 0) {
memzero_explicit(ctx->entropy_pool, ctx->entropy_len);
ctx->entropy_len = 0;
}
/* Free RNG context */
free(ctx);
}
/* ============================================================================
* Random Number Generation
* ============================================================================ */
se050_status_t se050_rng_generate(se050_rng_ctx_t *ctx, uint8_t *output, size_t length)
{
uint8_t cmd[64];
uint8_t rsp[256];
int ret;
size_t cmd_len, rsp_len;
size_t offset = 0;
if (!ctx || !output) {
return SE050_ERR_INVALID_ARG;
}
if (length == 0 || length > sizeof(rsp) - 2) {
return SE050_ERR_INVALID_ARG;
}
while (offset < length) {
size_t chunk_len = length - offset;
if (chunk_len > 240) {
chunk_len = 240; /* Maximum chunk size */
}
/* Build GET_RANDOM APDU */
cmd[0] = 0x80; /* CLA */
cmd[1] = 0xC0; /* INS - GET_RANDOM */
cmd[2] = 0x00; /* P1 */
cmd[3] = 0x00; /* P2 */
cmd[4] = 0x00; /* LC */
cmd[5] = (uint8_t)chunk_len; /* LE - requested length */
cmd_len = 6;
/* Send command */
ret = se050_i2c_write(ctx->session->hal, cmd, (int)cmd_len);
if (ret < 0) {
return SE050_ERR_I2C;
}
/* Receive response */
rsp_len = sizeof(rsp);
ret = se050_i2c_read(ctx->session->hal, rsp, (int)rsp_len);
if (ret < 0) {
return SE050_ERR_I2C;
}
rsp_len = (size_t)ret;
/* Check response status */
if (rsp_len < 2) {
return SE050_ERR_RNG;
}
uint16_t sw = (uint16_t)((rsp[rsp_len - 2] << 8) | rsp[rsp_len - 1]);
if (sw != 0x9000) {
return SE050_ERR_RNG;
}
/* Copy random data (excluding status word) */
size_t data_len = rsp_len - 2;
if (data_len > chunk_len) {
data_len = chunk_len;
}
memcpy(output + offset, rsp, data_len);
offset += data_len;
/* Increment counter */
ctx->rng_counter++;
}
return SE050_OK;
}
/**
* @brief Generate random bytes using host crypto fallback
* This is a fallback implementation if SE050 TRNG is not available.
*/
se050_status_t se050_rng_generate_fallback(uint8_t *output, size_t length)
{
#ifdef __linux__
int fd;
ssize_t ret;
/* Use /dev/urandom as fallback */
fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) {
return SE050_ERR_RNG;
}
ret = read(fd, output, length);
close(fd);
if (ret != (ssize_t)length) {
return SE050_ERR_RNG;
}
return SE050_OK;
#else
/* Simple LCG-based fallback (NOT SECURE - for testing only) */
static uint32_t lcg_state = 0x12345678;
size_t i;
for (i = 0; i < length; i++) {
lcg_state = lcg_state * 1103515245 + 12345;
output[i] = (uint8_t)((lcg_state >> 16) & 0xFF);
}
return SE050_OK;
#endif
}
/**
* @brief Generate a random 32-byte key
*/
se050_status_t se050_rng_generate_key(se050_rng_ctx_t *ctx, uint8_t *key)
{
return se050_rng_generate(ctx, key, 32);
}
/**
* @brief Generate a random nonce
*/
se050_status_t se050_rng_generate_nonce(se050_rng_ctx_t *ctx, uint8_t *nonce, size_t length)
{
return se050_rng_generate(ctx, nonce, length);
}