HarmonyOS 鸿蒙Next中SM2密钥协商

HarmonyOS 鸿蒙Next中SM2密钥协商 密钥协商(ArkTS)-开发指导-密钥协商-密钥使用-Universal Keystore Kit(密钥管理服务)-安全-系统 - 华为HarmonyOS开发者

我参考文档写了SM2密钥协商的demo,但是没有输出结果,请问这是什么问题?

09-25 20:01:16.243   33053-33053   A03D00/com.example.dh/JSAPP     pid-33053             I     Callee constructor is OK string
09-25 20:01:16.243   33053-33053   A03D00/com.example.dh/JSAPP     pid-33053             I     Ability::constructor callee is object [object Object]
09-25 20:01:16.249   33053-33053   A00000/com.example.dh/testTag   pid-33053             I     Ability onCreate
09-25 20:01:16.257   33053-33053   A00000/com.example.dh/testTag   pid-33053             I     Ability onWindowStageCreate
09-25 20:01:16.262   33053-33053   A00000/com.example.dh/testTag   pid-33053             I     Ability onForeground
09-25 20:01:16.302   33053-33053   A00000/com.example.dh/testTag   pid-33053             I     Succeeded in loading the content.
import { huks } from '@kit.UniversalKeystoreKit';

// 辅助函数:将字符串转换为 Uint8Array
function StringToUint8Array(str: string) {
  let arr: number[] = [];
  for (let i = 0, j = str.length; i < j; ++i) {
    arr.push(str.charCodeAt(i));
  }
  return new Uint8Array(arr);
}

// 辅助函数:将 Uint8Array 转换为 BigInt
function Uint8ArrayToBigInt(arr: Uint8Array): bigint {
  let i = 0;
  const byteMax: bigint = BigInt('0x100');
  let result: bigint = BigInt('0');
  while (i < arr.length) {
    result = result * byteMax;
    result = result + BigInt(arr[i]);
    i += 1;
  }
  return result;
}

// SM2 密钥协商基本参数
const sm2Agree: Array<huks.HuksParam> = [
  {
    tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
    value: huks.HuksKeyAlg.HUKS_ALG_SM2, // 使用 SM2 算法
  },
  {
    tag: huks.HuksTag.HUKS_TAG_PURPOSE,
    value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE, // 密钥协商用途
  },
];

// SM2 密钥协商参数(256 位密钥)
const sm2Agree256: Array<huks.HuksParam> = [
  ...sm2Agree,
  {
    tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
    value: huks.HuksKeySize.HUKS_SM2_KEY_SIZE_256, // SM2 256 位密钥
  },
];

// SM2 密钥生成选项
const sm2GenOptions: huks.HuksOptions = {
  properties: sm2Agree256,
  inData: new Uint8Array([]),
};

// 空选项,用于导出密钥等操作
const emptyOptions: huks.HuksOptions = {
  properties: [],
  inData: new Uint8Array([]),
};

// SM2 密钥协商并导出共享密钥
async function HuksSm2AgreeExportKey(
  keyAlias: string,
  peerPubKey: huks.HuksReturnResult
): Promise<huks.HuksReturnResult> {
  const initHandle = await huks.initSession(keyAlias, sm2GenOptions);
  const sm2AgreeUpdatePeerPubKey: huks.HuksOptions = {
    properties: [
      ...sm2Agree256,
      {
        tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
        value: huks.HuksKeyStorageType.HUKS_STORAGE_KEY_EXPORT_ALLOWED, // 允许导出共享密钥
      },
    ],
    inData: peerPubKey.outData, // 对方的公钥
  };
  await huks.updateSession(initHandle.handle, sm2AgreeUpdatePeerPubKey);
  return await huks.finishSession(initHandle.handle, emptyOptions);
}

// 测试 SM2 密钥协商并导出共享密钥
async function HuksSm2AgreeExportTest(
  aliasA: string,
  aliasB: string,
  pubKeyA: huks.HuksReturnResult,
  pubKeyB: huks.HuksReturnResult
) {
  const agreedKeyFromAlice = await HuksSm2AgreeExportKey(aliasA, pubKeyB);
  console.info(
    `ok! agreedKeyFromAlice export is 0x${Uint8ArrayToBigInt(
      agreedKeyFromAlice.outData
    ).toString(16)}`
  );

  const agreedKeyFromBob = await HuksSm2AgreeExportKey(aliasB, pubKeyA);
  console.info(
    `ok! agreedKeyFromBob export is 0x${Uint8ArrayToBigInt(
      agreedKeyFromBob.outData
    ).toString(16)}`
  );
}

// SM2 密钥协商,共享密钥存储在 HUKS 中
async function HuksSm2AgreeInHuks(
  keyAlias: string,
  peerPubKey: huks.HuksReturnResult,
  aliasAgreedKey: string
): Promise<huks.HuksReturnResult> {
  const onlyUsedInHuks: Array<huks.HuksParam> = [
    {
      tag: huks.HuksTag.HUKS_TAG_KEY_STORAGE_FLAG,
      value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS, // 密钥仅在 HUKS 中使用
    },
    {
      tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
      value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS, // 共享密钥仅在 HUKS 中
    },
  ];

  const sm2AgreeInit: huks.HuksOptions = {
    properties: [
      ...sm2Agree,
      {
        tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
        value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, // 使用 SM4 128 位作为协商密钥
      },
      ...onlyUsedInHuks,
    ],
    inData: new Uint8Array([]),
  };

  const sm2AgreeFinishParams: Array<huks.HuksParam> = [
    ...onlyUsedInHuks,
    {
      tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS,
      value: true,
    },
    {
      tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
      value: huks.HuksKeyAlg.HUKS_ALG_SM4, // 协商密钥用于 SM4 加密
    },
    {
      tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
      value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, // SM4 128 位密钥
    },
    {
      tag: huks.HuksTag.HUKS_TAG_PURPOSE,
      value:
      huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT |
      huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, // 加密和解密用途
    },
  ];

  const handle = await huks.initSession(keyAlias, sm2AgreeInit);
  const sm2AgreeUpdatePubKey: huks.HuksOptions = {
    properties: [...sm2Agree, ...onlyUsedInHuks],
    inData: peerPubKey.outData, // 对方的公钥
  };
  await huks.updateSession(handle.handle, sm2AgreeUpdatePubKey);
  const sm2AgreeFinish: huks.HuksOptions = {
    properties: [
      ...sm2AgreeFinishParams,
      {
        tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS,
        value: StringToUint8Array(aliasAgreedKey), // 共享密钥的别名
      },
    ],
    inData: new Uint8Array([]),
  };
  return await huks.finishSession(handle.handle, sm2AgreeFinish);
}

// 测试 SM2 密钥协商,共享密钥存储在 HUKS 中
async function HuksSm2AgreeInHuksTest(
  aliasA: string,
  aliasB: string,
  pubKeyA: huks.HuksReturnResult,
  pubKeyB: huks.HuksReturnResult,
  aliasAgreedKeyFromA: string,
  aliasAgreedKeyFromB: string
) {
  const finishAliceResult = await HuksSm2AgreeInHuks(
    aliasA,
    pubKeyB,
    aliasAgreedKeyFromA
  );
  console.info(
    `ok! finishAliceResult in huks is 0x${Uint8ArrayToBigInt(
      finishAliceResult.outData
    ).toString(16)}`
  );
  const aliceAgreedExist = await huks.isKeyItemExist(
    aliasAgreedKeyFromA,
    emptyOptions
  );
  console.info(`ok! aliceAgreedExist in huks is ${aliceAgreedExist}`);

  const finishBobResult = await HuksSm2AgreeInHuks(
    aliasB,
    pubKeyA,
    aliasAgreedKeyFromB
  );
  console.info(
    `ok! finishBobResult in huks is 0x${Uint8ArrayToBigInt(
      finishBobResult.outData
    ).toString(16)}`
  );
  const bobAgreedExist = await huks.isKeyItemExist(
    aliasAgreedKeyFromB,
    emptyOptions
  );
  console.info(`ok! bobAgreedExist in huks is ${bobAgreedExist}`);

  // 清理协商生成的密钥
  await huks.deleteKeyItem(aliasAgreedKeyFromA, emptyOptions);
  await huks.deleteKeyItem(aliasAgreedKeyFromB, emptyOptions);
}

// 主测试函数
async function HuksSm2AgreeTest() {
  const aliasAlice = 'alice';
  const aliasBob = 'bob';

  // 生成 Alice 和 Bob 的 SM2 密钥对
  await huks.generateKeyItem(aliasAlice, sm2GenOptions);
  await huks.generateKeyItem(aliasBob, sm2GenOptions);

  // 导出 Alice 和 Bob 的公钥
  const pubKeyAlice = await huks.exportKeyItem(aliasAlice, emptyOptions);
  const pubKeyBob = await huks.exportKeyItem(aliasBob, emptyOptions);

  // 测试 SM2 密钥协商并导出共享密钥
  await HuksSm2AgreeExportTest(aliasAlice, aliasBob, pubKeyAlice, pubKeyBob);

  // 测试 SM2 密钥协商,共享密钥存储在 HUKS 中
  await HuksSm2AgreeInHuksTest(
    aliasAlice,
    aliasBob,
    pubKeyAlice,
    pubKeyBob,
    'agreedKeyFromAlice',
    'agreedKeyFromBob'
  );

  // 清理密钥
  await huks.deleteKeyItem(aliasAlice, emptyOptions);
  await huks.deleteKeyItem(aliasBob, emptyOptions);
}

// 运行测试
HuksSm2AgreeTest();


@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  build() {
    RelativeContainer() {
      Text(this.message)
        .id('HelloWorld')
        .fontSize($r('app.float.page_text_font_size'))
        .fontWeight(FontWeight.Bold)
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
        .onClick(() => {
          this.message = 'Welcome';
        })
    }
    .height('100%')
    .width('100%')
  }
}

更多关于HarmonyOS 鸿蒙Next中SM2密钥协商的实战教程也可以访问 https://www.itying.com/category-93-b0.html

4 回复

【解决方案】

根据密钥协商介绍及算法规格,目前仅支持ECDH,DH,X25519,不支持SM2。

更多关于HarmonyOS 鸿蒙Next中SM2密钥协商的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,SM2密钥协商基于国密算法标准,用于安全建立共享密钥。它通过椭圆曲线密码机制实现双方密钥交换,依赖SM2密钥对(公钥和私钥)完成协商过程。系统提供相关API支持密钥生成、协商计算及协议处理,确保端到端通信安全。具体实现需调用鸿蒙密码库接口,遵循GM/T 0003.5标准规范。

根据你提供的代码和日志,问题可能出现在以下几个方面:

  1. 密钥生成阶段:日志显示应用正常启动,但没有密钥协商相关的输出。首先检查generateKeyItem是否成功执行,建议在每个关键操作后添加日志输出,确认密钥对生成是否完成。

  2. 公钥导出问题exportKeyItem可能返回空数据。确保aliasAlicealiasBob对应的密钥已正确生成,且具有导出权限(HUKS_TAG_EXPORTABLE标签应设置为true)。

  3. 密钥协商参数不匹配:在HuksSm2AgreeExportKey函数中,sm2AgreeUpdatePeerPubKeyproperties包含了HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,但协商阶段可能不需要此标签。尝试移除该标签,仅保留基础SM2参数。

  4. 数据类型转换错误Uint8ArrayToBigInt函数在处理空或无效数据时可能抛出异常,导致后续日志无法输出。建议在转换前检查outData是否非空。

  5. 异步操作未正确处理:确保所有huksAPI调用均使用await,避免因异步未完成而跳过关键步骤。

建议先添加详细日志,定位具体失败的操作步骤,再逐步调整参数配置。

回到顶部