密钥协商(ArkTS)

以协商密钥类型为X25519,并密钥仅在HUKS内使用为例,完成密钥协商。具体的场景介绍及支持的算法规格,请参考密钥生成支持的算法

开发步骤

生成密钥

设备A、设备B各自生成一个非对称密钥,具体请参考密钥生成密钥导入

密钥生成时,可指定参数HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG(可选),用于标识基于该密钥协商出的密钥是否由HUKS管理。

  • 当TAG设置为HUKS_STORAGE_ONLY_USED_IN_HUKS时,表示基于该密钥协商出的密钥,由HUKS管理,可保证协商密钥全生命周期不出安全环境。

  • 当TAG设置为HUKS_STORAGE_KEY_EXPORT_ALLOWED时,表示基于该密钥协商出的密钥,返回给调用方管理,由业务自行保证密钥安全。

  • 若业务未设置TAG的具体值,表示基于该密钥协商出的密钥,可由HUKS管理,也可返回给调用方管理,业务可在后续协商时再选择使用何种方式保护密钥。

导出密钥

设备A、B导出非对称密钥对的公钥材料,具体请参考密钥导出

密钥协商

设备A、B分别基于本端私钥和对端设备的公钥,协商出共享密钥。

密钥协商时,可指定参数HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG(可选),用于标识协商得到的密钥是否由HUKS管理。

生成 协商 规格
HUKS_STORAGE_ONLY_USED_IN_HUKS HUKS_STORAGE_ONLY_USED_IN_HUKS 密钥由HUKS管理
HUKS_STORAGE_KEY_EXPORT_ALLOWED HUKS_STORAGE_KEY_EXPORT_ALLOWED 密钥返回给调用方管理
未指定TAG具体值 HUKS_STORAGE_ONLY_USED_IN_HUKS 密钥由HUKS管理
未指定TAG具体值 HUKS_STORAGE_KEY_EXPORT_ALLOWED 密钥返回给调用方管理
未指定TAG具体值 未指定TAG具体值 密钥返回给调用方管理

注:协商时指定的TAG值,不可与生成时指定的TAG值冲突。表格中仅列举有效的指定方式。

删除密钥

当密钥废弃不用时,设备A、B均需要删除密钥,具体请参考密钥删除

下面分别以X25519 与 DH密钥为例,进行协商。

  • X25519非对称密钥协商用例

    /*
    *以下以X25519密钥的Promise操作使用为例
    */
    import { huks } from '@kit.UniversalKeystoreKit';
    
    /*
    * 确定密钥别名和封装密钥属性参数集
    */
    let srcKeyAliasFirst = "AgreeX25519KeyFirstAlias";
    let srcKeyAliasSecond = "AgreeX25519KeySecondAlias";
    let agreeX25519InData = 'AgreeX25519TestIndata';
    let finishOutData: Uint8Array;
    let handle: number;
    let exportKey: Uint8Array;
    let exportKeyFirst: Uint8Array;
    let exportKeySecond: Uint8Array;
    /* 集成生成密钥参数集 */
    let properties: Array<huks.HuksParam> = [{
      tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
      value: huks.HuksKeyAlg.HUKS_ALG_X25519,
    }, {
      tag: huks.HuksTag.HUKS_TAG_PURPOSE,
      value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE,
    }, {
      tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
      value: huks.HuksKeySize.HUKS_CURVE25519_KEY_SIZE_256,
    }, {
      tag: huks.HuksTag.HUKS_TAG_DIGEST,
      value: huks.HuksKeyDigest.HUKS_DIGEST_NONE,
    }, {
      tag: huks.HuksTag.HUKS_TAG_PADDING,
      value: huks.HuksKeyPadding.HUKS_PADDING_NONE,
    }, {
      tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
      value: huks.HuksCipherMode.HUKS_MODE_CBC,
    }, {
      tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
      value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
    }];
    let HuksOptions: huks.HuksOptions = {
      properties: properties,
      inData: new Uint8Array(new Array())
    }
    /* 集成第一个协商参数集 */
    const finishProperties: Array<huks.HuksParam> = [{
      tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
      value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
    }, {
      tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS,
      value: true
    }, {
      tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
      value: huks.HuksKeyAlg.HUKS_ALG_AES,
    }, {
      tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
      value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256,
    }, {
      tag: huks.HuksTag.HUKS_TAG_PURPOSE,
      value:
      huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT |
      huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT,
    }, {
      tag: huks.HuksTag.HUKS_TAG_DIGEST,
      value: huks.HuksKeyDigest.HUKS_DIGEST_NONE,
    }, {
      tag: huks.HuksTag.HUKS_TAG_PADDING,
      value: huks.HuksKeyPadding.HUKS_PADDING_NONE,
    }, {
      tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
      value: huks.HuksCipherMode.HUKS_MODE_ECB,
    }];
    let finishOptionsFirst: huks.HuksOptions = {
      properties: [
        ...finishProperties, {
        tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS,
        value: StringToUint8Array(srcKeyAliasFirst + 'final'),
      }],
      inData: StringToUint8Array(agreeX25519InData)
    }
    /* 集成第二个协商参数集 */
    let finishOptionsSecond: huks.HuksOptions = {
      properties: [
        ...finishProperties, {
        tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS,
        value: StringToUint8Array(srcKeyAliasSecond + 'final'),
      }],
      inData: StringToUint8Array(agreeX25519InData)
    }
    
    function StringToUint8Array(str: string) {
      let arr: number[] = new Array();
      for (let i = 0, j = str.length; i < j; ++i) {
        arr.push(str.charCodeAt(i));
      }
      return new Uint8Array(arr);
    }
    
    class throwObject {
      isThrow: boolean = false
    }
    
    /* 生成密钥 */
    function generateKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) {
      return new Promise<void>((resolve, reject) => {
        try {
          huks.generateKeyItem(keyAlias, huksOptions, (error, data) => {
            if (error) {
              reject(error);
            } else {
              resolve(data);
            }
          });
        } catch (error) {
          throwObject.isThrow = true;
          throw (error as Error);
        }
      });
    }
    
    /* 调用generateKeyItem生成密钥 */
    async function publicGenKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) {
      console.info(`enter promise generateKeyItem`);
      let throwObject: throwObject = { isThrow: false };
      try {
        await generateKeyItem(keyAlias, huksOptions, throwObject)
          .then((data) => {
            console.info(`promise: generateKeyItem success, data = ${JSON.stringify(data)}`);
          })
          .catch((error: Error) => {
            if (throwObject.isThrow) {
              throw (error as Error);
            } else {
              console.error(`promise: generateKeyItem failed, ${JSON.stringify(error)}`);
            }
          });
      } catch (error) {
        console.error(`promise: generateKeyItem input arg invalid, ${JSON.stringify(error)}`);
      }
    }
    
    /*初始化密钥会话接口,并获取一个句柄(必选)和挑战值(可选)*/
    function initSession(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) {
      return new Promise<huks.HuksSessionHandle>((resolve, reject) => {
        try {
          huks.initSession(keyAlias, huksOptions, (error, data) => {
            if (error) {
              reject(error);
            } else {
              resolve(data);
            }
          });
        } catch (error) {
          throwObject.isThrow = true;
          throw (error as Error);
        }
      });
    }
    
    /*调用initSession获取handle*/
    async function publicInitFunc(keyAlias: string, huksOptions: huks.HuksOptions) {
      console.info(`enter promise doInit`);
      let throwObject: throwObject = { isThrow: false };
      try {
        await initSession(keyAlias, huksOptions, throwObject)
          .then((data) => {
            console.info(`promise: doInit success, data = ${JSON.stringify(data)}`);
            handle = data.handle;
          })
          .catch((error: Error) => {
            if (throwObject.isThrow) {
              throw (error as Error);
            } else {
              console.error(`promise: doInit failed, ${JSON.stringify(error)}`);
            }
          });
      } catch (error) {
        console.error(`promise: doInit input arg invalid, ${JSON.stringify(error)}`);
      }
    }
    
    /* 分段添加密钥操作的数据并进行相应的密钥操作,输出处理数据 */
    function updateSession(handle: number, huksOptions: huks.HuksOptions, throwObject: throwObject) {
      return new Promise<huks.HuksReturnResult>((resolve, reject) => {
        try {
          huks.updateSession(handle, huksOptions, (error, data) => {
            if (error) {
              reject(error);
            } else {
              resolve(data);
            }
          });
        } catch (error) {
          throwObject.isThrow = true;
          throw (error as Error);
        }
      });
    }
    
    /* 调用updateSession进行协商操作 */
    async function publicUpdateFunc(handle: number, huksOptions: huks.HuksOptions) {
      console.info(`enter promise doUpdate`);
      let throwObject: throwObject = { isThrow: false };
      try {
        await updateSession(handle, huksOptions, throwObject)
          .then((data) => {
            console.info(`promise: doUpdate success, data = ${JSON.stringify(data)}`);
          })
          .catch((error: Error) => {
            if (throwObject.isThrow) {
              throw (error as Error);
            } else {
              console.error(`promise: doUpdate failed, ${JSON.stringify(error)}`);
            }
          });
      } catch (error) {
        console.error(`promise: doUpdate input arg invalid, ${JSON.stringify(error)}`);
      }
    }
    
    /* 结束密钥会话并进行相应的密钥操作,输出处理数据 */
    function finishSession(handle: number, huksOptions: huks.HuksOptions, throwObject: throwObject) {
      return new Promise<huks.HuksReturnResult>((resolve, reject) => {
        try {
          huks.finishSession(handle, huksOptions, (error, data) => {
            if (error) {
              reject(error);
            } else {
              resolve(data);
            }
          });
        } catch (error) {
          throwObject.isThrow = true;
          throw (error as Error);
        }
      });
    }
    
    /* 调用finishSession结束操作 */
    async function publicFinishFunc(handle: number, huksOptions: huks.HuksOptions) {
      console.info(`enter promise doFinish`);
      let throwObject: throwObject = { isThrow: false };
      try {
        await finishSession(handle, huksOptions, throwObject)
          .then((data) => {
            finishOutData = data.outData as Uint8Array;
            console.info(`promise: doFinish success, data = ${JSON.stringify(data)}`);
          })
          .catch((error: Error) => {
            if (throwObject.isThrow) {
              throw (error as Error);
            } else {
              console.error(`promise: doFinish failed, ${JSON.stringify(error)}`);
            }
          });
      } catch (error) {
        console.error(`promise: doFinish input arg invalid, ${JSON.stringify(error)}`);
      }
    }
    
    /* 导出密钥 */
    function exportKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) {
      return new Promise<huks.HuksReturnResult>((resolve, reject) => {
        try {
          huks.exportKeyItem(keyAlias, huksOptions, (error, data) => {
            if (error) {
              reject(error);
            } else {
              resolve(data);
            }
          });
        } catch (error) {
          throwObject.isThrow = true;
          throw (error as Error);
        }
      });
    }
    
    /* 调用exportKeyItem导出公钥操作 */
    async function publicExportKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) {
      console.info(`enter promise export`);
      let throwObject: throwObject = { isThrow: false };
      try {
        await exportKeyItem(keyAlias, huksOptions, throwObject)
          .then((data) => {
            console.info(`promise: exportKeyItem success, data = ${JSON.stringify(data)}`);
            exportKey = data.outData as Uint8Array;
          })
          .catch((error: Error) => {
            if (throwObject.isThrow) {
              throw (error as Error);
            } else {
              console.error(`promise: exportKeyItem failed, ${JSON.stringify(error)}`);
            }
          });
      } catch (error) {
        console.error(`promise: exportKeyItem input arg invalid, ${JSON.stringify(error)}`);
      }
    }
    
    /* 删除密钥操作 */
    function deleteKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) {
      return new Promise<void>((resolve, reject) => {
        try {
          huks.deleteKeyItem(keyAlias, huksOptions, (error, data) => {
            if (error) {
              reject(error);
            } else {
              resolve(data);
            }
          });
        } catch (error) {
          throwObject.isThrow = true;
          throw (error as Error);
        }
      });
    }
    
    /* 调用deleteKeyItem删除密钥操作 */
    async function publicDeleteKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) {
      console.info(`enter promise deleteKeyItem`);
      let throwObject: throwObject = { isThrow: false };
      try {
        await deleteKeyItem(keyAlias, huksOptions, throwObject)
          .then((data) => {
            console.info(`promise: deleteKeyItem key success, data = ${JSON.stringify(data)}`);
          })
          .catch((error: Error) => {
            if (throwObject.isThrow) {
              throw (error as Error);
            } else {
              console.error(`promise: deleteKeyItem failed, ${JSON.stringify(error)}`);
            }
          });
      } catch (error) {
        console.error(`promise: deleteKeyItem input arg invalid, ${JSON.stringify(error)}`);
      }
    }
    
    async function testAgree() {
      /* 1.确定密钥别名并集成并集成要参数集 A设备:srcKeyAliasFirst  B设备:srcKeyAliasSecond*/
      /* 2.设备A生成密钥 */
      await publicGenKeyFunc(srcKeyAliasFirst, HuksOptions);
      /* 3.设备B生成密钥 */
      await publicGenKeyFunc(srcKeyAliasSecond, HuksOptions);
      /* 4.设备A、B导出非对称密钥的公钥 */
      await publicExportKeyFunc(srcKeyAliasFirst, HuksOptions);
      exportKeyFirst = exportKey;
      await publicExportKeyFunc(srcKeyAliasSecond, HuksOptions);
      exportKeySecond = exportKey;
      /* 5.对第一个密钥进行协商(三段式)*/
      await publicInitFunc(srcKeyAliasFirst, HuksOptions);
      HuksOptions.inData = exportKeySecond;
      await publicUpdateFunc(handle, HuksOptions);
      await publicFinishFunc(handle, finishOptionsFirst);
      /* 5.对第二个密钥进行协商(三段式) */
      await publicInitFunc(srcKeyAliasSecond, HuksOptions);
      HuksOptions.inData = exportKeyFirst;
      await publicUpdateFunc(handle, HuksOptions);
      await publicFinishFunc(handle, finishOptionsSecond);
      /* 6.设备A、B删除密钥 */
      await publicDeleteKeyFunc(srcKeyAliasFirst, HuksOptions);
      await publicDeleteKeyFunc(srcKeyAliasSecond, HuksOptions);
    }
    
  • DH密钥协商用例

    /*
    *以下以 DH密钥的Promise操作使用为例
    */
    import { huks } from '@kit.UniversalKeystoreKit';
    
    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)
    }
    
    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
    }
    
    const dhAgree: Array<huks.HuksParam> = [{
      tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
      value: huks.HuksKeyAlg.HUKS_ALG_DH,
    }, {
      tag: huks.HuksTag.HUKS_TAG_PURPOSE,
      value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE,
    }]
    const dh2048Agree: Array<huks.HuksParam> = [
      ...dhAgree, {
      tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
      value: huks.HuksKeySize.HUKS_DH_KEY_SIZE_2048,
    }]
    const dhGenOptions: huks.HuksOptions = {
      properties: dh2048Agree,
      inData: new Uint8Array([])
    }
    const emptyOptions: huks.HuksOptions = {
      properties: [],
      inData: new Uint8Array([])
    }
    
    async function HuksDhAgreeExportKey(keyAlias: string,
      peerPubKey: huks.HuksReturnResult): Promise<huks.HuksReturnResult> {
      const initHandle = await huks.initSession(keyAlias, dhGenOptions)
      const dhAgreeUpdateBobPubKey: huks.HuksOptions = {
        properties: [
          ...dh2048Agree, {
          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, dhAgreeUpdateBobPubKey)
      return await huks.finishSession(initHandle.handle, emptyOptions)
    }
    
    async function HuksDhAgreeExportTest(
      aliasA: string, aliasB: string,
      pubKeyA: huks.HuksReturnResult, pubKeyB: huks.HuksReturnResult) {
    
      const agreedKeyFromAlice = await HuksDhAgreeExportKey(aliasA, pubKeyB)
      console.info(`ok! agreedKeyFromAlice export is 0x${Uint8ArrayToBigInt(agreedKeyFromAlice.outData).toString(16)}`)
    
      const agreedKeyFromBob = await HuksDhAgreeExportKey(aliasB, pubKeyA)
      console.info(`ok! agreedKeyFromBob export is 0x${Uint8ArrayToBigInt(agreedKeyFromBob.outData).toString(16)}`)
    }
    
    async function HuksDhAgreeInHuks(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,
      }, {
        tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
        value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
      }]
      const dhAgreeInit: huks.HuksOptions = {
        properties: [
          ...dhAgree,
          { tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256, },
          ...onlyUsedInHuks],
        inData: new Uint8Array([])
      }
      const dhAgreeFinishParams: 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_AES },
        { tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
        {
          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, dhAgreeInit)
      const dhAgreeUpdatePubKey: huks.HuksOptions = {
        properties: [...dhAgree, ...onlyUsedInHuks],
        inData: peerPubKey.outData
      }
      await huks.updateSession(handle.handle, dhAgreeUpdatePubKey)
      const dhAgreeAliceFinnish: huks.HuksOptions = {
        properties: [...dhAgreeFinishParams, {
          tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS, value: StringToUint8Array(aliasAgreedKey)
        }], inData: new Uint8Array([])
      }
      return await huks.finishSession(handle.handle, dhAgreeAliceFinnish)
    }
    
    async function HuksDhAgreeInHuksTest(
      aliasA: string, aliasB: string,
      pubKeyA: huks.HuksReturnResult, pubKeyB: huks.HuksReturnResult,
      aliasAgreedKeyFromA: string, aliasAgreedKeyFromB: string) {
    
      const finishAliceResult = await HuksDhAgreeInHuks(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 HuksDhAgreeInHuks(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)
    }
    
    export default async function HuksDhAgreeTest() {
      const aliasAlice = 'alice'
      const aliasBob = 'bob'
    
      /* 调用generateKeyItem生成别名为alice与bob的两个密钥 */
      await huks.generateKeyItem(aliasAlice, dhGenOptions)
      await huks.generateKeyItem(aliasBob, dhGenOptions)
    
      /* 导出非对称密钥alice与bob的的公钥 */
      const pubKeyAlice = await huks.exportKeyItem(aliasAlice, emptyOptions)
      const pubKeyBob = await huks.exportKeyItem(aliasBob, emptyOptions)
    
      /* 开始协商,协商生成的密钥返回给业务管理 */
      await HuksDhAgreeExportTest(aliasAlice, aliasBob, pubKeyAlice, pubKeyBob)
    
      /* 开始协商,协商生成的密钥由HUKS管理 */
      await HuksDhAgreeInHuksTest(aliasAlice, aliasBob, pubKeyAlice, pubKeyBob, 'agreedKeyFromAlice', 'agreedKeyFromBob')
    
      await huks.deleteKeyItem(aliasAlice, emptyOptions)
      await huks.deleteKeyItem(aliasBob, emptyOptions)
    }