在端云协同或离线通信场景中,非对称加密的密钥分发一直是个难题:传统上需要同时持有私钥和公钥,或者依赖网络从服务器下载密钥对。但在某些脱网环境(如智能卡读取、加密狗植入),终端往往只能拿到一串裸私钥二进制流。如何在本地安全地推导出对应的公钥,一度需要引入庞大的第三方库如 OpenSSL,导致应用体积膨胀且内存安全难以保障。
HarmonyOS NEXT 6.1(API 23)的 Crypto Architecture Kit 从架构层面解决了这一痛点——为 PriKey 对象新增了 getPubKey() 和 getPubKeySync() 两个方法。开发者仅凭一把私钥,就能在端侧安全无损地剥离重构出配套公钥,彻底摆脱“全量密钥对分发协议”的束缚。
核心机制与底层链路
新 API 并非直接对一段 Uint8Array 二进制调用 getPubKey,而是需要先通过 Crypto 引擎将裸私钥流转换为引擎可识别的 PriKey 对象。转换的关键步骤是使用 createAsyKeyGenerator 创建非对称生成器,然后调用 convertKeySync,并将公钥参数传入 null,表示只注入私钥。后续即可在 PriKey 对象上调用 getPubKey 或 getPubKeySync 获得公钥,再通过 getEncoded 导出公钥裸流。整个过程无需依赖网络,且基于系统级硬件加密库,保障安全与性能。
实战:构建密钥衍生控制舱
以下是一个完整的工程化示例,演示如何从裸私钥流异步/同步剥离公钥,并与预期公钥进行字节级比对。代码位于 CryptoDemo.ets 中。
- import { cryptoFramework } from '@kit.CryptoArchitectureKit';
- import { buffer } from '@kit.ArkTS';
- import { promptAction } from '@kit.ArkUI';
- @Entry
- @Component
- struct CryptoDemo {
- @State log: string = '等待中控台指令...\n';
- @State isExtracting: boolean = false;
- @State extractedPubKeyData: string = '';
- // 模拟从外部(如网络或本地安全区)加载的裸私钥二进制流 (RSA1024)
- private readonly skData = new Uint8Array([48, 130, 2, 119, 2, 1, 0, 48, /* ...此处省略大量字节... */ 248, 148, 151]);
- // 预期的裸公钥二进制流(用于比对验证剥离是否无损)
- private readonly expectPkdata = new Uint8Array([48, 129, 159, 48, /* ...此处省略大量字节... */ 3, 1, 0, 1]);
- async extractPubKey(useSync: boolean) {
- this.isExtracting = true;
- this.extractedPubKeyData = '';
- try {
- let rsaGenerator = cryptoFramework.createAsyKeyGenerator('RSA1024');
- let skDataBlob: cryptoFramework.DataBlob = { data: this.skData };
- // 关键:注入私钥,公钥传 null
- let keyPair = rsaGenerator.convertKeySync(null, skDataBlob);
- let priKey = keyPair.priKey;
- let pubkey: cryptoFramework.PubKey;
- if (useSync) {
- pubkey = priKey.getPubKeySync();
- } else {
- pubkey = await priKey.getPubKey();
- }
- let pkBlob = pubkey.getEncoded();
- // 字节级比对
- let isValid: boolean = buffer.from(pkBlob.data).compare(this.expectPkdata) === 0;
- if (isValid) {
- this.extractedPubKeyData = Array.from(pkBlob.data).map(b => b.toString(16).padStart(2, '0')).join('').substring(0, 48) + '...';
- promptAction.showToast({ message: '公钥提取成功' });
- }
- } catch (e) {
- // 错误处理
- } finally {
- this.isExtracting = false;
- }
- }
- }
复制代码
避坑指南
- 类型强校验:传入 convertKeySync 的数据必须是合法的 Uint8Array。如果服务端返回 Base64 编码的密钥,务必先使用 util.Base64Helper 解码,切忌用 any 绕过类型检查。
- 同步 vs 异步:对于 RSA1024 等短密钥,getPubKeySync 可瞬间完成;但对于 RSA4096 或国密 SM2 等复杂算法,推荐使用基于 Promise 的 getPubKey(),避免主线程卡顿甚至触发 Watchdog 超时。
- 算法严格匹配:用 RSA1024 生成器只能处理 RSA1024 规格的私钥数据流。若传入 RSA2048 的数据,底层在 convertKeySync 时会抛出错误码 17620002(参数转换失败),务必严格对齐算法与密钥长度。
总结
Crypto Architecture Kit 在 API 23 的私钥剥离公钥能力,看似是微小函数新增,实则为端侧密码学架构带来重要突破。它让终端设备仅需最核心的 Private Key 种子,就能本地安全衍生出配套公钥,大幅降低带宽与存储开销。在无网、离线、近场认证等严苛场景中,该特性成为开发者的利器。 |