/** * @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 #include #include #include #include #include /** * @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); }