返回首页

PSA Crypto 学习笔记

本笔记学习 PSA(Platform Security Architecture)Crypto API,ARM 推出的标准化密码学接口。


示例路径

nrf/samples/crypto/ecdsa/    - ECDSA 签名验证
nrf/samples/crypto/aes_gcm/  - AES-GCM 认证加密
nrf/samples/crypto/ecdh/     - ECDH 密钥协商
nrf/samples/crypto/sha256/   - SHA-256 哈希
nrf/samples/crypto/hmac/     - HMAC 消息认证

核心概念

PSA Crypto API 是什么?

PSA Crypto API 是 ARM 定义的平台安全架构密码学接口,提供:

特性说明
统一接口硬件加速器和软件实现统一 API
安全设计密钥不可导出、安全存储
可扩展支持多种算法和密钥类型
认证通过 PSA 认证测试

支持的算法

类别常见算法
哈希SHA-1, SHA-224, SHA-256, SHA-384, SHA-512
AEADAES-GCM, AES-CCM, ChaCha20-Poly1305
对称加密AES-CBC, AES-CTR, AES-XTS
非对称签名ECDSA, RSA-PKCS1, RSA-PSS
密钥协商ECDH
MACHMAC, CMAC
KDFHKDF, PBKDF2, TLS-12-PRF

具体算法是否可用,取决于当前 SoC、后端实现和 prj.conf 中启用的 CONFIG_PSA_WANT_* 选项。


基本使用流程

1. 初始化 PSA Crypto

#include <psa/crypto.h>

psa_status_t status;

status = psa_crypto_init();
if (status != PSA_SUCCESS) {
    printk("PSA Crypto 初始化失败: %d\n", status);
    return -1;
}

2. 生成密钥

psa_key_id_t key_id;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;

/* 设置密钥属性 */
psa_set_key_usage_flags(&attributes, 
                        PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH);
psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_bits(&attributes, 256);

/* 生成密钥 */
status = psa_generate_key(&attributes, &key_id);
if (status != PSA_SUCCESS) {
    printk("密钥生成失败: %d\n", status);
    return -1;
}

psa_reset_key_attributes(&attributes);

3. 使用密钥

/* 签名 */
uint8_t hash[32] = {...};  // SHA-256 哈希值
uint8_t signature[128];
size_t sig_len;

status = psa_sign_hash(key_id, 
                       PSA_ALG_ECDSA(PSA_ALG_SHA_256),
                       hash, sizeof(hash),
                       signature, sizeof(signature),
                       &sig_len);

/* 验证 */
status = psa_verify_hash(key_id,
                         PSA_ALG_ECDSA(PSA_ALG_SHA_256),
                         hash, sizeof(hash),
                         signature, sig_len);

4. 销毁密钥

psa_destroy_key(key_id);

完整示例:ECDSA 签名验证

#include <zephyr/kernel.h>
#include <psa/crypto.h>

static void print_hex(const char *label, const uint8_t *data, size_t len)
{
    printk("%s: ", label);
    for (size_t i = 0; i < len; i++) {
        printk("%02x", data[i]);
    }
    printk("\n");
}

int ecdsa_demo(void)
{
    psa_status_t status;
    psa_key_id_t key_id;
    psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
    
    /* 1. 初始化 */
    status = psa_crypto_init();
    if (status != PSA_SUCCESS) {
        printk("初始化失败: %d\n", status);
        return -1;
    }
    
    /* 2. 设置密钥属性 */
    psa_set_key_usage_flags(&attr, 
                            PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH |
                            PSA_KEY_USAGE_EXPORT);
    psa_set_key_algorithm(&attr, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
    psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
    psa_set_key_bits(&attr, 256);
    
    /* 3. 生成 ECC 密钥对 */
    status = psa_generate_key(&attr, &key_id);
    if (status != PSA_SUCCESS) {
        printk("密钥生成失败: %d\n", status);
        return -1;
    }
    printk("ECC 密钥对已生成\n");
    
    /* 4. 导出公钥 */
    uint8_t pubkey[128];
    size_t pubkey_len;
    status = psa_export_public_key(key_id, pubkey, sizeof(pubkey), &pubkey_len);
    print_hex("公钥", pubkey, pubkey_len);
    
    /* 5. 计算消息哈希 */
    const char *message = "Hello, PSA Crypto!";
    uint8_t hash[32];
    size_t hash_len;
    
    status = psa_hash_compute(PSA_ALG_SHA_256,
                              message, strlen(message),
                              hash, sizeof(hash), &hash_len);
    print_hex("哈希", hash, hash_len);
    
    /* 6. 签名 */
    uint8_t signature[128];
    size_t sig_len;
    
    status = psa_sign_hash(key_id,
                           PSA_ALG_ECDSA(PSA_ALG_SHA_256),
                           hash, hash_len,
                           signature, sizeof(signature),
                           &sig_len);
    if (status == PSA_SUCCESS) {
        printk("签名成功\n");
        print_hex("签名", signature, sig_len);
    }
    
    /* 7. 验证签名 */
    status = psa_verify_hash(key_id,
                             PSA_ALG_ECDSA(PSA_ALG_SHA_256),
                             hash, hash_len,
                             signature, sig_len);
    if (status == PSA_SUCCESS) {
        printk("签名验证成功 ✓\n");
    } else {
        printk("签名验证失败 ✗\n");
    }
    
    /* 8. 清理 */
    psa_destroy_key(key_id);
    
    return 0;
}

完整示例:AES-GCM 认证加密

#include <zephyr/kernel.h>
#include <psa/crypto.h>

int aes_gcm_demo(void)
{
    psa_status_t status;
    psa_key_id_t key_id;
    psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
    
    /* 初始化 */
    psa_crypto_init();
    
    /* 设置 AES 密钥属性 */
    psa_set_key_usage_flags(&attr, 
                            PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
    psa_set_key_algorithm(&attr, PSA_ALG_GCM);
    psa_set_key_type(&attr, PSA_KEY_TYPE_AES);
    psa_set_key_bits(&attr, 128);
    
    /* 生成 AES 密钥 */
    status = psa_generate_key(&attr, &key_id);
    printk("AES 密钥已生成\n");
    
    /* 明文和附加数据 */
    const char *plaintext = "Secret message for AES-GCM encryption!";
    const char *aad = "Additional authenticated data";
    
    /* 生成随机 IV (12 bytes for GCM) */
    uint8_t iv[12];
    status = psa_generate_random(iv, sizeof(iv));
    
    /* 加密 */
    uint8_t ciphertext[128];
    size_t ciphertext_len;
    
    status = psa_aead_encrypt(key_id, PSA_ALG_GCM,
                              iv, sizeof(iv),
                              (const uint8_t *)aad, strlen(aad),
                              (const uint8_t *)plaintext, strlen(plaintext),
                              ciphertext, sizeof(ciphertext),
                              &ciphertext_len);
    
    if (status == PSA_SUCCESS) {
        printk("加密成功,密文长度: %d (含 16 bytes tag)\n", ciphertext_len);
    }
    
    /* 解密 */
    uint8_t decrypted[128];
    size_t decrypted_len;
    
    status = psa_aead_decrypt(key_id, PSA_ALG_GCM,
                              iv, sizeof(iv),
                              (const uint8_t *)aad, strlen(aad),
                              ciphertext, ciphertext_len,
                              decrypted, sizeof(decrypted),
                              &decrypted_len);
    
    if (status == PSA_SUCCESS) {
        decrypted[decrypted_len] = '\0';
        printk("解密成功: %s\n", decrypted);
    } else {
        printk("解密失败: 认证标签不匹配或数据被篡改\n");
    }
    
    /* 清理 */
    psa_destroy_key(key_id);
    
    return 0;
}

密钥管理

密钥属性

psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;

/* 密钥类型 */
psa_set_key_type(&attr, PSA_KEY_TYPE_AES);

/* 密钥位数 */
psa_set_key_bits(&attr, 256);

/* 使用标志 */
psa_set_key_usage_flags(&attr,
    PSA_KEY_USAGE_ENCRYPT |       // 加密
    PSA_KEY_USAGE_DECRYPT |       // 解密
    PSA_KEY_USAGE_SIGN_HASH |     // 签名
    PSA_KEY_USAGE_VERIFY_HASH |   // 验证
    PSA_KEY_USAGE_DERIVE |        // 密钥派生
    PSA_KEY_USAGE_EXPORT          // 导出
);

/* 算法 */
psa_set_key_algorithm(&attr, PSA_ALG_GCM);

/* 密钥 ID(持久化时使用)*/
psa_set_key_id(&attr, 1);  // 持久化密钥 ID

/* 生命周期 */
psa_set_key_lifetime(&attr, PSA_KEY_LIFETIME_PERSISTENT);

密钥导入/导出

/* 导入密钥 */
uint8_t key_data[32] = {...};
psa_key_id_t key_id;

status = psa_import_key(&attr, key_data, sizeof(key_data), &key_id);

/* 导出密钥 */
uint8_t exported[64];
size_t exported_len;
status = psa_export_key(key_id, exported, sizeof(exported), &exported_len);

/* 导出公钥(私钥对)*/
status = psa_export_public_key(key_id, exported, sizeof(exported), &exported_len);

哈希计算

#include <psa/crypto.h>

/* 一次性计算 */
uint8_t hash[32];
size_t hash_len;

psa_status_t status = psa_hash_compute(
    PSA_ALG_SHA_256,
    data, data_len,
    hash, sizeof(hash), &hash_len
);

/* 分块计算 */
psa_hash_operation_t op = PSA_HASH_OPERATION_INIT;

psa_hash_setup(&op, PSA_ALG_SHA_256);
psa_hash_update(&op, chunk1, len1);
psa_hash_update(&op, chunk2, len2);
psa_hash_finish(&op, hash, sizeof(hash), &hash_len);

配置选项

# prj.conf

# 启用 PSA Crypto
CONFIG_PSA_CRYPTO_CLIENT=y

# 启用特定算法
CONFIG_PSA_WANT_ALG_SHA_256=y
CONFIG_PSA_WANT_ALG_ECDSA=y
CONFIG_PSA_WANT_ALG_GCM=y

# 启用密钥类型
CONFIG_PSA_WANT_KEY_TYPE_AES=y
CONFIG_PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE=y

# 启用随机数生成
CONFIG_PSA_WANT_GENERATE_RANDOM=y

# nRF Security 后端
CONFIG_NRF_SECURITY=y

nRF 芯片硬件加速

nRF54L15 Crypto 特性

特性说明
CRACEN加密加速引擎
ECC硬件 ECC 加速
AES硬件 AES 加速
SHA硬件 SHA 加速
TRNG真随机数生成器

启用硬件加速

CONFIG_PSA_CRYPTO_DRIVER_CRACEN=y

错误处理

错误码含义
PSA_SUCCESS成功
PSA_ERROR_NOT_SUPPORTED不支持
PSA_ERROR_INSUFFICIENT_MEMORY内存不足
PSA_ERROR_CORRUPTION_DETECTED数据损坏
PSA_ERROR_INVALID_SIGNATURE签名无效
PSA_ERROR_INVALID_HANDLE密钥句柄无效
psa_status_t status = psa_sign_hash(...);

if (status != PSA_SUCCESS) {
    printk("操作失败: %d\n", status);
    switch (status) {
    case PSA_ERROR_NOT_SUPPORTED:
        printk("算法不支持\n");
        break;
    case PSA_ERROR_INVALID_HANDLE:
        printk("密钥无效\n");
        break;
    default:
        printk("其他错误\n");
    }
}

安全最佳实践

  1. 最小权限: 只设置必要的 usage flags
  2. 密钥保护: 避免导出私钥
  3. 随机 IV: 每次加密使用新的随机 IV
  4. 密钥轮换: 定期更换密钥
  5. 安全存储: 使用 PSA 持久化密钥存储

应用场景

场景推荐算法
数据加密AES-256-GCM
数字签名ECDSA (secp256r1)
密钥协商ECDH
密码存储PBKDF2 + SHA-256
消息认证HMAC-SHA256

相关 API 总结

函数说明
psa_crypto_init()初始化
psa_generate_key()生成密钥
psa_import_key()导入密钥
psa_export_key()导出密钥
psa_destroy_key()销毁密钥
psa_hash_compute()计算哈希
psa_sign_hash()签名
psa_verify_hash()验证签名
psa_aead_encrypt()认证加密
psa_aead_decrypt()认证解密
psa_generate_random()生成随机数

*小白 🤖 - 2026-03-17*