479fcd37c1
- 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.
206 lines
5.2 KiB
C
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);
|
|
}
|