4. PSA Crypto API核心概念

在PSA Crypto API中,真正贯穿所有调用流程的并不是某个具体函数,而是一组彼此关联的核心概念:密钥标识用于定位密钥,密钥属性描述密钥的静态特征,密钥策略约束密钥能做什么,操作句柄承载一次具体运算的上下文,算法标识声明本次运算的算法与模式,错误码体系则统一反馈调用结果。理解这六个概念之间的关系,是后续集成、排障与安全审计的基础。

一、六个核心概念的分工与关系

可以把一次PSA调用理解为“用某把钥匙、按某条规则、做某件事”。密钥标识回答“用哪把钥匙”;密钥属性回答“这把钥匙长什么样”;密钥策略回答“这把钥匙被允许开哪些门”;算法标识回答“这次要开的是哪种锁”;操作句柄回答“这次开锁动作的现场凭证”;错误码回答“这次动作是否成功、失败原因是什么”。

PSA Crypto API 核心概念关系图 密钥标识 psa_key_id_t 定位密钥的唯一句柄 密钥属性 psa_key_attributes_t 类型、位数、用途、算法 密钥策略 usage + permitted_alg 允许的操作与算法白名单 算法标识 psa_algorithm_t 算法族 + 模式 + 哈希 操作句柄 psa_operation_t 多步运算的上下文 错误码体系 psa_status_t 统一状态反馈 典型调用流程 设置属性 set_attributes 导入/生成密钥 import / generate 执行运算 cipher / sign / hash 检查状态码 psa_status_t

二、密钥标识与密钥属性

密钥标识(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,把错误码处理纳入正常业务流程,而不是当作异常分支忽略。