4. PSA Crypto API核心概念
在PSA Crypto API中,真正贯穿所有调用流程的并不是某个具体函数,而是一组彼此关联的核心概念:密钥标识用于定位密钥,密钥属性描述密钥的静态特征,密钥策略约束密钥能做什么,操作句柄承载一次具体运算的上下文,算法标识声明本次运算的算法与模式,错误码体系则统一反馈调用结果。理解这六个概念之间的关系,是后续集成、排障与安全审计的基础。
一、六个核心概念的分工与关系
可以把一次PSA调用理解为“用某把钥匙、按某条规则、做某件事”。密钥标识回答“用哪把钥匙”;密钥属性回答“这把钥匙长什么样”;密钥策略回答“这把钥匙被允许开哪些门”;算法标识回答“这次要开的是哪种锁”;操作句柄回答“这次开锁动作的现场凭证”;错误码回答“这次动作是否成功、失败原因是什么”。
二、密钥标识与密钥属性
密钥标识(psa_key_id_t)是一个整数型句柄,调用者通过它引用密钥库中的密钥。它本身不包含密钥材料,只是一个索引。密钥属性(psa_key_attributes_t)则是一组描述信息,包括密钥类型(如AES、ECC、RSA)、密钥位数、密钥用途(加密、解密、签名、验证、派生等)、允许的算法集合以及生命周期策略。
在导入或生成密钥时,必须先设置属性,再调用psa_import_key()或psa_generate_key(),系统会返回一个密钥标识。此后所有操作都通过该标识引用密钥,而不是直接传递密钥材料。这种设计实现了密钥材料与调用逻辑的分离,有利于安全隔离。
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_set_key_algorithm(&attr, PSA_ALG_GCM);
psa_key_id_t key_id;
psa_status_t st = psa_import_key(&attr, key_data, key_len, &key_id);
三、密钥策略:用途与算法白名单
密钥策略是密钥属性中最具安全意义的部分,由用途标志和允许算法共同构成。用途标志决定密钥能参与哪类操作,例如PSA_KEY_USAGE_ENCRYPT、PSA_KEY_USAGE_DECRYPT、PSA_KEY_USAGE_SIGN_HASH、PSA_KEY_USAGE_VERIFY_HASH、PSA_KEY_USAGE_DERIVE等。允许算法则是一个白名单,只有列出的算法才能与该密钥配合使用。
策略检查发生在每次运算调用时。如果调用者试图用一把仅允许加密的密钥执行解密,或者用AES-GCM密钥执行CBC模式,PSA会返回PSA_ERROR_NOT_PERMITTED。这种“默认拒绝”的机制,使得密钥即使被错误引用,也无法越权使用。
四、算法标识与操作句柄
算法标识(psa_algorithm_t)是一个复合编码,通常由算法族、具体算法、模式和哈希算法组合而成。例如PSA_ALG_ECDSA(PSA_ALG_SHA_256)表示使用SHA-256的ECDSA签名算法;PSA_ALG_GCM表示AES-GCM模式。算法标识在密钥策略和具体运算调用中都会出现,必须保持一致。
操作句柄(psa_operation_t)用于多步运算场景,如分块哈希、分块加解密或流式签名。调用psa_hash_setup()、psa_cipher_encrypt_setup()等函数时,会初始化一个操作句柄,后续通过psa_hash_update()、psa_cipher_update()逐步传入数据,最后用psa_hash_finish()或psa_cipher_finish()完成运算。操作句柄必须在完成或中止后释放,避免资源泄漏。
psa_operation_t op = PSA_OPERATION_INIT;
psa_hash_operation_t hash_op = PSA_HASH_OPERATION_INIT;
psa_status_t st = psa_hash_setup(&hash_op, PSA_ALG_SHA_256);
st = psa_hash_update(&hash_op, data1, len1);
st = psa_hash_update(&hash_op, data2, len2);
uint8_t digest[32];
size_t digest_len;
st = psa_hash_finish(&hash_op, digest, sizeof(digest), &digest_len);
五、错误码体系与常见状态
PSA Crypto API统一使用psa_status_t作为返回类型。成功时返回PSA_SUCCESS(值为0),失败时返回负值错误码。错误码按语义分类,便于快速定位问题。下表列出集成中最常见的状态码及其含义。
| 错误码 | 含义 | 典型触发场景 |
|---|---|---|
PSA_SUCCESS |
操作成功 | 正常完成 |
PSA_ERROR_NOT_PERMITTED |
密钥策略不允许该操作 | 用途或算法不在白名单中 |
PSA_ERROR_INVALID_ARGUMENT |
参数无效 | 算法标识与密钥类型不匹配 |
PSA_ERROR_NOT_SUPPORTED |
算法或密钥类型不支持 | 当前实现未启用该算法 |
PSA_ERROR_BUFFER_TOO_SMALL |
输出缓冲区不足 | 密文或摘要长度超出预期 |
PSA_ERROR_DOES_NOT_EXIST |
密钥标识不存在 | 密钥已被销毁或未导入 |
PSA_ERROR_BAD_STATE |
操作句柄状态异常 | 未setup就update,或重复finish |
六、案例与常见误区
假设一个物联网设备需要上报加密数据。开发者导入一把AES-256密钥,策略设置为仅允许PSA_KEY_USAGE_ENCRYPT和PSA_ALG_GCM。设备端调用psa_cipher_encrypt()成功。后来业务需要解密回读,开发者直接复用同一密钥调用解密接口,结果返回PSA_ERROR_NOT_PERMITTED。原因不是密钥错误,而是策略中没有授予解密用途。正确做法是重新导入或生成一把具有解密用途的密钥,或者在一开始就规划好双向用途。
复盘来看,六个核心概念构成了一条完整的约束链:密钥标识定位对象,密钥属性描述对象,密钥策略限制行为,算法标识声明意图,操作句柄承载过程,错误码反馈结果。任何一环理解偏差,都会表现为调用失败或安全策略失效。建议在集成初期就建立一张“密钥—策略—算法”对照表,并在每次调用后严格检查psa_status_t,把错误码处理纳入正常业务流程,而不是当作异常分支忽略。