返回首页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 |
| AEAD | AES-GCM, AES-CCM, ChaCha20-Poly1305 |
| 对称加密 | AES-CBC, AES-CTR, AES-XTS |
| 非对称签名 | ECDSA, RSA-PKCS1, RSA-PSS |
| 密钥协商 | ECDH |
| MAC | HMAC, CMAC |
| KDF | HKDF, 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");
}
}
安全最佳实践
- 最小权限: 只设置必要的 usage flags
- 密钥保护: 避免导出私钥
- 随机 IV: 每次加密使用新的随机 IV
- 密钥轮换: 定期更换密钥
- 安全存储: 使用 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*