昨天我們在連結 Oberon 的時候失敗,只要在 Makefile 做以下的修改 (第 15 行),連結就會成功
ifeq ($(TARGET),nrf52840)
CFLAGS += -mfloat-abi=soft -mfpu=fpv4-sp-d16 -O2 \
-I$(NRFXLIB_DIR)/crypto/nrf_oberon/include
ARCH_DIR := cortex-m4
FLOAT_DIR := soft-float
else ifeq ($(TARGET),nrf5340dk)
CFLAGS += -mfloat-abi=soft -mfpu=fpv5-sp-d16 -O2 \
-I$(NRFXLIB_DIR)/crypto/nrf_oberon/include
ARCH_DIR := cortex-m33+nodsp
FLOAT_DIR := soft-float
endif
OBERON_LIB := $(NRFXLIB_DIR)/crypto/nrf_oberon/lib/$(strip $(ARCH_DIR))/$(strip $(FLOAT_DIR))/liboberon_3.0.17.a
昨天連結失敗是因為第11行後面有空白,所以串接路徑的時候會多了空白,為了避免空白這種問題,第15行就用 $(strip $(FLOAT_DIR))
。
如果成功連結到 Oberon cryptographic library 的 ocrypto_hmac_sha256 和 ocrypto_sha256,就會在 map 看到以下結果
Oberon 有版權,請詳閱 LICENSE。如果要把 Oberon library 靜態放進 ELF 做發佈,請務必詳閱 LICENSE 以避免侵權。
hmac_sha256 可以這樣用 [2
]
int hmac_sha256(uint8_t out[32],
const uint8_t *key, size_t key_len,
const uint8_t *msg, size_t msg_len)
{
ocrypto_hmac_sha256_ctx ctx;
ocrypto_hmac_sha256_init(&ctx, key, key_len);
ocrypto_hmac_sha256_update(&ctx, msg, msg_len);
ocrypto_hmac_sha256_final(&ctx, out);
return 0;
}
然後我們寫一段測試一下
void test_hmac_sha256()
{
uint8_t sk_seed[SPX_N];
uint8_t pk_seed[SPX_N];
unsigned char entropy_input[48];
for (int i=0; i<48; i++) {
entropy_input[i] = i;
}
rng_init(entropy_input, NULL, 256);
rng_bytes(sk_seed, SPX_N);
rng_bytes(pk_seed, SPX_N);
uint8_t hmac_sha256_out[32];
hmac_sha256(hmac_sha256_out, sk_seed, SPX_N, "abc", 3);
uarte0_hex("hmac_sha256", hmac_sha256_out, 32);
}
在 CI 我們就可以看到這個結果
PRF_msg 可以這樣用 hmac_sha256
static void prf_msg(uint8_t R[SPX_N],
const uint8_t sk_prf[SPX_N],
const uint8_t optrand[SPX_N],
const uint8_t *m,
size_t mlen)
{
uint8_t opt_rand_M[SPX_N + mlen];
memcpy(opt_rand_M, optrand, SPX_N);
memcpy(opt_rand_M + SPX_N, m, mlen);
uint8_t hmac_sha256_out[32];
hmac_sha256(hmac_sha256_out, sk_prf, SPX_N, opt_rand_M, sizeof(opt_rand_M));
memcpy(R, hmac_sha256_out, SPX_N);
}
使用 ocrypto_hmac_sha256 是暫時的,純粹是方便在開發階段用 ocrypto_hmac_sha256 在 renode 計算 hmac_sha256。
一開始寫的 hmac_sha256,我想把 function宣告成 PSA 的 function prototype [3
] [4
],所以在這裡講一下 PSA Certified Crypto API,簡單來說,他是 Arm 推動的一個 API,他對底層的 implementation 做了抽象化,也就是說,只要相容這個 API,可以直接更換不同的實作,不侷限於 Arm 的硬體,也不侷限於某一個 library。所以,我現在把 function prototype 照 PSA Certified Crypto API 改寫,之後如果有別人提供了不同的實作,只要是支援 PSA Certified Crypto API,那我就可以直接連結到其他的實作而不用改我的程式。
psa_mac_compute
[4
] 的 prototype 是這樣
psa_status_t psa_mac_compute(psa_key_id_t key,
psa_algorithm_t alg,
const uint8_t * input,
size_t input_length,
uint8_t * mac,
size_t mac_size,
size_t * mac_length);
psa_mac_compute 有一個值得注意的地方,他和我一開始草率的實作有一個很大的不同,psa_mac_compute 的第一個參數 psa_key_id_t,就是一個 key handle,有了 key handle,就不用像我一開始寫的 hmac_sha256那樣還要傳 sk_seed 給 hmac_sha256,這是很重要的一點,這代表目前為止把 sk_seed 拿來在各 function 之間傳遞的情況將不復見,從此傳的都是 key handle。
CryptoCell 312 有 Key Management Unit (KMU) keys,因為 CryptoCell-310 沒有 KMU,所以之後我只會在 nRF5340 DK 上實驗 key handle。