本日重點: 使用 Mbed TLS 產生亂數
本來是只想在 nRF5340 DK 上實驗 key handle,不過,因為 PSA Crypto 的 key lifetime 也包括將 key 存在 MCU 的 RAM,所以,為了方便在 Renode 上進行模擬,我將先在 renode 上 使用 Mbed TLS 產生亂數,然後 Day 22 會用這個亂數做種子,使用 Mbed TLS 產生金鑰。
首先是在 CI 裡放一個 Mbed TLS 的 cache,
怎麼寫 yml 才能有 cache,怎麼進行 cache 前後的檢查,怎麼寫 yml 比較合適,因為那不是本系列的重點,我不想在這上面有過多的著墨以免越寫越偏,所以我就跳過了,有興趣的請看連結 [ci.yml
, action.yml
]。
值得提一下的是 [action.yml
],這幾個 sed
和 CFLAGS='-DMBEDTLS_NO_PLATFORM_ENTROPY -DMBEDTLS_NO_DEFAULT_ENTROPY_SOURCES -DMBEDTLS_TEST_NULL_ENTROPY'
,因為這是在 make 裸機用的 mbedTLS,所以要把他們關掉。
sed -ri 's/^(\s*)#define\s+MBEDTLS_FS_IO/\1\/\/ #define MBEDTLS_FS_IO/' third_party/mbedtls/include/mbedtls/config.h
sed -ri 's/^(\s*)#define\s+MBEDTLS_HAVE_TIME_DATE/\1\/\/ #define MBEDTLS_HAVE_TIME_DATE/' third_party/mbedtls/include/mbedtls/config.h
sed -ri 's/^(\s*)#define\s+MBEDTLS_TIMING_C/\1\/\/ #define MBEDTLS_TIMING_C/' third_party/mbedtls/include/mbedtls/config.h
sed -ri 's/^(\s*)#define\s+MBEDTLS_PSA_ITS_FILE_C/\1\/\/ #define MBEDTLS_PSA_ITS_FILE_C/' third_party/mbedtls/include/mbedtls/config.h
sed -ri 's/^(\s*)#define\s+MBEDTLS_PSA_CRYPTO_STORAGE_C/\1\/\/ #define MBEDTLS_PSA_CRYPTO_STORAGE_C/' third_party/mbedtls/include/mbedtls/config.h
sed -ri 's/^(\s*)#define\s+MBEDTLS_NET_C/\1\/\/ #define MBEDTLS_NET_C/' third_party/mbedtls/include/mbedtls/config.h
make -C third_party/mbedtls lib CC=arm-none-eabi-gcc AR=arm-none-eabi-ar \
CFLAGS='-DMBEDTLS_NO_PLATFORM_ENTROPY -DMBEDTLS_NO_DEFAULT_ENTROPY_SOURCES -DMBEDTLS_TEST_NULL_ENTROPY'
mbedTLS 準備好 cache 後就能看到這個
Mbed TLS 的 CTR_DRBG 是依照 NIST SP 800-90A 的 CTR-DRBG 演算法實作,他需要熵做 input,例如 True Random Number Generator (TRNG)。TRNG 從名字看起來就像是一個產生真亂數的產生器,但實際上他只是一個 entropy sources,是代表合規 (SP 800-90B) 的熵源,這個熵源產生的熵,是用來給 SP 800-90A 產生亂數的。
Mbed TLS 取熵是通過 mbedtls_hardware_poll
,它是哪一個 implementation 是在 link time 決定的,如果是 -lnrf_cc3xx_platform,就會去讀CC310(或CC312) 的 TRNG,然後取熵。
因為 Renode 沒有 TRNG,如果還用 -lnrf_cc3xx_platform,就會因為讀不到 TRNG 而失敗。所以,在 Renode 用 Mbed TLS 產生亂數 (CTR_DRBG) 就要自己寫 mbedtls_hardware_poll
來提供熵。
TRNG 產生不了符合 800-90A 的亂數,但是 TRNG 的 output 可以給 800-90A 拿去產生亂數。
我們寫的 mbedtls_hardware_poll
只會用在 Renode 上做模擬,hardcode 就可以了
#include <stddef.h>
#include <string.h>
static const uint8_t entropy_input[32] = {
0x15,0x2B,0x7E,0xC3,0xA1,0x9D,0x1F,0x63,
0x5A,0x8E,0x2D,0x44,0x91,0x17,0x6B,0x3C,
0xDE,0xAD,0xBE,0xEF,0xFE,0xED,0xFA,0xCE,
0x12,0x34,0x56,0x78,0x9A,0xBC,0xDF,0x01
};
int mbedtls_hardware_poll(void *data,
unsigned char *out,
size_t len,
size_t *olen) {
(void)data;
for (size_t i = 0; i < len; i++) out[i] = entropy_input[i & 31];
*olen = len;
return 0;
}
寫完 mbedtls_hardware_poll
就可以直接使用 mbedTLS 取亂數,例如 platforms/mbedtls/rng.c
#include "../../hal_rng.h"
#include "uart_min.h"
#include <stdint.h>
#include <string.h>
#include "psa/crypto.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
void rng_init(const uint8_t *entropy, const uint8_t *pers, size_t L) {
psa_status_t status = psa_crypto_init();
if (status != PSA_SUCCESS) {
uarte0_puts("mbedtls_ctr_drbg_seed fail");
}
}
void rng_bytes(uint8_t *out, size_t len) {
psa_status_t status = psa_generate_random(out, len);
if (status != PSA_SUCCESS) {
uarte0_puts("mbedtls_ctr_drbg_random fail");
}
}
psa/crypto.h 是截錄自 PSA Certified Crypto API 1.1 [2
, 3
, 4
],entropy.h 和 ctr_drbg.h 是來自於 mbedtls [5
].
#pragma once
#include <stdint.h>
#include <stddef.h>
/*
* See https://arm-software.github.io/psa-api/crypto/1.1/api/library/status.html
*/
typedef int32_t psa_status_t;
#define PSA_SUCCESS ((psa_status_t)0)
/**
* See https://arm-software.github.io/psa-api/crypto/1.1/api/library/library.html#c.psa_crypto_init
*/
psa_status_t psa_crypto_init();
/**
* See https://arm-software.github.io/psa-api/crypto/1.1/api/ops/rng.html#c.psa_generate_random
*/
psa_status_t psa_generate_random(uint8_t *output, size_t output_size);
Makefile 在第一行加這個,強制讓 Makefile 不使用 NIST KAT rng.c
override export KAT := 0
然後將 Makefile 的 RNG_SRC 改成 platforms/mbedtls/rng.c
# Only use KAT rng.c when make KAT_RNG=1
ifeq ($(KAT_RNG),1)
RNG_SRC := kat/rng.c kat/kat_rng.c kat/aes256.c
CFLAGS += -DKAT_RNG
else
#RNG_SRC := $(PLATFORM)/rng.c
RNG_SRC := platforms/mbedtls/rng.c
endif
然後觀察CI的輸出
首先看到 rng.c,確實是我們剛寫的 mbedtls 底下的 rng.c
觀察到 map 有這三行,都是 mbedTLS的 library,是 CI 己經準備好的 cache
至此我們已經能用 mbedTLS 來產生亂數,這裡簡單說一下 psa_crypto_init
, psa_generate_random
這兩個 function, mbedTLS 和 PSA Certified Crypto API 彼此的關係。
PSA Certified Crypto API 定義了 function prototype,而 mbedTLS 對這些 function prototype 提供了實作,所以只要 linker 連結到 libmbedcrypto.a,同時在 CFLAGS 打開對應的開關,psa_crypto_init
, psa_generate_random
就會 reference 到 libmbedcrypto.a,而且,因為這是 .a,所以會是靜態連結,直接成為 elf 的一部份。
由於 mbedTLS 完成了靜態連結,PSA Certified Crypto API 的其他 function 將會很容易去呼叫,明天將會繼續在 mbedTLS 的基礎上實現 SLH-DSA 的演算法。