本日重點: 用 psa_mac_compute 去改寫 PRF_msg
Day 25 跳過了 psa_key_attributes_t,今天從 psa_key_attributes_t
開始。
對 psa_key_attributes_t
的初始化有幾個方法:memset、static、PSA_KEY_ATTRIBUTES_INIT、psa_key_attributes_init()
如果是用 macro,就是 PSA_KEY_ATTRIBUTES_INIT
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
雖然我在 psa_generate_key
的實作裡面不會去管 psa_key_attributes_t,但之後換成 Mbed TLS之後,psa_key_attributes_t 還是有作用的,所以接下來就是去指定各欄位。
因為我希望 key 是 persistent,所以 key_id 要自己指定,key_lifetime 也要設成 PSA_KEY_LIFETIME_PERSISTENT
psa_set_key_id(&attributes, 1)
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_PERSISTENT);
在指定 key type [1
, 2
] 的時候我發現了一個問題,Mbed TLS 的 psa_generate_key
尚未 support SLH-DSA,所以找不到能適用的 key type,雖然有 PSA Certified Crypto API 1.3 PQC Extension,但上面寫著 This is a BETA release ...
,網路上也找不到其他支援 SLH-DSA 的 psa_generate_key
implementation,所以現在寫的這版,我會用來在 nrf52840 和 nrf5340 實體開發版上執行。因此,一些不安全的做法,例如輸出到 UART 就遲早要拿掉。
那如果我自己產生 key,然後用 Mbed TLS 的 psa_import_key 匯入,讓 Mbed TLS 的 library 來維護私鑰行嗎? 我查了 psa_import_key,這樣也是不行的,會 return PSA_ERROR_INVALID_ARGUMENT
The key type is invalid.
至此,因為 key type 不支援 SLH-DSA,所以也不用過多的糾結 psa_key_attributes_t,直接這樣 call psa_generate_key
就可以了
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_id(&attributes, 1)
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_PERSISTENT);
psa_key_id_t key_id;
psa_status_t st = psa_generate_key(&attributes, &key_id);
PSA_KEY_ATTRIBUTES_INIT 是 macro,所以不用實作,直接用就可以了
crypto_struct.h, line 311
#define PSA_KEY_ATTRIBUTES_INIT { PSA_CORE_KEY_ATTRIBUTES_INIT, NULL, 0 }
產生 key 之後就是要簽章了,有兩個 function 是之後可以 offload 到 CC310/CC312的,就是 SHA-256 和 HMAC-SHA-256。
PSA 有兩個 define PSA_ALG_HMAC 和 PSA_ALG_SHA_256,可以這樣用
PSA_ALG_HMAC(PSA_ALG_SHA_256)
在 PSA_ALG_HMAC [3
] 的 Description 可以看到這段
PSA_ALG_HMAC(PSA_ALG_SHA_256) is HMAC-SHA-256.
這裡,我們看一下 PSA_ALG_HMAC [3
],PSA_ALG_HMAC 是一個 macro,使用它的時候,需要指定用哪一種 hash algorithm,例如 PSA_ALG_SHA_256
Macro to build an HMAC message-authentication-code algorithm from an underlying hash algorithm.
#define PSA_ALG_HMAC(hash_alg) /* specification-defined value */
PSA_ALG_HMAC 就是一個 psa_algorithm_t,是 psa_mac_compute 的第二個 parameter
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);
所以 HMAC-SHA-256 可以這麼呼叫 psa_mac_compute
psa_mac_compute(key, PSA_ALG_HMAC(PSA_ALG_SHA_256), ...)
PSA_ALG_SHA_256 也是 一種 psa_algorithm_t,但他不是 MAC algorithms,所以要用 psa_hash_compute
psa_status_t psa_hash_compute(psa_algorithm_t alg,
const uint8_t * input,
size_t input_length,
uint8_t * hash,
size_t hash_size,
size_t * hash_length);
因此,SHA-256 就 call psa_hash_compute(PSA_ALG_SHA_256, ...), HMAC-SHA-256 就 call psa_mac_compute(key, PSA_ALG_HMAC(PSA_ALG_SHA_256), ...)
接下來就是實作 psa_mac_compute
和 psa_hash_compute
,因為沒有連結到 Mbed TLS,所以我也不會真的去處理 psa_algorithm_t,我的策略就是 call psa_mac_compute 就直接執行 HMAC-SHA-256,call psa_hash_compute 就直接執行 SHA-256,反正之後在 nrf52840/nrf5340 上也是直接用 CC310/CC312。
SHA-256 和 HMAC-SHA-256 的軟體實作直接讓 ChatGPT 產生就可以了,不在這裡過多描述,寫完 psa_mac_compute
和 psa_hash_compute
就可以繼續改寫其他 function,因為實作全是 ChatGPT 所產生,重點就在於怎麼 call,例如:
const char abc[] = "abc";
uint8_t mac[32];
size_t mac_len = 0;
psa_status_t status = psa_mac_compute(key_id,
PSA_ALG_HMAC(PSA_ALG_SHA_256),
abc, sizeof(abc) - 1,
mac, sizeof(mac),
&mac_len);
const char abc[] = "abc";
uint8_t out32[32];
sha256(abc, sizeof(abc) - 1, out32);
psa_status_t status = psa_hash_compute(PSA_ALG_SHA_256,
abc, sizeof(abc) - 1,
out32, sizeof(out32),
PSA_HASH_LENGTH(PSA_ALG_SHA_256));
有一個地方要特別注意,在我實作的 psa_mac_compute
裡,因為目的是實現 SLH-DSA 演算法,所以我是直接去讀 static uint8_t sk_prf[SPX_N],這是不安全的,絕對不能在正式環境這麼做,我把 sk.prf 放 static 純粹是為了 方便在開發環境實現演算法。
至此,PRF_msg
就可以用 PSA_ALG_HMAC(PSA_ALG_SHA_256),然後改寫成這樣(第 15 行)
void prf_msg(uint8_t R[SPX_N],
psa_key_id_t key_id,
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];
size_t mac_len = 0;
psa_status_t status = psa_mac_compute(key_id,
PSA_ALG_HMAC(PSA_ALG_SHA_256),
opt_rand_M, sizeof(opt_rand_M) - 1,
hmac_sha256_out, sizeof(hmac_sha256_out),
&mac_len);
if (status != PSA_SUCCESS) {
uarte0_puts("psa_mac_compute fail");
for(;;); // 失敗就停在這裡
}
memcpy(R, hmac_sha256_out, SPX_N);
}