• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 密钥协商(ArkTS)
2
3<!--Kit: Universal Keystore Kit-->
4<!--Subsystem: Security-->
5<!--Owner: @wutiantian-gitee-->
6<!--Designer: @HighLowWorld-->
7<!--Tester: @wxy1234564846-->
8<!--Adviser: @zengyawen-->
9
10以X25519和DH两个协商密钥类型为例,在密钥由HUKS管理的情况下,完成密钥协商。具体的场景介绍及支持的算法规格,请参考[密钥生成支持的算法](huks-key-generation-overview.md#支持的算法)。
11
12## 开发步骤
13
14**生成密钥**
15
16设备A、设备B各自生成一个非对称密钥,具体请参考[密钥生成](huks-key-generation-overview.md)或[密钥导入](huks-key-import-overview.md)。
17
18密钥生成时,可指定参数[HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG](../../reference/apis-universal-keystore-kit/capi-native-huks-type-h.md#oh_huks_keystoragetype)(可选),用于标识基于该密钥协商出的密钥是否由HUKS管理。
19
20- 当TAG设置为HUKS_STORAGE_ONLY_USED_IN_HUKS时,表示基于该密钥协商出的密钥,由HUKS管理,可保证协商密钥全生命周期不出安全环境。
21
22- 当TAG设置为HUKS_STORAGE_KEY_EXPORT_ALLOWED时,表示基于该密钥协商出的密钥,返回给调用方管理,由业务自行保证密钥安全。
23
24- 若业务未设置TAG的具体值,表示基于该密钥协商出的密钥,可由HUKS管理,也可返回给调用方管理,业务可在后续协商时再选择使用何种方式保护密钥。
25
26**导出密钥**
27
28设备A、B导出非对称密钥对的公钥材料,具体请参考[密钥导出](huks-export-key-arkts.md)。
29
30**密钥协商**
31
32设备A、B分别基于本端私钥和对端设备的公钥,协商出共享密钥。
33
34密钥协商时,可指定参数HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG(可选),用于标识协商得到的密钥是否由HUKS管理。
35
36| 生成 | 协商 | 规格 |
37| -------- | -------- | -------- |
38| HUKS_STORAGE_ONLY_USED_IN_HUKS | HUKS_STORAGE_ONLY_USED_IN_HUKS | 密钥由HUKS管理 |
39| HUKS_STORAGE_KEY_EXPORT_ALLOWED | HUKS_STORAGE_KEY_EXPORT_ALLOWED | 密钥返回给调用方管理 |
40| 未指定TAG具体值 | HUKS_STORAGE_ONLY_USED_IN_HUKS | 密钥由HUKS管理 |
41| 未指定TAG具体值 | HUKS_STORAGE_KEY_EXPORT_ALLOWED | 密钥返回给调用方管理 |
42| 未指定TAG具体值 | 未指定TAG具体值 | 密钥返回给调用方管理 |
43
44注:协商时指定的TAG值,不可与生成时指定的TAG值冲突。表格中仅列举有效的指定方式。
45
46**删除密钥**
47
48当密钥废弃不用时,设备A、B均需要删除密钥,具体请参考[密钥删除](huks-delete-key-arkts.md)。
49
50
51下面分别以X25519 与 DH密钥为例,进行协商。
52### X25519非对称密钥协商用例
53```ts
54/*
55 * 以下以X25519密钥的Promise操作使用为例
56 */
57import { huks } from '@kit.UniversalKeystoreKit';
58import { BusinessError } from "@kit.BasicServicesKit";
59
60function StringToUint8Array(str: string) {
61  let arr: number[] = new Array();
62  for (let i = 0, j = str.length; i < j; ++i) {
63    arr.push(str.charCodeAt(i));
64  }
65  return new Uint8Array(arr);
66}
67
68function Uint8ArrayToString(fileData: Uint8Array) {
69  let dataString = '';
70  for (let i = 0; i < fileData.length; i++) {
71    dataString += String.fromCharCode(fileData[i]);
72  }
73  return dataString;
74}
75
76/*
77 * 确定密钥别名和封装密钥属性参数集
78 */
79let srcKeyAliasFirst = "AgreeX25519KeyFirstAlias";
80let srcKeyAliasSecond = "AgreeX25519KeySecondAlias";
81let agreeX25519InData = 'AgreeX25519TestIndata';
82let finishOutData: Uint8Array;
83let handle: number;
84let exportKey: Uint8Array;
85let exportKeyFirst: Uint8Array;
86let exportKeySecond: Uint8Array;
87/* 集成生成密钥参数集 */
88let properties: Array<huks.HuksParam> = [{
89    tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
90    value: huks.HuksKeyAlg.HUKS_ALG_X25519,
91  }, {
92    tag: huks.HuksTag.HUKS_TAG_PURPOSE,
93    value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE,
94  }, {
95    tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
96    value: huks.HuksKeySize.HUKS_CURVE25519_KEY_SIZE_256,
97  }, {
98    tag: huks.HuksTag.HUKS_TAG_DIGEST,
99    value: huks.HuksKeyDigest.HUKS_DIGEST_NONE,
100  }, {
101    tag: huks.HuksTag.HUKS_TAG_PADDING,
102    value: huks.HuksKeyPadding.HUKS_PADDING_NONE,
103  }, {
104    tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
105    value: huks.HuksCipherMode.HUKS_MODE_CBC,
106  }, {
107    tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
108    value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
109  }
110];
111let HuksOptions: huks.HuksOptions = {
112  properties: properties,
113  inData: new Uint8Array(new Array())
114}
115/* 集成第一个协商参数集 */
116const finishProperties: Array<huks.HuksParam> = [{
117    tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
118    value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
119  }, {
120    tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS,
121    value: true
122  }, {
123    tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
124    value: huks.HuksKeyAlg.HUKS_ALG_AES,
125  }, {
126    tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
127    value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256,
128  }, {
129    tag: huks.HuksTag.HUKS_TAG_PURPOSE,
130    value:
131    huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT |
132    huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT,
133  }, {
134    tag: huks.HuksTag.HUKS_TAG_DIGEST,
135    value: huks.HuksKeyDigest.HUKS_DIGEST_NONE,
136  }, {
137    tag: huks.HuksTag.HUKS_TAG_PADDING,
138    value: huks.HuksKeyPadding.HUKS_PADDING_NONE,
139  }, {
140    tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
141    value: huks.HuksCipherMode.HUKS_MODE_ECB,
142  }
143];
144let finishOptionsFirst: huks.HuksOptions = {
145  properties: [
146    ...finishProperties, {
147    tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS,
148    value: StringToUint8Array(srcKeyAliasFirst + 'final'),
149  }],
150  inData: StringToUint8Array(agreeX25519InData)
151}
152/* 集成第二个协商参数集 */
153let finishOptionsSecond: huks.HuksOptions = {
154  properties: [
155    ...finishProperties, {
156    tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS,
157    value: StringToUint8Array(srcKeyAliasSecond + 'final'),
158  }],
159  inData: StringToUint8Array(agreeX25519InData)
160}
161
162/* 生成密钥 */
163async function generateKeyItem(keyAlias: string, huksOptions: huks.HuksOptions) {
164  console.info("promise: enter generateKeyItem");
165  try {
166    await huks.generateKeyItem(keyAlias, huksOptions)
167      .then(() => {
168        console.info(`promise: generateKeyItem success`);
169      }).catch((error: BusinessError) => {
170        console.error(`promise: generateKeyItem failed, errCode : ${error.code}, errMsg : ${error.message}`);
171      })
172  } catch (error) {
173    console.error(`promise: generateKeyItem input arg invalid`);
174  }
175}
176
177/* 初始化密钥会话接口,并获取一个句柄(必选)和挑战值(可选) */
178async function initSession(keyAlias: string, huksOptions: huks.HuksOptions) {
179  console.info("promise: enter initSession");
180  try {
181    await huks.initSession(keyAlias, huksOptions)
182      .then((data) => {
183        handle = data.handle;
184        console.info(`promise: initSession success`);
185      }).catch((error: BusinessError) => {
186        console.error(`promise: initSession failed, errCode : ${error.code}, errMsg : ${error.message}`);
187      })
188  } catch (error) {
189    console.error(`promise: initSession input arg invalid`);
190  }
191}
192
193/* 分段添加密钥操作的数据并进行相应的密钥操作,输出处理数据 */
194async function updateSession(handle: number, huksOptions: huks.HuksOptions) {
195  console.info("promise: enter updateSession");
196  try {
197    await huks.updateSession(handle, huksOptions)
198      .then((data) => {
199        console.info(`promise: updateSession success, data is ` + Uint8ArrayToString(data.outData as Uint8Array));
200      }).catch((error: BusinessError) => {
201        console.error(`promise: updateSession failed, errCode : ${error.code}, errMsg : ${error.message}`);
202      })
203  } catch (error) {
204    console.error(`promise: updateSession input arg invalid`);
205  }
206}
207
208/* 结束密钥会话并进行相应的密钥操作,输出处理数据 */
209async function finishSession(handle: number, huksOptions: huks.HuksOptions) {
210  console.info("promise: enter finishSession");
211  try {
212    await huks.finishSession(handle, huksOptions)
213      .then((data) => {
214        finishOutData = data.outData as Uint8Array;
215        console.info(`promise: finishSession success, data is ` + Uint8ArrayToString(data.outData as Uint8Array));
216      }).catch((error: BusinessError) => {
217        console.error(`promise: finishSession failed, errCode : ${error.code}, errMsg : ${error.message}`);
218      })
219  } catch (error) {
220    console.error(`promise: finishSession input arg invalid`);
221  }
222}
223
224/* 导出密钥 */
225async function exportKeyItem(keyAlias: string, huksOptions: huks.HuksOptions) {
226  console.info("promise: enter exportKeyItem");
227  try {
228    await huks.exportKeyItem(keyAlias, huksOptions)
229      .then((data) => {
230        exportKey = data.outData as Uint8Array;
231        console.info(`promise: exportKey success, data is ` + Uint8ArrayToString(data.outData as Uint8Array));
232      }).catch((error: BusinessError) => {
233        console.error(`promise: exportKeyItem failed, errCode : ${error.code}, errMsg : ${error.message}`);
234      })
235  } catch (error) {
236    console.error(`promise: exportKeyItem input arg invalid`);
237  }
238}
239
240/* 删除密钥操作 */
241async function deleteKeyItem(keyAlias: string, huksOptions: huks.HuksOptions) {
242  console.info("promise: enter deleteKeyItem");
243  try {
244    await huks.deleteKeyItem(keyAlias, huksOptions)
245      .then(() => {
246        console.info(`promise: deleteKeyItem success`);
247      }).catch((error: BusinessError) => {
248        console.error(`promise: deleteKeyItem failed, errCode : ${error.code}, errMsg : ${error.message}`);
249      })
250  } catch (error) {
251    console.error(`promise: deleteKeyItem input arg invalid`);
252  }
253}
254
255async function testAgree() {
256  /* 1.确定密钥别名并集成要参数集。A设备:srcKeyAliasFirst;B设备:srcKeyAliasSecond */
257  /* 2.设备A生成密钥 */
258  await generateKeyItem(srcKeyAliasFirst, HuksOptions);
259  /* 3.设备B生成密钥 */
260  await generateKeyItem(srcKeyAliasSecond, HuksOptions);
261  /* 4.设备A、B导出非对称密钥的公钥 */
262  await exportKeyItem(srcKeyAliasFirst, HuksOptions);
263  exportKeyFirst = exportKey;
264  await exportKeyItem(srcKeyAliasSecond, HuksOptions);
265  exportKeySecond = exportKey;
266  /* 5.对第一个密钥进行协商(三段式) */
267  await initSession(srcKeyAliasFirst, HuksOptions);
268  HuksOptions.inData = exportKeySecond;
269  await updateSession(handle, HuksOptions);
270  await finishSession(handle, finishOptionsFirst);
271  /* 6.对第二个密钥进行协商(三段式) */
272  await initSession(srcKeyAliasSecond, HuksOptions);
273  HuksOptions.inData = exportKeyFirst;
274  await updateSession(handle, HuksOptions);
275  await finishSession(handle, finishOptionsSecond);
276  /* 7.设备A、B删除密钥 */
277  await deleteKeyItem(srcKeyAliasFirst, HuksOptions);
278  await deleteKeyItem(srcKeyAliasSecond, HuksOptions);
279}
280```
281
282### DH密钥协商用例
283```ts
284/*
285 * 下面以DH密钥的Promise操作使用为例
286 */
287import { huks } from '@kit.UniversalKeystoreKit';
288
289function StringToUint8Array(str: string) {
290  let arr: number[] = []
291  for (let i = 0, j = str.length; i < j; ++i) {
292    arr.push(str.charCodeAt(i))
293  }
294  return new Uint8Array(arr)
295}
296
297function Uint8ArrayToBigInt(arr: Uint8Array): bigint {
298  let i = 0
299  const byteMax: bigint = BigInt('0x100')
300  let result: bigint = BigInt('0')
301  while (i < arr.length) {
302    result = result * byteMax
303    result = result + BigInt(arr[i])
304    i += 1
305  }
306  return result
307}
308
309const dhAgree: Array<huks.HuksParam> = [{
310  tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
311  value: huks.HuksKeyAlg.HUKS_ALG_DH,
312}, {
313  tag: huks.HuksTag.HUKS_TAG_PURPOSE,
314  value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE,
315}]
316const dh2048Agree: Array<huks.HuksParam> = [
317  ...dhAgree, {
318  tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
319  value: huks.HuksKeySize.HUKS_DH_KEY_SIZE_2048,
320}]
321const dhGenOptions: huks.HuksOptions = {
322  properties: dh2048Agree,
323  inData: new Uint8Array([])
324}
325const emptyOptions: huks.HuksOptions = {
326  properties: [],
327  inData: new Uint8Array([])
328}
329
330async function HuksDhAgreeExportKey(keyAlias: string,
331  peerPubKey: huks.HuksReturnResult): Promise<huks.HuksReturnResult> {
332  const initHandle = await huks.initSession(keyAlias, dhGenOptions)
333  const dhAgreeUpdateBobPubKey: huks.HuksOptions = {
334    properties: [
335      ...dh2048Agree, {
336      tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
337      value: huks.HuksKeyStorageType.HUKS_STORAGE_KEY_EXPORT_ALLOWED,
338    }],
339    inData: peerPubKey.outData
340  }
341  await huks.updateSession(initHandle.handle, dhAgreeUpdateBobPubKey)
342  return await huks.finishSession(initHandle.handle, emptyOptions)
343}
344
345async function HuksDhAgreeExportTest(
346  aliasA: string, aliasB: string,
347  pubKeyA: huks.HuksReturnResult, pubKeyB: huks.HuksReturnResult) {
348
349  const agreedKeyFromAlice = await HuksDhAgreeExportKey(aliasA, pubKeyB)
350  console.info(`ok! agreedKeyFromAlice export is 0x${Uint8ArrayToBigInt(agreedKeyFromAlice.outData).toString(16)}`)
351
352  const agreedKeyFromBob = await HuksDhAgreeExportKey(aliasB, pubKeyA)
353  console.info(`ok! agreedKeyFromBob export is 0x${Uint8ArrayToBigInt(agreedKeyFromBob.outData).toString(16)}`)
354}
355
356async function HuksDhAgreeInHuks(keyAlias: string, peerPubKey: huks.HuksReturnResult,
357  aliasAgreedKey: string): Promise<huks.HuksReturnResult> {
358  const onlyUsedInHuks: Array<huks.HuksParam> = [{
359    tag: huks.HuksTag.HUKS_TAG_KEY_STORAGE_FLAG,
360    value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
361  }, {
362    tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
363    value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
364  }]
365  const dhAgreeInit: huks.HuksOptions = {
366    properties: [
367      ...dhAgree,
368      { tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256, },
369      ...onlyUsedInHuks],
370    inData: new Uint8Array([])
371  }
372  const dhAgreeFinishParams: Array<huks.HuksParam> = [
373    ...onlyUsedInHuks,
374    { tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS, value: true },
375    { tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
376    { tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
377    {
378      tag: huks.HuksTag.HUKS_TAG_PURPOSE,
379      value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT
380    }
381  ]
382
383  const handle = await huks.initSession(keyAlias, dhAgreeInit)
384  const dhAgreeUpdatePubKey: huks.HuksOptions = {
385    properties: [...dhAgree, ...onlyUsedInHuks],
386    inData: peerPubKey.outData
387  }
388  await huks.updateSession(handle.handle, dhAgreeUpdatePubKey)
389  const dhAgreeAliceFinnish: huks.HuksOptions = {
390    properties: [...dhAgreeFinishParams, {
391      tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS, value: StringToUint8Array(aliasAgreedKey)
392    }], inData: new Uint8Array([])
393  }
394  return await huks.finishSession(handle.handle, dhAgreeAliceFinnish)
395}
396
397async function HuksDhAgreeInHuksTest(
398  aliasA: string, aliasB: string,
399  pubKeyA: huks.HuksReturnResult, pubKeyB: huks.HuksReturnResult,
400  aliasAgreedKeyFromA: string, aliasAgreedKeyFromB: string) {
401
402  const finishAliceResult = await HuksDhAgreeInHuks(aliasA, pubKeyB, aliasAgreedKeyFromA)
403  console.info(`ok! finishAliceResult in huks is 0x${Uint8ArrayToBigInt(finishAliceResult.outData).toString(16)}`)
404  const aliceAgreedExist = await huks.isKeyItemExist(aliasAgreedKeyFromA, emptyOptions)
405  console.info(`ok! aliceAgreedExist in huks is ${aliceAgreedExist}`)
406
407  const finishBobResult = await HuksDhAgreeInHuks(aliasB, pubKeyA, aliasAgreedKeyFromB)
408  console.info(`ok! finishBobResult in huks is 0x${Uint8ArrayToBigInt(finishBobResult.outData).toString(16)}`)
409  const bobAgreedExist = await huks.isKeyItemExist(aliasAgreedKeyFromB, emptyOptions)
410  console.info(`ok! bobAgreedExist in huks is ${bobAgreedExist}`)
411
412  await huks.deleteKeyItem(aliasAgreedKeyFromA, emptyOptions)
413  await huks.deleteKeyItem(aliasAgreedKeyFromB, emptyOptions)
414}
415
416async function HuksDhAgreeTest() {
417  const aliasAlice = 'alice'
418  const aliasBob = 'bob'
419
420  /* 调用generateKeyItem生成别名为alice与bob的两个密钥 */
421  await huks.generateKeyItem(aliasAlice, dhGenOptions)
422  await huks.generateKeyItem(aliasBob, dhGenOptions)
423
424  /* 导出非对称密钥alice与bob的公钥 */
425  const pubKeyAlice = await huks.exportKeyItem(aliasAlice, emptyOptions)
426  const pubKeyBob = await huks.exportKeyItem(aliasBob, emptyOptions)
427
428  /* 开始协商,协商生成的密钥返回给业务管理 */
429  await HuksDhAgreeExportTest(aliasAlice, aliasBob, pubKeyAlice, pubKeyBob)
430
431  /* 开始协商,协商生成的密钥由HUKS管理 */
432  await HuksDhAgreeInHuksTest(aliasAlice, aliasBob, pubKeyAlice, pubKeyBob, 'agreedKeyFromAlice', 'agreedKeyFromBob')
433
434  await huks.deleteKeyItem(aliasAlice, emptyOptions)
435  await huks.deleteKeyItem(aliasBob, emptyOptions)
436}
437```