iT邦幫忙

2025 iThome 鐵人賽

DAY 26
0

本日重點: 用 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_computepsa_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_computepsa_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);
}

References

  1. psa_key_type_t
  2. B.2 Key type encoding
  3. PSA_ALG_HMAC

上一篇
Day 25 以 PSA Certified Crypto API 的 interface 實作 SLH-DSA 演算法 (三)
下一篇
Day 27 將 psa_key_id_t 整合到 SLH-DSA 簽章演算法的實作裡
系列文
裸機實作 SLH-DSA 簽章:FIPS 205 之演算法實作、測試、防禦與跨平台27
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言