已合并
分组密钥资料 #117244
lcy_lovebug创建于 2025年11月19日
分组密钥资料 #117244
已合并
lcy_lovebug创建于 2025年11月19日
29 个文件变更+1728-13
@@ -2934,6 +2934,7 @@ API version 11系统能力为SystemCapability.Security.Huks.Extension;从API v
2934| HUKS_TAG_ATTESTATION_ID_VERSION_INFO | HuksTagType.HUKS_TAG_TYPE_BYTES \| 515 | 表示attestation时的版本号。<br>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。<br> **系统能力:** SystemCapability.Security.Huks.Extension |2934| HUKS_TAG_ATTESTATION_ID_VERSION_INFO | HuksTagType.HUKS_TAG_TYPE_BYTES \| 515 | 表示attestation时的版本号。<br>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。<br> **系统能力:** SystemCapability.Security.Huks.Extension |
2935| HUKS_TAG_KEY_OVERRIDE<sup>20+</sup> | HuksTagType.HUKS_TAG_TYPE_BOOL \| 520 | 表示是否覆写同名密钥。<br>**原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。<br> **系统能力:** SystemCapability.Security.Huks.Core |2935| HUKS_TAG_KEY_OVERRIDE<sup>20+</sup> | HuksTagType.HUKS_TAG_TYPE_BOOL \| 520 | 表示是否覆写同名密钥。<br>**原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。<br> **系统能力:** SystemCapability.Security.Huks.Core |
2936| HUKS_TAG_AE_TAG_LEN<sup>22+</sup> | HuksTagType.HUKS_TAG_TYPE_UINT \| 521 | 表示指定的AEAD标签长度。<br>**原子化服务API:** 从API version 22开始,该接口支持在原子化服务中使用。<br> **系统能力:** SystemCapability.Security.Huks.Core |2936| HUKS_TAG_AE_TAG_LEN<sup>22+</sup> | HuksTagType.HUKS_TAG_TYPE_UINT \| 521 | 表示指定的AEAD标签长度。<br>**原子化服务API:** 从API version 22开始,该接口支持在原子化服务中使用。<br> **系统能力:** SystemCapability.Security.Huks.Core |
2937+| HUKS_TAG_KEY_ACCESS_GROUP<sup>23+</sup> | HuksTagType.HUKS_TAG_TYPE_BYTES \| 523 | 表示指定的分组信息。<br>**原子化服务API:** 从API version 23开始,该接口支持在原子化服务中使用。<br> **系统能力:** SystemCapability.Security.Huks.Extension |
2937| HUKS_TAG_IS_KEY_ALIAS | HuksTagType.HUKS_TAG_TYPE_BOOL \| 1001 | 表示是否使用生成key时传入的别名的Tag。<br>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。<br> **系统能力:** SystemCapability.Security.Huks.Core |2938| HUKS_TAG_IS_KEY_ALIAS | HuksTagType.HUKS_TAG_TYPE_BOOL \| 1001 | 表示是否使用生成key时传入的别名的Tag。<br>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。<br> **系统能力:** SystemCapability.Security.Huks.Core |
2938| HUKS_TAG_KEY_STORAGE_FLAG | HuksTagType.HUKS_TAG_TYPE_UINT \| 1002 | 表示密钥存储方式的Tag。<br>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。<br> **系统能力:** SystemCapability.Security.Huks.Core |2939| HUKS_TAG_KEY_STORAGE_FLAG | HuksTagType.HUKS_TAG_TYPE_UINT \| 1002 | 表示密钥存储方式的Tag。<br>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。<br> **系统能力:** SystemCapability.Security.Huks.Core |
2939| HUKS_TAG_IS_ALLOWED_WRAP | HuksTagType.HUKS_TAG_TYPE_BOOL \| 1003 | 预留。<br>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。<br> **系统能力:** SystemCapability.Security.Huks.Core<sup>12+</sup> <br>SystemCapability.Security.Huks.Extension<sup>8-11</sup>|2940| HUKS_TAG_IS_ALLOWED_WRAP | HuksTagType.HUKS_TAG_TYPE_BOOL \| 1003 | 预留。<br>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。<br> **系统能力:** SystemCapability.Security.Huks.Core<sup>12+</sup> <br>SystemCapability.Security.Huks.Extension<sup>8-11</sup>|
@@ -79,6 +79,11 @@
79 - 查询密钥别名集<!--huks-list-aliases-->79 - 查询密钥别名集<!--huks-list-aliases-->
80 - [查询密钥别名集(ArkTS)](huks-list-aliases-arkts.md)80 - [查询密钥别名集(ArkTS)](huks-list-aliases-arkts.md)
81 - [查询密钥别名集(C/C++)](huks-list-aliases-ndk.md)81 - [查询密钥别名集(C/C++)](huks-list-aliases-ndk.md)
82+ - 群组密钥<!--huks-group-key-->
83+ - [群组密钥介绍](huks-group-key-overview.md)
84+ - 开发指导<!--huks-group-key-dev-->
85+ - [群组密钥(ArkTS)](huks-group-key-arkts.md)
86+ - [群组密钥(C/C++)](huks-group-key-ndk.md)
82 <!--Del-->87 <!--Del-->
83 - [指定用户身份操作(仅对系统应用开放)](huks-as-user-sys.md)88 - [指定用户身份操作(仅对系统应用开放)](huks-as-user-sys.md)
84 <!--DelEnd-->89 <!--DelEnd-->
@@ -10,6 +10,7 @@
10多用户并发进行密钥操作时,为了实现密钥数据隔离和访问控制,HUKS提供了额外的可以指定用户进行密钥操作的接口。10多用户并发进行密钥操作时,为了实现密钥数据隔离和访问控制,HUKS提供了额外的可以指定用户进行密钥操作的接口。
11 11 
12>**说明:**12>**说明:**
13+>
13> 轻量级设备不支持指定用户身份操作功能。14> 轻量级设备不支持指定用户身份操作功能。
14 15 
15## 约束与限制16## 约束与限制
@@ -9,6 +9,8 @@
9 9 
10HUKS提供了接口供应用查询指定密钥是否存在。10HUKS提供了接口供应用查询指定密钥是否存在。
11 11 
12+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
13+ 
12## 开发步骤14## 开发步骤
13 15 
141. 指定密钥别名,密钥别名命名规范参考[密钥生成介绍及算法规格](huks-key-generation-overview.md)。161. 指定密钥别名,密钥别名命名规范参考[密钥生成介绍及算法规格](huks-key-generation-overview.md)。
@@ -9,10 +9,13 @@
9 9 
10HUKS提供了接口供应用查询指定密钥是否存在。10HUKS提供了接口供应用查询指定密钥是否存在。
11 11 
12+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
13+ 
12## 在CMake脚本中链接相关动态库14## 在CMake脚本中链接相关动态库
13```txt15```txt
14target_link_libraries(entry PUBLIC libhuks_ndk.z.so)16target_link_libraries(entry PUBLIC libhuks_ndk.z.so)
15```17```
18+ 
16## 开发步骤19## 开发步骤
17 20 
181. 指定密钥别名,密钥别名命名规范参考[密钥生成介绍及算法规格](huks-key-generation-overview.md)。211. 指定密钥别名,密钥别名命名规范参考[密钥生成介绍及算法规格](huks-key-generation-overview.md)。
@@ -9,6 +9,8 @@
9 9 
10为保证数据安全性,当不需要使用该密钥时,应该删除密钥。10为保证数据安全性,当不需要使用该密钥时,应该删除密钥。
11 11 
12+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
13+ 
12## 开发步骤14## 开发步骤
13 15 
14以删除HKDF256密钥为例。16以删除HKDF256密钥为例。
@@ -9,6 +9,8 @@
9 9 
10为保证数据安全性,当不需要使用该密钥时,应该删除密钥。10为保证数据安全性,当不需要使用该密钥时,应该删除密钥。
11 11 
12+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
13+ 
12## 在CMake脚本中链接相关动态库14## 在CMake脚本中链接相关动态库
13```txt15```txt
14target_link_libraries(entry PUBLIC libhuks_ndk.z.so)16target_link_libraries(entry PUBLIC libhuks_ndk.z.so)
@@ -9,6 +9,8 @@
9 9 
10在HUKS中已经有密钥,需要对一段数据加密或是解密,均可以使用HUKS完成加密/解密操作。10在HUKS中已经有密钥,需要对一段数据加密或是解密,均可以使用HUKS完成加密/解密操作。
11 11 
12+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
13+ 
12## 支持的算法14## 支持的算法
13 15 
14以下为密钥加密/解密支持的规格说明。16以下为密钥加密/解密支持的规格说明。
@@ -9,8 +9,11 @@
9 9 
10业务需要获取持久化存储的非对称密钥的公钥时使用,当前支持ECC/RSA/ED25519/X25519/SM2的公钥导出。10业务需要获取持久化存储的非对称密钥的公钥时使用,当前支持ECC/RSA/ED25519/X25519/SM2的公钥导出。
11>**说明:**11>**说明:**
12+>
12> <!--RP1-->轻量级设备<!--RP1End-->仅支持RSA公钥导出。13> <!--RP1-->轻量级设备<!--RP1End-->仅支持RSA公钥导出。
13 14 
15+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
16+ 
14## 开发步骤17## 开发步骤
15 18 
161. 指定密钥别名,密钥别名命名规范参考[密钥生成介绍及算法规格](huks-key-generation-overview.md)。191. 指定密钥别名,密钥别名命名规范参考[密钥生成介绍及算法规格](huks-key-generation-overview.md)。
@@ -10,8 +10,11 @@
10业务需要获取持久化存储的非对称密钥的公钥时使用,当前支持ECC/RSA/ED25519/X25519/SM2的公钥导出。10业务需要获取持久化存储的非对称密钥的公钥时使用,当前支持ECC/RSA/ED25519/X25519/SM2的公钥导出。
11 11 
12>**说明:**12>**说明:**
13+>
13> <!--RP1-->轻量级设备<!--RP1End-->仅支持RSA公钥导出。14> <!--RP1-->轻量级设备<!--RP1End-->仅支持RSA公钥导出。
14 15 
16+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
17+ 
15## 在CMake脚本中链接相关动态库18## 在CMake脚本中链接相关动态库
16```txt19```txt
17target_link_libraries(entry PUBLIC libhuks_ndk.z.so)20target_link_libraries(entry PUBLIC libhuks_ndk.z.so)
@@ -0,0 +1,807 @@
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+群组密钥支持的HUKS密钥操作及详细介绍参考[群组密钥介绍](huks-group-key-overview.md),本文档以[AES/CBC/NoPadding加解密](#aescbcnopadding加解密)、[X25519非对称密钥协商](#x25519非对称密钥协商)、[PBKDF2派生密钥](#pbkdf2派生密钥)为例展示群组密钥使用方法。
11+ 
12+**配置文件**
13+ 
14+使用群组密钥之前,需要在app.json5文件中配置群组信息,配置方法参考[配置文件示例](../../quick-start/app-configuration-file.md#配置文件示例)中assetAccessGroups字段的配置方式。
15+ 
16+## AES/CBC/NoPadding加解密
17+ 
18+### 开发步骤
19+ 
20+**生成密钥**
21+ 
22+1. 指定密钥别名,密钥别名命名规范参考[密钥生成介绍及算法规格](huks-key-generation-overview.md)。
23+ 
24+2. 初始化密钥属性集。需要添加群组密钥标签[HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit/js-apis-huks.md#hukstag)。
25+ 
26+3. 调用[generateKeyItem](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksgeneratekeyitem9)生成密钥,具体请参考[密钥生成](huks-key-generation-overview.md)。
27+ 
28+除此之外,开发者也可以参考[密钥导入](huks-key-import-overview.md),导入已有的密钥。
29+ 
30+**加密**
31+ 
32+1. 指定密钥别名。
33+ 
34+2. 指定待加密的数据。
35+ 
36+3. 指定加密[算法参数配置](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksparam)。需要添加群组密钥标签[HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit/js-apis-huks.md#hukstag)。
37+ 
38+4. 调用[initSession](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksinitsession9)初始化密钥会话,并获取会话的句柄handle。
39+ 
40+5. 调用[finishSession](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksfinishsession9)结束密钥会话,获取加密后的密文。
41+ 
42+**解密**
43+ 
44+1. 指定密钥别名。
45+ 
46+2. 指定待解密的密文。
x_huahua
x_huahuax_huahua2025年11月25日

加解密我看两个描述都差不多,只有这两处不一样。能否将加解密整成一个?就在第二点处写

指定待加密的数据或待解密的密文。

likedislike
x_huahua
x_huahua
2025年11月25日 评论:
47+ 
48+3. 指定解密[算法参数配置](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksparam)。需要添加群组密钥标签[HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit/js-apis-huks.md#hukstag)。
49+ 
50+4. 调用[initSession](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksinitsession9)初始化密钥会话,并获取会话的句柄handle。
51+ 
52+5. 调用[finishSession](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksfinishsession9)结束密钥会话,获取解密后的数据。
53+ 
54+**删除密钥**
55+ 
56+1. 指定密钥别名。
57+ 
58+2. 指定密钥删除[算法参数配置](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksparam)。需要添加群组密钥标签[HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit/js-apis-huks.md#hukstag)。
59+ 
60+3. 调用[deleteKeyItem](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksdeletekeyitem9)删除密钥,具体请参考[密钥删除](huks-delete-key-arkts.md)。
61+ 
62+### 开发示例
63+ 
64+```ts
x_huahua
x_huahuax_huahua2025年11月25日

这个整同源吗?整的话是下次重新提PR?

likedislike
65+/*
66+ * 以下以AES/CBC/NoPadding的Promise操作使用为例
67+ */
68+import { huks } from '@kit.UniversalKeystoreKit';
69+import { cryptoFramework } from '@kit.CryptoArchitectureKit';
70+import { BusinessError } from "@kit.BasicServicesKit";
71+ 
72+let aesKeyAlias = 'groupKey_test_aesKeyAlias';
73+let handle: number;
74+let plainText = '123456';
75+let IV = cryptoFramework.createRandom().generateRandomSync(12).data;
76+let cipherData: Uint8Array;
77+/*
78+ * 需要在app.json5中配置assetAccessGroups字段新增群组信息
79+ */
80+let group = 'ohos.test.groupKey';
81+ 
82+function StringToUint8Array(str: string) {
83+ let arr: number[] = new Array();
84+ for (let i = 0, j = str.length; i < j; ++i) {
85+ arr.push(str.charCodeAt(i));
86+ }
87+ return new Uint8Array(arr);
88+}
89+ 
90+function Uint8ArrayToString(fileData: Uint8Array) {
91+ let dataString = '';
92+ for (let i = 0; i < fileData.length; i++) {
93+ dataString += String.fromCharCode(fileData[i]);
94+ }
95+ return dataString;
96+}
97+ 
98+function GetAesGenerateProperties() {
99+ let properties: Array<huks.HuksParam> = [{
100+ tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
101+ value: huks.HuksKeyAlg.HUKS_ALG_AES
102+ }, {
103+ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
104+ value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_128
105+ }, {
106+ tag: huks.HuksTag.HUKS_TAG_PURPOSE,
107+ value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT
108+ }, {
109+ tag: huks.HuksTag.HUKS_TAG_KEY_ACCESS_GROUP,
110+ value: StringToUint8Array(group)
111+ }];
112+ return properties;
113+}
114+ 
115+function GetAesEncryptProperties() {
116+ let properties: Array<huks.HuksParam> = [{
117+ tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
118+ value: huks.HuksKeyAlg.HUKS_ALG_AES
119+ }, {
120+ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
121+ value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_128
122+ }, {
123+ tag: huks.HuksTag.HUKS_TAG_PURPOSE,
124+ value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT
125+ }, {
126+ tag: huks.HuksTag.HUKS_TAG_PADDING,
127+ value: huks.HuksKeyPadding.HUKS_PADDING_NONE
128+ }, {
129+ tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
130+ value: huks.HuksCipherMode.HUKS_MODE_CBC
131+ }, {
132+ tag: huks.HuksTag.HUKS_TAG_IV,
133+ value: IV
134+ }, {
135+ tag: huks.HuksTag.HUKS_TAG_KEY_ACCESS_GROUP,
136+ value: StringToUint8Array(group)
137+ }];
138+ return properties;
139+}
140+ 
141+function GetAesDecryptProperties() {
142+ let properties: Array<huks.HuksParam> = [{
143+ tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
144+ value: huks.HuksKeyAlg.HUKS_ALG_AES
145+ }, {
146+ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
147+ value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_128
148+ }, {
149+ tag: huks.HuksTag.HUKS_TAG_PURPOSE,
150+ value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT
151+ }, {
152+ tag: huks.HuksTag.HUKS_TAG_PADDING,
153+ value: huks.HuksKeyPadding.HUKS_PADDING_NONE
154+ }, {
155+ tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
156+ value: huks.HuksCipherMode.HUKS_MODE_CBC
157+ }, {
158+ tag: huks.HuksTag.HUKS_TAG_IV,
159+ value: IV
160+ }, {
161+ tag: huks.HuksTag.HUKS_TAG_KEY_ACCESS_GROUP,
162+ value: StringToUint8Array(group)
163+ }];
164+ return properties;
165+}
166+ 
167+async function GenerateAesKey() {
168+ /*
169+ * 模拟生成密钥场景
170+ * 1. 确定密钥别名
171+ */
172+ /*
173+ * 2. 获取生成密钥算法参数配置
174+ */
175+ let genProperties = GetAesGenerateProperties();
176+ let options: huks.HuksOptions = {
177+ properties: genProperties
178+ }
179+ /*
180+ * 3. 调用generateKeyItem
181+ */
182+ await huks.generateKeyItem(aesKeyAlias, options)
183+ .then(() => {
184+ console.info(`promise: generate AES Key success`);
185+ }).catch((error: BusinessError) => {
186+ console.error(`promise: generate AES Key failed, errCode: ${error.code}, errMsg: ${error.message}`);
187+ })
188+}
189+ 
190+async function EncryptData() {
191+ /*
192+ * 模拟加密场景
193+ * 1. 获取密钥别名
194+ */
195+ /*
196+ * 2. 获取待加密的数据
197+ */
198+ /*
199+ * 3. 获取加密算法参数配置
200+ */
201+ let encryptProperties = GetAesEncryptProperties();
202+ let options: huks.HuksOptions = {
203+ properties: encryptProperties,
204+ inData: StringToUint8Array(plainText)
205+ }
206+ /*
207+ * 4. 调用initSession获取handle
208+ */
209+ await huks.initSession(aesKeyAlias, options)
210+ .then((data) => {
211+ handle = data.handle;
212+ }).catch((error: BusinessError) => {
213+ console.error(`promise: init EncryptData failed, errCode: ${error.code}, errMsg: ${error.message}`);
214+ })
215+ /*
216+ * 5. 调用finishSession获取加密后的密文
217+ */
218+ await huks.finishSession(handle, options)
219+ .then((data) => {
220+ console.info(`promise: encrypt data success, data is ` + Uint8ArrayToString(data.outData as Uint8Array));
221+ cipherData = data.outData as Uint8Array;
222+ }).catch((error: BusinessError) => {
223+ console.error(`promise: encrypt data failed, errCode: ${error.code}, errMsg: ${error.message}`);
224+ })
225+}
226+ 
227+async function DecryptData() {
228+ /*
229+ * 模拟解密场景
230+ * 1. 获取密钥别名
231+ */
232+ /*
233+ * 2. 获取待解密的密文
234+ */
235+ /*
236+ * 3. 获取解密算法参数配置
237+ */
238+ let decryptOptions = GetAesDecryptProperties()
239+ let options: huks.HuksOptions = {
240+ properties: decryptOptions,
241+ inData: cipherData
242+ }
243+ /*
244+ * 4. 调用initSession获取handle
245+ */
246+ await huks.initSession(aesKeyAlias, options)
247+ .then((data) => {
248+ handle = data.handle;
249+ }).catch((error: BusinessError) => {
250+ console.error(`promise: init DecryptData failed, errCode: ${error.code}, errMsg: ${error.message}`);
251+ })
252+ /*
253+ * 5. 调用finishSession获取解密后的数据
254+ */
255+ await huks.finishSession(handle, options)
256+ .then((data) => {
257+ console.info(`promise: decrypt data success, data is ` + Uint8ArrayToString(data.outData as Uint8Array));
258+ }).catch((error: BusinessError) => {
259+ console.error(`promise: decrypt data failed, errCode: ${error.code}, errMsg: ${error.message}`);
260+ })
261+}
262+ 
263+async function DeleteKey() {
264+ /*
265+ * 模拟删除密钥场景
266+ * 1. 获取密钥别名
267+ */
268+ let emptyOptions: huks.HuksOptions = {
269+ properties: []
270+ }
271+ /*
272+ * 2. 调用deleteKeyItem删除密钥
273+ */
274+ await huks.deleteKeyItem(aesKeyAlias, emptyOptions)
275+ .then(() => {
276+ console.info(`promise: delete data success`);
277+ }).catch((error: BusinessError) => {
278+ console.error(`promise: delete data failed, errCode: ${error.code}, errMsg: ${error.message}`);
279+ })
280+}
281+ 
282+async function TestGroupKeyEncryptDecrypt() {
283+ await GenerateAesKey();
284+ await EncryptData();
285+ await DecryptData();
286+ await DeleteKey();
287+}
288+```
289+ 
290+## X25519非对称密钥协商
291+ 
292+### 开发步骤
293+ 
294+**生成密钥**
295+ 
296+设备A、设备B各自生成一个非对称密钥,具体请参考[密钥生成](huks-key-generation-overview.md)或[密钥导入](huks-key-import-overview.md)。
297+ 
298+密钥生成时,指定参数[HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit/js-apis-huks.md#hukstag),用于生成群组密钥。
299+ 
300+**导出密钥**
301+ 
302+设备A、B导出非对称密钥对的公钥材料,具体请参考[密钥导出](huks-export-key-arkts.md)。
303+ 
304+导出密钥时,指定参数[HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit/js-apis-huks.md#hukstag),用于导出群组密钥。
305+ 
306+**密钥协商**
307+ 
308+设备A、B分别基于本端私钥和对端设备的公钥,协商出共享密钥。
309+ 
310+密钥协商时,指定参数[HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit/js-apis-huks.md#hukstag),用于协商群组密钥。
311+ 
312+**删除密钥**
313+ 
314+当密钥废弃不用时,设备A、B均需要删除密钥,具体请参考[密钥删除](huks-delete-key-arkts.md)。
315+ 
316+删除密钥时,指定参数[HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit/js-apis-huks.md#hukstag),用于删除群组密钥。
317+ 
318+### 开发示例
319+ 
320+```ts
321+/*
322+ * 以下以X25519密钥的Promise操作使用为例
323+ * 通过群组密钥协商群组密钥
324+ */
325+import { huks } from '@kit.UniversalKeystoreKit';
326+import { BusinessError } from "@kit.BasicServicesKit";
327+ 
328+function StringToUint8Array(str: string) {
329+ let arr: number[] = new Array();
330+ for (let i = 0, j = str.length; i < j; ++i) {
331+ arr.push(str.charCodeAt(i));
332+ }
333+ return new Uint8Array(arr);
334+}
335+ 
336+function Uint8ArrayToString(fileData: Uint8Array) {
337+ let dataString = '';
338+ for (let i = 0; i < fileData.length; i++) {
339+ dataString += String.fromCharCode(fileData[i]);
340+ }
341+ return dataString;
342+}
343+ 
344+/*
345+ * 确定密钥别名和封装密钥属性参数集
346+ */
347+let srcKeyAliasFirst = "AgreeX25519KeyFirstAlias";
348+let srcKeyAliasSecond = "AgreeX25519KeySecondAlias";
349+let agreeX25519InData = 'AgreeX25519TestIndata';
350+let finishOutData: Uint8Array;
351+let handle: number;
352+let exportKey: Uint8Array;
353+let exportKeyFirst: Uint8Array;
354+let exportKeySecond: Uint8Array;
355+/*
356+ * 需要在app.json5中配置assetAccessGroups字段新增群组信息
357+ */
358+let group = 'ohos.test.groupKey';
359+/* 集成生成密钥参数集 */
360+let properties: Array<huks.HuksParam> = [{
361+ tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
362+ value: huks.HuksKeyAlg.HUKS_ALG_X25519,
363+ }, {
364+ tag: huks.HuksTag.HUKS_TAG_PURPOSE,
365+ value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE,
366+ }, {
367+ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
368+ value: huks.HuksKeySize.HUKS_CURVE25519_KEY_SIZE_256,
369+ }, {
370+ tag: huks.HuksTag.HUKS_TAG_DIGEST,
371+ value: huks.HuksKeyDigest.HUKS_DIGEST_NONE,
372+ }, {
373+ tag: huks.HuksTag.HUKS_TAG_PADDING,
374+ value: huks.HuksKeyPadding.HUKS_PADDING_NONE,
375+ }, {
376+ tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
377+ value: huks.HuksCipherMode.HUKS_MODE_CBC,
378+ }, {
379+ tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
380+ value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
381+ }, {
382+ tag: huks.HuksTag.HUKS_TAG_KEY_ACCESS_GROUP,
383+ value: StringToUint8Array(group)
384+ }
385+];
386+let HuksOptions: huks.HuksOptions = {
387+ properties: properties,
388+ inData: new Uint8Array(new Array())
389+}
390+const finishProperties: Array<huks.HuksParam> = [{
391+ tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
392+ value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
393+ }, {
394+ tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS,
395+ value: true
396+ }, {
397+ tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
398+ value: huks.HuksKeyAlg.HUKS_ALG_AES,
399+ }, {
400+ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
401+ value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256,
402+ }, {
403+ tag: huks.HuksTag.HUKS_TAG_PURPOSE,
404+ value:
405+ huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT |
406+ huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT,
407+ }, {
408+ tag: huks.HuksTag.HUKS_TAG_DIGEST,
409+ value: huks.HuksKeyDigest.HUKS_DIGEST_NONE,
410+ }, {
411+ tag: huks.HuksTag.HUKS_TAG_PADDING,
412+ value: huks.HuksKeyPadding.HUKS_PADDING_NONE,
413+ }, {
414+ tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
415+ value: huks.HuksCipherMode.HUKS_MODE_ECB,
416+ }, {
417+ tag: huks.HuksTag.HUKS_TAG_KEY_ACCESS_GROUP,
418+ value: StringToUint8Array(group)
419+ }
420+];
421+/* 集成第一个协商参数集 */
422+let finishOptionsFirst: huks.HuksOptions = {
423+ properties: [
424+ ...finishProperties, {
425+ tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS,
426+ value: StringToUint8Array(srcKeyAliasFirst + 'final'),
427+ }],
428+ inData: StringToUint8Array(agreeX25519InData)
429+}
430+/* 集成第二个协商参数集 */
431+let finishOptionsSecond: huks.HuksOptions = {
432+ properties: [
433+ ...finishProperties, {
434+ tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS,
435+ value: StringToUint8Array(srcKeyAliasSecond + 'final'),
436+ }],
437+ inData: StringToUint8Array(agreeX25519InData)
438+}
439+ 
440+/* 生成密钥 */
441+async function generateKeyItem(keyAlias: string, huksOptions: huks.HuksOptions) {
442+ console.info("promise: enter generateKeyItem");
443+ try {
444+ await huks.generateKeyItem(keyAlias, huksOptions)
445+ .then(() => {
446+ console.info(`promise: generateKeyItem success`);
447+ }).catch((error: BusinessError) => {
448+ console.error(`promise: generateKeyItem failed, errCode : ${error.code}, errMsg : ${error.message}`);
449+ })
450+ } catch (error) {
451+ console.error(`promise: generateKeyItem input arg invalid`);
452+ }
453+}
454+ 
455+/* 初始化密钥会话接口,并获取一个句柄(必选)和挑战值(可选) */
456+async function initSession(keyAlias: string, huksOptions: huks.HuksOptions) {
457+ console.info("promise: enter initSession");
458+ try {
459+ await huks.initSession(keyAlias, huksOptions)
460+ .then((data) => {
461+ handle = data.handle;
462+ console.info(`promise: initSession success`);
463+ }).catch((error: BusinessError) => {
464+ console.error(`promise: initSession failed, errCode : ${error.code}, errMsg : ${error.message}`);
465+ })
466+ } catch (error) {
467+ console.error(`promise: initSession input arg invalid`);
468+ }
469+}
470+ 
471+/* 分段添加密钥操作的数据并进行相应的密钥操作,输出处理数据 */
472+async function updateSession(handle: number, huksOptions: huks.HuksOptions) {
473+ console.info("promise: enter updateSession");
474+ try {
475+ await huks.updateSession(handle, huksOptions)
476+ .then((data) => {
477+ console.info(`promise: updateSession success, data is ` + Uint8ArrayToString(data.outData as Uint8Array));
478+ }).catch((error: BusinessError) => {
479+ console.error(`promise: updateSession failed, errCode : ${error.code}, errMsg : ${error.message}`);
480+ })
481+ } catch (error) {
482+ console.error(`promise: updateSession input arg invalid`);
483+ }
484+}
485+ 
486+/* 结束密钥会话并进行相应的密钥操作,输出处理数据 */
487+async function finishSession(handle: number, huksOptions: huks.HuksOptions) {
488+ console.info("promise: enter finishSession");
489+ try {
490+ await huks.finishSession(handle, huksOptions)
491+ .then((data) => {
492+ finishOutData = data.outData as Uint8Array;
493+ console.info(`promise: finishSession success, data is ` + Uint8ArrayToString(data.outData as Uint8Array));
494+ }).catch((error: BusinessError) => {
495+ console.error(`promise: finishSession failed, errCode : ${error.code}, errMsg : ${error.message}`);
496+ })
497+ } catch (error) {
498+ console.error(`promise: finishSession input arg invalid`);
499+ }
500+}
501+ 
502+/* 导出密钥 */
503+async function exportKeyItem(keyAlias: string, huksOptions: huks.HuksOptions) {
504+ console.info("promise: enter exportKeyItem");
505+ try {
506+ await huks.exportKeyItem(keyAlias, huksOptions)
507+ .then((data) => {
508+ exportKey = data.outData as Uint8Array;
509+ console.info(`promise: exportKey success, data is ` + Uint8ArrayToString(data.outData as Uint8Array));
510+ }).catch((error: BusinessError) => {
511+ console.error(`promise: exportKeyItem failed, errCode : ${error.code}, errMsg : ${error.message}`);
512+ })
513+ } catch (error) {
514+ console.error(`promise: exportKeyItem input arg invalid`);
515+ }
516+}
517+ 
518+/* 删除密钥操作 */
519+async function deleteKeyItem(keyAlias: string, huksOptions: huks.HuksOptions) {
520+ console.info("promise: enter deleteKeyItem");
521+ try {
522+ await huks.deleteKeyItem(keyAlias, huksOptions)
523+ .then(() => {
524+ console.info(`promise: deleteKeyItem success`);
525+ }).catch((error: BusinessError) => {
526+ console.error(`promise: deleteKeyItem failed, errCode : ${error.code}, errMsg : ${error.message}`);
527+ })
528+ } catch (error) {
529+ console.error(`promise: deleteKeyItem input arg invalid`);
530+ }
531+}
532+ 
533+async function testAgree() {
534+ /* 1.确定密钥别名并集成要参数集。A设备:srcKeyAliasFirst;B设备:srcKeyAliasSecond */
535+ /* 2.设备A生成密钥 */
536+ await generateKeyItem(srcKeyAliasFirst, HuksOptions);
537+ /* 3.设备B生成密钥 */
538+ await generateKeyItem(srcKeyAliasSecond, HuksOptions);
539+ /* 4.设备A、B导出非对称密钥的公钥 */
540+ await exportKeyItem(srcKeyAliasFirst, HuksOptions);
541+ exportKeyFirst = exportKey;
542+ await exportKeyItem(srcKeyAliasSecond, HuksOptions);
543+ exportKeySecond = exportKey;
544+ /* 5.对第一个密钥进行协商(三段式) */
545+ await initSession(srcKeyAliasFirst, HuksOptions);
546+ HuksOptions.inData = exportKeySecond;
547+ await updateSession(handle, HuksOptions);
548+ await finishSession(handle, finishOptionsFirst);
549+ /* 6.对第二个密钥进行协商(三段式) */
550+ await initSession(srcKeyAliasSecond, HuksOptions);
551+ HuksOptions.inData = exportKeyFirst;
552+ await updateSession(handle, HuksOptions);
553+ await finishSession(handle, finishOptionsSecond);
554+ /* 7.设备A、B删除密钥 */
555+ await deleteKeyItem(srcKeyAliasFirst, HuksOptions);
556+ await deleteKeyItem(srcKeyAliasSecond, HuksOptions);
557+}
558+```
559+ 
560+## PBKDF2派生密钥
561+ 
562+### 开发步骤
563+ 
564+**生成密钥**
565+ 
566+1. 指定密钥别名,密钥别名命名规范参考[密钥生成介绍及算法规格](huks-key-generation-overview.md)。
567+ 
568+2. 密钥生成时,指定参数[HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit/js-apis-huks.md#hukstag),用于生成群组密钥。
569+ 
570+3. 调用[generateKeyItem](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksgeneratekeyitem9)生成密钥,具体请参考[密钥生成](huks-key-generation-overview.md)。
571+ 
572+除此之外,开发者也可以参考[密钥导入](huks-key-import-overview.md),导入已有的密钥。
573+ 
574+**密钥派生**
575+ 
576+1. 获取密钥别名,指定对应的属性参数HuksOptions,添加参数[HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit/js-apis-huks.md#hukstag),用于派生群组密钥。
577+ 
578+2. 调用[initSession](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksinitsession9)初始化密钥会话,并获取会话的句柄handle。
579+ 
580+3. 调用[updateSession](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksupdatesession9)更新密钥会话。
581+ 
582+4. 调用[finishSession](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksfinishsession9)结束密钥会话,完成派生。
583+ 
584+**删除密钥**
585+ 
586+当密钥废弃不用时,需要调用[deleteKeyItem](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksdeletekeyitem9)删除密钥,具体请参考[密钥删除](huks-delete-key-arkts.md)。
587+ 
588+删除密钥时,指定参数[HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit/js-apis-huks.md#hukstag),用于删除群组密钥。
589+ 
590+### 开发示例
591+ 
592+```ts
593+/*
594+ * 以下以PBKDF2密钥的Promise操作使用为例
595+ * 使用群组密钥派生群组密钥
596+ */
597+import { huks } from '@kit.UniversalKeystoreKit';
598+import { BusinessError } from "@kit.BasicServicesKit";
599+ 
600+function StringToUint8Array(str: string) {
601+ let arr: number[] = new Array();
602+ for (let i = 0, j = str.length; i < j; ++i) {
603+ arr.push(str.charCodeAt(i));
604+ }
605+ return new Uint8Array(arr);
606+}
607+ 
608+function Uint8ArrayToString(fileData: Uint8Array) {
609+ let dataString = '';
610+ for (let i = 0; i < fileData.length; i++) {
611+ dataString += String.fromCharCode(fileData[i]);
612+ }
613+ return dataString;
614+}
615+ 
616+/*
617+ * 确定密钥别名和封装密钥属性参数集
618+ */
619+let srcKeyAlias = "pbkdf2_Key";
620+let salt = "mySalt";
621+let iterationCount = 10000;
622+let derivedKeySize = 32;
623+let handle: number;
624+let finishOutData: Uint8Array;
625+/*
626+ * 需要在app.json5中配置assetAccessGroups字段新增群组信息
627+ */
628+let group = 'ohos.test.groupKey';
629+ 
630+/* 集成生成密钥参数集 */
631+let properties: Array<huks.HuksParam> = [{
632+ tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
633+ value: huks.HuksKeyAlg.HUKS_ALG_AES,
634+ }, {
635+ tag: huks.HuksTag.HUKS_TAG_PURPOSE,
636+ value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DERIVE,
637+ }, {
638+ tag: huks.HuksTag.HUKS_TAG_DIGEST,
639+ value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256,
640+ }, {
641+ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
642+ value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256,
643+ }, {
644+ tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
645+ value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
646+ }, {
647+ tag: huks.HuksTag.HUKS_TAG_KEY_ACCESS_GROUP,
648+ value: StringToUint8Array(group)
649+ }
650+];
651+ 
652+let huksOptions: huks.HuksOptions = {
653+ properties: properties,
654+ inData: new Uint8Array(new Array())
655+}
656+ 
657+/* 集成init时密钥参数集 */
658+let initProperties: Array<huks.HuksParam> = [{
659+ tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
660+ value: huks.HuksKeyAlg.HUKS_ALG_PBKDF2,
661+ }, {
662+ tag: huks.HuksTag.HUKS_TAG_PURPOSE,
663+ value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DERIVE,
664+ }, {
665+ tag: huks.HuksTag.HUKS_TAG_DIGEST,
666+ value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256,
667+ }, {
668+ tag: huks.HuksTag.HUKS_TAG_DERIVE_KEY_SIZE,
669+ value: derivedKeySize,
670+ }, {
671+ tag: huks.HuksTag.HUKS_TAG_ITERATION,
672+ value: iterationCount,
673+ }, {
674+ tag: huks.HuksTag.HUKS_TAG_SALT,
675+ value: StringToUint8Array(salt),
676+ }, {
677+ tag: huks.HuksTag.HUKS_TAG_KEY_ACCESS_GROUP,
678+ value: StringToUint8Array(group)
679+ }
680+];
681+ 
682+let initOptions: huks.HuksOptions = {
683+ properties: initProperties,
684+ inData: new Uint8Array(new Array())
685+}
686+ 
687+/* 集成finish时密钥参数集 */
688+let finishProperties: Array<huks.HuksParam> = [{
689+ tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
690+ value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
691+ }, {
692+ tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS,
693+ value: true,
694+ }, {
695+ tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
696+ value: huks.HuksKeyAlg.HUKS_ALG_AES,
697+ }, {
698+ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
699+ value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256,
700+ }, {
701+ tag: huks.HuksTag.HUKS_TAG_PURPOSE,
702+ value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT,
703+ }, {
704+ tag: huks.HuksTag.HUKS_TAG_DIGEST,
705+ value: huks.HuksKeyDigest.HUKS_DIGEST_NONE,
706+ }, {
707+ tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS,
708+ value: StringToUint8Array(srcKeyAlias),
709+ }, {
710+ tag: huks.HuksTag.HUKS_TAG_PADDING,
711+ value: huks.HuksKeyPadding.HUKS_PADDING_NONE,
712+ }, {
713+ tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
714+ value: huks.HuksCipherMode.HUKS_MODE_ECB,
715+ }, {
716+ tag: huks.HuksTag.HUKS_TAG_KEY_ACCESS_GROUP,
717+ value: StringToUint8Array(group)
718+ }
719+];
720+ 
721+let finishOptions: huks.HuksOptions = {
722+ properties: finishProperties,
723+ inData: new Uint8Array(new Array())
724+}
725+ 
726+async function generateKeyItem(keyAlias: string, huksOptions: huks.HuksOptions) {
727+ console.info(`promise: enter generateKeyItem`);
728+ try {
729+ await huks.generateKeyItem(keyAlias, huksOptions)
730+ .then(() => {
731+ console.info(`promise: generateKeyItem success`);
732+ }).catch((error: BusinessError) => {
733+ console.error(`promise: generateKeyItem failed, errCode : ${error.code}, errMsg : ${error.message}`);
734+ })
735+ } catch (error) {
736+ console.error(`promise: generateKeyItem input arg invalid`);
737+ }
738+}
739+ 
740+async function initSession(keyAlias: string, huksOptions: huks.HuksOptions) {
741+ console.info(`promise: enter initSession`);
742+ try {
743+ await huks.initSession(keyAlias, huksOptions)
744+ .then((data) => {
745+ handle = data.handle;
746+ console.info(`promise: initSession success`);
747+ }).catch((error: BusinessError) => {
748+ console.error(`promise: initSession failed, errCode : ${error.code}, errMsg : ${error.message}`);
749+ })
750+ } catch (error) {
751+ console.error(`promise: initSession input arg invalid`);
752+ }
753+}
754+ 
755+async function updateSession(handle: number, huksOptions: huks.HuksOptions) {
756+ console.info(`promise: enter updateSession`);
757+ try {
758+ await huks.updateSession(handle, huksOptions)
759+ .then((data) => {
760+ let outData = data.outData as Uint8Array;
761+ console.info(`promise: updateSession success, data = ${Uint8ArrayToString(outData)}`);
762+ }).catch((error: BusinessError) => {
763+ console.error(`promise: updateSession failed, errCode : ${error.code}, errMsg : ${error.message}`);
764+ })
765+ } catch (error) {
766+ console.error(`promise: updateSession input arg invalid`);
767+ }
768+}
769+ 
770+async function finishSession(handle: number, huksOptions: huks.HuksOptions) {
771+ console.info(`promise: enter finishSession`);
772+ try {
773+ await huks.finishSession(handle, huksOptions)
774+ .then((data) => {
775+ let outData = data.outData as Uint8Array;
776+ console.info(`promise: finishSession success, data = ${Uint8ArrayToString(outData)}`);
777+ }).catch((error: BusinessError) => {
778+ console.error(`promise: finishSession failed, errCode : ${error.code}, errMsg : ${error.message}`);
779+ })
780+ } catch (error) {
781+ console.error(`promise: finishSession input arg invalid`);
782+ }
783+}
784+ 
785+async function deleteKeyItem(keyAlias: string, huksOptions: huks.HuksOptions) {
786+ console.info(`promise: enter deleteKeyItem`);
787+ try {
788+ await huks.deleteKeyItem(keyAlias, huksOptions)
789+ .then(() => {
790+ console.info(`promise: deleteKeyItem success`);
791+ }).catch((error: BusinessError) => {
792+ console.error(`promise: deleteKeyItem failed, errCode : ${error.code}, errMsg : ${error.message}`);
793+ })
794+ } catch (error) {
795+ console.error(`promise: deleteKeyItem input arg invalid`);
796+ }
797+}
798+async function testDerive() {
799+ /* 生成密钥 */
800+ await generateKeyItem(srcKeyAlias, huksOptions);
801+ /* 进行派生操作 */
802+ await initSession(srcKeyAlias, initOptions);
803+ await updateSession(handle, initOptions);
804+ await finishSession(handle, finishOptions);
805+ await deleteKeyItem(srcKeyAlias, huksOptions);
806+}
807+```
@@ -0,0 +1,805 @@
1+# 群组密钥(C/C++)
2+ 
3+<!--Kit: Universal Keystore Kit-->
4+<!--Subsystem: Security-->
5+<!--Owner: @wutiantian-gitee-->
6+<!--Designer: @HighLowWorld-->
7+<!--Tester: @wxy1234564846-->
8+<!--Adviser: @zengyawen-->
9+ 
10+群组密钥支持的HUKS密钥操作及详细介绍参考[群组密钥介绍](huks-group-key-overview.md),本文档以[AES/CBC/NoPadding加解密](#aescbcnopadding加解密)、[X25519非对称密钥协商](#x25519非对称密钥协商)、[PBKDF2派生密钥](#pbkdf2派生密钥)为例展示群组密钥使用方法。
11+ 
12+## 在CMake脚本中链接相关动态库
13+```txt
14+target_link_libraries(entry PUBLIC libhuks_ndk.z.so)
15+```
16+ 
17+**配置文件**
18+ 
19+使用群组密钥之前,需要在app.json5文件中配置群组信息,配置方法参考[配置文件示例](../../quick-start/app-configuration-file.md#配置文件示例)中assetAccessGroups字段的配置方式。
20+ 
21+## AES/CBC/NoPadding加解密
22+ 
23+### 开发步骤
24+ 
25+**生成密钥**
26+ 
27+1. 指定密钥别名,密钥别名命名规范参考[密钥生成介绍及算法规格](huks-key-generation-overview.md)。
28+ 
29+2. 初始化密钥属性集。需要添加群组密钥标签[OH_HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit//capi-native-huks-type-h.md#oh_huks_tag)。
30+ 
31+3. 调用[OH_Huks_GenerateKeyItem](../../reference/apis-universal-keystore-kit/capi-native-huks-api-h.md#oh_huks_generatekeyitem)生成密钥,具体请参考[密钥生成](huks-key-generation-overview.md)。
32+ 
33+除此之外,开发者也可以参考[密钥导入](huks-key-import-overview.md),导入已有的密钥。
34+ 
35+**加密**
36+ 
37+1. 指定密钥别名。
38+ 
39+2. 指定待加密的数据。
40+ 
41+3. 调用[OH_Huks_InitParamSet](../../reference/apis-universal-keystore-kit/capi-native-huks-param-h.md#oh_huks_initparamset)指定算法参数配置。需要添加群组密钥标签[OH_HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit//capi-native-huks-type-h.md#oh_huks_tag)。
42+ 
43+4. 调用[OH_Huks_InitSession](../../reference/apis-universal-keystore-kit/capi-native-huks-api-h.md#oh_huks_initsession)初始化密钥会话,并获取会话的句柄handle。
44+ 
45+5. 调用[OH_Huks_FinishSession](../../reference/apis-universal-keystore-kit/capi-native-huks-api-h.md#oh_huks_finishsession)结束密钥会话,获取加密后的密文。
46+ 
47+**解密**
48+ 
49+1. 指定密钥别名。
50+ 
51+2. 指定待解密的密文。
52+ 
53+3. 调用[OH_Huks_InitParamSet](../../reference/apis-universal-keystore-kit/capi-native-huks-param-h.md#oh_huks_initparamset)指定算法参数配置。需要添加群组密钥标签[OH_HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit//capi-native-huks-type-h.md#oh_huks_tag)。
54+ 
55+4. 调用[OH_Huks_InitSession](../../reference/apis-universal-keystore-kit/capi-native-huks-api-h.md#oh_huks_initsession)初始化密钥会话,并获取会话的句柄handle。
56+ 
57+5. 调用[OH_Huks_FinishSession](../../reference/apis-universal-keystore-kit/capi-native-huks-api-h.md#oh_huks_finishsession)结束密钥会话,获取解密后的数据。
58+ 
59+**删除密钥**
60+ 
61+1. 指定密钥别名。
62+ 
63+2. 调用[OH_Huks_InitParamSet](../../reference/apis-universal-keystore-kit/capi-native-huks-param-h.md#oh_huks_initparamset)指定算法参数配置。需要添加群组密钥标签[OH_HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit//capi-native-huks-type-h.md#oh_huks_tag)。
64+ 
65+3. 调用[OH_Huks_DeleteKeyItem](../../reference/apis-universal-keystore-kit/capi-native-huks-api-h.md#oh_huks_deletekeyitem)删除密钥,具体请参考[密钥删除](huks-delete-key-ndk.md)。
66+ 
67+当密钥废弃不用时,需要调用OH_Huks_DeleteKeyItem删除密钥,具体请参考[密钥删除](huks-delete-key-ndk.md)。
68+ 
69+### 开发示例
70+ 
71+```c++
72+#include "huks/native_huks_api.h"
73+#include "huks/native_huks_param.h"
74+#include "napi/native_api.h"
75+#include <string.h>
76+#include "CryptoArchitectureKit/crypto_architecture_kit.h"
77+ 
78+static OH_Crypto_ErrCode genRandomNumber(uint32_t randomLength, uint8_t *out)
79+{
80+ // 创建随机数生成器。
81+ OH_CryptoRand *rand = nullptr;
82+ OH_Crypto_ErrCode ret = OH_CryptoRand_Create(&rand);
83+ if (ret != CRYPTO_SUCCESS) {
84+ return ret;
85+ }
86+ Crypto_DataBlob blob = {out, randomLength};
87+ // 生成指定长度的随机数。
88+ ret = OH_CryptoRand_GenerateRandom(rand, randomLength, &blob);
89+ if (ret != CRYPTO_SUCCESS) {
90+ OH_CryptoRand_Destroy(rand);
91+ return ret;
92+ }
93+ OH_CryptoRand_Destroy(rand);
94+ 
95+ return CRYPTO_SUCCESS;
96+}
97+ 
98+OH_Huks_Result InitParamSet(struct OH_Huks_ParamSet **paramSet, const struct OH_Huks_Param *params, uint32_t paramCount)
99+{
100+ OH_Huks_Result ret = OH_Huks_InitParamSet(paramSet);
101+ if (ret.errorCode != OH_HUKS_SUCCESS) {
102+ return ret;
103+ }
104+ ret = OH_Huks_AddParams(*paramSet, params, paramCount);
105+ if (ret.errorCode != OH_HUKS_SUCCESS) {
106+ OH_Huks_FreeParamSet(paramSet);
107+ return ret;
108+ }
109+ ret = OH_Huks_BuildParamSet(paramSet);
110+ if (ret.errorCode != OH_HUKS_SUCCESS) {
111+ OH_Huks_FreeParamSet(paramSet);
112+ return ret;
113+ }
114+ return ret;
115+}
116+uint32_t OH_HUKS_TAG_KEY_ACCESS_GROUP = 5 << 28 | 523;
117+static const uint32_t IV_SIZE = 16;
118+static uint8_t IV[IV_SIZE] = { 0 };
119+static OH_Crypto_ErrCode ret = genRandomNumber(IV_SIZE, IV);
120+/*
121+ * 需要在app.json5中配置assetAccessGroups字段新增分组信息
122+ */
123+static char group[] = "ohos.test.group";
124+static struct OH_Huks_Param g_genEncDecParams[] = {
125+ {
126+ .tag = OH_HUKS_TAG_ALGORITHM,
127+ .uint32Param = OH_HUKS_ALG_AES
128+ }, {
129+ .tag = OH_HUKS_TAG_PURPOSE,
130+ .uint32Param = OH_HUKS_KEY_PURPOSE_ENCRYPT | OH_HUKS_KEY_PURPOSE_DECRYPT
131+ }, {
132+ .tag = OH_HUKS_TAG_KEY_SIZE,
133+ .uint32Param = OH_HUKS_AES_KEY_SIZE_256
134+ }, {
135+ .tag = OH_HUKS_TAG_PADDING,
136+ .uint32Param = OH_HUKS_PADDING_NONE
137+ }, {
138+ .tag = OH_HUKS_TAG_BLOCK_MODE,
139+ .uint32Param = OH_HUKS_MODE_CBC
140+ }, {
141+ .tag = OH_HUKS_TAG_KEY_ACCESS_GROUP,
142+ .blob = {
143+ .size = (uint32_t)strlen(group),
144+ .data = (uint8_t *)group
145+ }
146+ }
147+};
148+static struct OH_Huks_Param g_encryptParams[] = {
149+ {
150+ .tag = OH_HUKS_TAG_ALGORITHM,
151+ .uint32Param = OH_HUKS_ALG_AES
152+ }, {
153+ .tag = OH_HUKS_TAG_PURPOSE,
154+ .uint32Param = OH_HUKS_KEY_PURPOSE_ENCRYPT
155+ }, {
156+ .tag = OH_HUKS_TAG_KEY_SIZE,
157+ .uint32Param = OH_HUKS_AES_KEY_SIZE_256
158+ }, {
159+ .tag = OH_HUKS_TAG_PADDING,
160+ .uint32Param = OH_HUKS_PADDING_NONE
161+ }, {
162+ .tag = OH_HUKS_TAG_BLOCK_MODE,
163+ .uint32Param = OH_HUKS_MODE_CBC
164+ }, {
165+ .tag = OH_HUKS_TAG_IV,
166+ .blob = {
167+ .size = IV_SIZE,
168+ .data = (uint8_t *)IV
169+ }
170+ }, {
171+ .tag = OH_HUKS_TAG_KEY_ACCESS_GROUP,
172+ .blob = {
173+ .size = (uint32_t)strlen(group),
174+ .data = (uint8_t *)group
175+ }
176+ }
177+};
178+static struct OH_Huks_Param g_decryptParams[] = {
179+ {
180+ .tag = OH_HUKS_TAG_ALGORITHM,
181+ .uint32Param = OH_HUKS_ALG_AES
182+ }, {
183+ .tag = OH_HUKS_TAG_PURPOSE,
184+ .uint32Param = OH_HUKS_KEY_PURPOSE_DECRYPT
185+ }, {
186+ .tag = OH_HUKS_TAG_KEY_SIZE,
187+ .uint32Param = OH_HUKS_AES_KEY_SIZE_256
188+ }, {
189+ .tag = OH_HUKS_TAG_PADDING,
190+ .uint32Param = OH_HUKS_PADDING_NONE
191+ }, {
192+ .tag = OH_HUKS_TAG_BLOCK_MODE,
193+ .uint32Param = OH_HUKS_MODE_CBC
194+ }, {
195+ .tag = OH_HUKS_TAG_IV,
196+ .blob = {
197+ .size = IV_SIZE,
198+ .data = (uint8_t *)IV
199+ }
200+ }, {
201+ .tag = OH_HUKS_TAG_KEY_ACCESS_GROUP,
202+ .blob = {
203+ .size = (uint32_t)strlen(group),
204+ .data = (uint8_t *)group
205+ }
206+ }
207+};
208+static const uint32_t AES_COMMON_SIZE = 1024;
209+ 
210+OH_Huks_Result HksAesCipherTestEncrypt(
211+ const struct OH_Huks_Blob *keyAlias, const struct OH_Huks_ParamSet *encryptParamSet,
212+ const struct OH_Huks_Blob *inData, struct OH_Huks_Blob *cipherText)
213+{
214+ uint8_t handleE[sizeof(uint64_t)] = {0};
215+ struct OH_Huks_Blob handleEncrypt = {sizeof(uint64_t), handleE};
216+ OH_Huks_Result ret = OH_Huks_InitSession(keyAlias, encryptParamSet, &handleEncrypt, nullptr);
217+ if (ret.errorCode != OH_HUKS_SUCCESS) {
218+ return ret;
219+ }
220+ ret = OH_Huks_FinishSession(&handleEncrypt, encryptParamSet, inData, cipherText);
221+ return ret;
222+}
223+ 
224+OH_Huks_Result HksAesCipherTestDecrypt(const struct OH_Huks_Blob *keyAlias,
225+ const struct OH_Huks_ParamSet *decryptParamSet, const struct OH_Huks_Blob *cipherText,
226+ struct OH_Huks_Blob *plainText, const struct OH_Huks_Blob *inData)
227+{
228+ uint8_t handleD[sizeof(uint64_t)] = {0};
229+ struct OH_Huks_Blob handleDecrypt = {sizeof(uint64_t), handleD};
230+ OH_Huks_Result ret = OH_Huks_InitSession(keyAlias, decryptParamSet, &handleDecrypt, nullptr);
231+ if (ret.errorCode != OH_HUKS_SUCCESS) {
232+ return ret;
233+ }
234+ ret = OH_Huks_FinishSession(&handleDecrypt, decryptParamSet, cipherText, plainText);
235+ return ret;
236+}
237+ 
238+static napi_value EncDecKey(napi_env env, napi_callback_info info)
239+{
240+ char tmpKeyAlias[] = "test_enc_dec";
241+ struct OH_Huks_Blob keyAlias = { (uint32_t)strlen(tmpKeyAlias), (uint8_t *)tmpKeyAlias };
242+ struct OH_Huks_ParamSet *genParamSet = nullptr;
243+ struct OH_Huks_ParamSet *encryptParamSet = nullptr;
244+ struct OH_Huks_ParamSet *decryptParamSet = nullptr;
245+ OH_Huks_Result ohResult;
246+ do {
247+ /* 1. Generate Key */
248+ /*
249+ * 模拟生成密钥场景
250+ * 1.1. 确定密钥别名
251+ */
252+ /*
253+ * 1.2. 获取生成密钥算法参数配置
254+ */
255+ ohResult = InitParamSet(&genParamSet, g_genEncDecParams, sizeof(g_genEncDecParams) / sizeof(OH_Huks_Param));
256+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
257+ break;
258+ }
259+ /*
260+ * 1.3. 调用generateKeyItem
261+ */
262+ ohResult = OH_Huks_GenerateKeyItem(&keyAlias, genParamSet, nullptr);
263+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
264+ break;
265+ }
266+ /* 2. Encrypt */
267+ /*
268+ * 模拟加密场景
269+ * 2.1. 获取密钥别名
270+ */
271+ /*
272+ * 2.2. 获取待加密的数据
273+ */
274+ /*
275+ * 2.3. 获取加密算法参数配置
276+ */
277+ ohResult = InitParamSet(&encryptParamSet, g_encryptParams, sizeof(g_encryptParams) / sizeof(OH_Huks_Param));
278+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
279+ break;
280+ }
281+ char tmpInData[] = "AES_ECB_INDATA_1";
282+ struct OH_Huks_Blob inData = { (uint32_t)strlen(tmpInData), (uint8_t *)tmpInData };
283+ uint8_t cipher[AES_COMMON_SIZE] = {0};
284+ struct OH_Huks_Blob cipherText = {AES_COMMON_SIZE, cipher};
285+ /*
286+ * 2.4. 调用initSession获取handle
287+ */
288+ /*
289+ * 2.5. 调用finishSession获取加密后的密文
290+ */
291+ ohResult = HksAesCipherTestEncrypt(&keyAlias, encryptParamSet, &inData, &cipherText);
292+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
293+ break;
294+ }
295+ /* 3. Decrypt */
296+ /*
297+ * 模拟解密场景
298+ * 3.1. 获取密钥别名
299+ */
300+ /*
301+ * 3.2. 获取待解密的密文
302+ */
303+ /*
304+ * 3.3. 获取解密算法参数配置
305+ */
306+ ohResult = InitParamSet(&decryptParamSet, g_decryptParams, sizeof(g_decryptParams) / sizeof(OH_Huks_Param));
307+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
308+ break;
309+ }
310+ uint8_t plain[AES_COMMON_SIZE] = {0};
311+ struct OH_Huks_Blob plainText = {AES_COMMON_SIZE, plain};
312+ /*
313+ * 3.4. 调用initSession获取handle
314+ */
315+ /*
316+ * 3.5. 调用finishSession获取解密后的数据
317+ */
318+ ohResult = HksAesCipherTestDecrypt(&keyAlias, decryptParamSet, &cipherText, &plainText, &inData);
319+ } while (0);
320+ /* 4. Delete Key */
321+ /*
322+ * 模拟删除密钥场景
323+ * 4.1. 获取密钥别名
324+ */
325+ /*
326+ * 4.2. 调用deleteKeyItem删除密钥
327+ */
328+ (void)OH_Huks_DeleteKeyItem(&keyAlias, genParamSet);
329+
330+ OH_Huks_FreeParamSet(&genParamSet);
331+ OH_Huks_FreeParamSet(&encryptParamSet);
332+ OH_Huks_FreeParamSet(&decryptParamSet);
333+
334+ napi_value ret;
335+ napi_create_int32(env, ohResult.errorCode, &ret);
336+ return ret;
337+}
338+```
339+ 
340+## X25519非对称密钥协商
341+ 
342+### 开发步骤
343+ 
344+**生成密钥**
345+ 
346+设备A、设备B各自生成一个非对称密钥,具体请参考[密钥生成](huks-key-generation-overview.md)或[密钥导入](huks-key-import-overview.md)。
347+ 
348+密钥生成时,指定参数[OH_HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit//capi-native-huks-type-h.md#oh_huks_tag),用于生成群组密钥。
349+ 
350+**导出密钥**
351+ 
352+设备A、B导出非对称密钥对的公钥材料,具体请参考[密钥导出](huks-export-key-arkts.md)。
353+ 
354+导出密钥时,指定参数[OH_HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit//capi-native-huks-type-h.md#oh_huks_tag),用于导出群组密钥。
355+ 
356+**密钥协商**
357+ 
358+设备A、B分别基于本端私钥和对端设备的公钥,协商出共享密钥。
359+ 
360+密钥协商时,指定参数[OH_HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit//capi-native-huks-type-h.md#oh_huks_tag),用于协商群组密钥。
361+ 
362+**删除密钥**
363+ 
364+当密钥废弃不用时,设备A、B均需要删除密钥,具体请参考[密钥删除](huks-delete-key-arkts.md)。
365+ 
366+删除密钥时,指定参数[OH_HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit//capi-native-huks-type-h.md#oh_huks_tag),用于删除群组密钥。
367+ 
368+### 开发示例
369+ 
370+```c++
371+#include "huks/native_huks_api.h"
372+#include "huks/native_huks_param.h"
373+#include "napi/native_api.h"
374+#include <cstring>
375+ 
376+static struct OH_Huks_Blob g_group = {(uint32_t)strlen("ohos.test.group"), (uint8_t *)"ohos.test.group"};
377+/* 初始化参数 */
378+static OH_Huks_Result InitParamSet(struct OH_Huks_ParamSet **paramSet, const struct OH_Huks_Param *params,
379+ uint32_t paramCount)
380+{
381+ OH_Huks_Result ret = OH_Huks_InitParamSet(paramSet);
382+ if (ret.errorCode != OH_HUKS_SUCCESS) {
383+ return ret;
384+ }
385+ ret = OH_Huks_AddParams(*paramSet, params, paramCount);
386+ if (ret.errorCode != OH_HUKS_SUCCESS) {
387+ OH_Huks_FreeParamSet(paramSet);
388+ return ret;
389+ }
390+ ret = OH_Huks_BuildParamSet(paramSet);
391+ if (ret.errorCode != OH_HUKS_SUCCESS) {
392+ OH_Huks_FreeParamSet(paramSet);
393+ return ret;
394+ }
395+ return ret;
396+}
397+static struct OH_Huks_Blob g_keyAliasFinal1001 = {(uint32_t)strlen("HksECDHAgreeKeyAliasTest001_1_final"),
398+ (uint8_t *)"HksECDHAgreeKeyAliasTest001_1_final"};
399+/* 集成密钥参数集 */
400+static struct OH_Huks_Param g_genAgreeParams[] = {
401+ {.tag = OH_HUKS_TAG_ALGORITHM, .uint32Param = OH_HUKS_ALG_X25519},
402+ {.tag = OH_HUKS_TAG_PURPOSE, .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE},
403+ {.tag = OH_HUKS_TAG_KEY_SIZE, .uint32Param = OH_HUKS_CURVE25519_KEY_SIZE_256},
404+ {.tag = OH_HUKS_TAG_DIGEST, .uint32Param = OH_HUKS_DIGEST_NONE},
405+ {.tag = OH_HUKS_TAG_KEY_ACCESS_GROUP, .blob = g_group}
406+};
407+static struct OH_Huks_Param g_agreeParamsInit01[] = {
408+ {.tag = OH_HUKS_TAG_ALGORITHM, .uint32Param = OH_HUKS_ALG_X25519},
409+ {.tag = OH_HUKS_TAG_PURPOSE, .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE},
410+ {.tag = OH_HUKS_TAG_KEY_SIZE, .uint32Param = OH_HUKS_CURVE25519_KEY_SIZE_256},
411+ {.tag = OH_HUKS_TAG_DIGEST, .uint32Param = OH_HUKS_DIGEST_NONE},
412+ {.tag = OH_HUKS_TAG_KEY_ACCESS_GROUP, .blob = g_group}
413+};
414+static struct OH_Huks_Param g_agreeParamsFinish01[] = {
415+ {.tag = OH_HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG, .uint32Param = OH_HUKS_STORAGE_ONLY_USED_IN_HUKS},
416+ {.tag = OH_HUKS_TAG_ALGORITHM, .uint32Param = OH_HUKS_ALG_AES},
417+ {.tag = OH_HUKS_TAG_KEY_SIZE, .uint32Param = OH_HUKS_AES_KEY_SIZE_256},
418+ {.tag = OH_HUKS_TAG_PURPOSE, .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE},
419+ {.tag = OH_HUKS_TAG_KEY_ALIAS, .blob = g_keyAliasFinal1001},
420+ {.tag = OH_HUKS_TAG_PADDING, .uint32Param = OH_HUKS_PADDING_NONE},
421+ {.tag = OH_HUKS_TAG_BLOCK_MODE, .uint32Param = OH_HUKS_MODE_ECB},
422+ {.tag = OH_HUKS_TAG_DIGEST, .uint32Param = OH_HUKS_DIGEST_NONE},
423+ {.tag = OH_HUKS_TAG_KEY_ACCESS_GROUP, .blob = g_group}
424+};
425+static struct OH_Huks_Blob g_keyAliasFinal2001 = {(uint32_t)strlen("HksX25519AgreeKeyAliasTest001_2_final"),
426+ (uint8_t *)"HksX25519AgreeKeyAliasTest001_2_final"};
427+static struct OH_Huks_Param g_agreeParamsInit02[] = {
428+ {.tag = OH_HUKS_TAG_ALGORITHM, .uint32Param = OH_HUKS_ALG_X25519},
429+ {.tag = OH_HUKS_TAG_PURPOSE, .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE},
430+ {.tag = OH_HUKS_TAG_KEY_SIZE, .uint32Param = OH_HUKS_CURVE25519_KEY_SIZE_256},
431+ {.tag = OH_HUKS_TAG_DIGEST, .uint32Param = OH_HUKS_DIGEST_NONE},
432+ {.tag = OH_HUKS_TAG_KEY_ACCESS_GROUP, .blob = g_group}
433+};
434+static struct OH_Huks_Param g_agreeParamsFinish02[] = {
435+ {.tag = OH_HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG, .uint32Param = OH_HUKS_STORAGE_ONLY_USED_IN_HUKS},
436+ {.tag = OH_HUKS_TAG_ALGORITHM, .uint32Param = OH_HUKS_ALG_AES},
437+ {.tag = OH_HUKS_TAG_KEY_SIZE, .uint32Param = OH_HUKS_AES_KEY_SIZE_256},
438+ {.tag = OH_HUKS_TAG_PURPOSE, .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE},
439+ {.tag = OH_HUKS_TAG_KEY_ALIAS, .blob = g_keyAliasFinal2001},
440+ {.tag = OH_HUKS_TAG_PADDING, .uint32Param = OH_HUKS_PADDING_NONE},
441+ {.tag = OH_HUKS_TAG_BLOCK_MODE, .uint32Param = OH_HUKS_MODE_ECB},
442+ {.tag = OH_HUKS_TAG_DIGEST, .uint32Param = OH_HUKS_DIGEST_NONE},
443+ {.tag = OH_HUKS_TAG_KEY_ACCESS_GROUP, .blob = g_group}
444+};
445+static const uint32_t X25519_COMMON_SIZE = 256;
446+static struct OH_Huks_Blob g_keyAlias01001 = {(uint32_t)strlen("HksX25519AgreeKeyAliasTest001_1"),
447+ (uint8_t *)"HksX25519AgreeKeyAliasTest001_1"};
448+static struct OH_Huks_Blob g_keyAlias02001 = {(uint32_t)strlen("HksX25519AgreeKeyAliasTest001_2"),
449+ (uint8_t *)"HksX25519AgreeKeyAliasTest001_2"};
450+ 
451+static OH_Huks_Result MallocAndCheckBlobData(struct OH_Huks_Blob *blob, const uint32_t blobSize)
452+{
453+ struct OH_Huks_Result ret;
454+ ret.errorCode = OH_HUKS_SUCCESS;
455+ if (blobSize == 0 || blobSize > X25519_COMMON_SIZE) {
456+ ret.errorCode = OH_HUKS_ERR_CODE_INTERNAL_ERROR;
457+ return ret;
458+ }
459+ blob->data = (uint8_t *)malloc(blobSize);
460+ if (blob->data == NULL) {
461+ ret.errorCode = OH_HUKS_ERR_CODE_INTERNAL_ERROR;
462+ }
463+ return ret;
464+}
465+/* 导出密钥 */
466+OH_Huks_Result HksX25519AgreeExport(const struct OH_Huks_Blob *keyAlias1, const struct OH_Huks_Blob *keyAlias2,
467+ struct OH_Huks_Blob *publicKey1, struct OH_Huks_Blob *publicKey2,
468+ const struct OH_Huks_ParamSet *genParamSet)
469+{
470+ OH_Huks_Result ret = OH_Huks_ExportPublicKeyItem(keyAlias1, genParamSet, publicKey1);
471+ if (ret.errorCode != OH_HUKS_SUCCESS) {
472+ return ret;
473+ }
474+ ret = OH_Huks_ExportPublicKeyItem(keyAlias2, genParamSet, publicKey2);
475+ if (ret.errorCode != OH_HUKS_SUCCESS) {
476+ return ret;
477+ }
478+ return ret;
479+}
480+static const char *IN_DATA = "Hks_X25519_Agree_Test";
481+/* 协商密钥操作 */
482+OH_Huks_Result HksX25519AgreeFinish(const struct OH_Huks_Blob *keyAlias, const struct OH_Huks_Blob *publicKey,
483+ const struct OH_Huks_ParamSet *initParamSet,
484+ const struct OH_Huks_ParamSet *finishParamSet, struct OH_Huks_Blob *outData)
485+{
486+ struct OH_Huks_Blob inData = {(uint32_t)strlen(IN_DATA), (uint8_t *)IN_DATA};
487+ uint8_t handleU[sizeof(uint64_t)] = {0};
488+ struct OH_Huks_Blob handle = {sizeof(uint64_t), handleU};
489+ OH_Huks_Result ret = OH_Huks_InitSession(keyAlias, initParamSet, &handle, nullptr);
490+ if (ret.errorCode != OH_HUKS_SUCCESS) {
491+ return ret;
492+ }
493+ uint8_t outDataU[X25519_COMMON_SIZE] = {0};
494+ struct OH_Huks_Blob outDataUpdate = {X25519_COMMON_SIZE, outDataU};
495+ ret = OH_Huks_UpdateSession(&handle, initParamSet, publicKey, &outDataUpdate);
496+ if (ret.errorCode != OH_HUKS_SUCCESS) {
497+ return ret;
498+ }
499+ ret = OH_Huks_FinishSession(&handle, finishParamSet, &inData, outData);
500+ if (ret.errorCode != OH_HUKS_SUCCESS) {
501+ return ret;
502+ }
503+ return ret;
504+}
505+ 
506+static OH_Huks_Result InitializeAgreeParamSets(struct OH_Huks_ParamSet **genParamSet,
507+ struct OH_Huks_ParamSet **initParamSet01,
508+ struct OH_Huks_ParamSet **finishParamSet01,
509+ struct OH_Huks_ParamSet **initParamSet02,
510+ struct OH_Huks_ParamSet **finishParamSet02)
511+{
512+ OH_Huks_Result ohResult;
513+
514+ ohResult = InitParamSet(genParamSet, g_genAgreeParams,
515+ sizeof(g_genAgreeParams) / sizeof(OH_Huks_Param));
516+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
517+ return ohResult;
518+ }
519+ ohResult = InitParamSet(initParamSet01, g_agreeParamsInit01,
520+ sizeof(g_agreeParamsInit01) / sizeof(OH_Huks_Param));
521+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
522+ return ohResult;
523+ }
524+ ohResult = InitParamSet(finishParamSet01, g_agreeParamsFinish01,
525+ sizeof(g_agreeParamsFinish01) / sizeof(OH_Huks_Param));
526+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
527+ return ohResult;
528+ }
529+ ohResult = InitParamSet(initParamSet02, g_agreeParamsInit02,
530+ sizeof(g_agreeParamsInit02) / sizeof(OH_Huks_Param));
531+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
532+ return ohResult;
533+ }
534+ ohResult = InitParamSet(finishParamSet02, g_agreeParamsFinish02,
535+ sizeof(g_agreeParamsFinish02) / sizeof(OH_Huks_Param));
536+ return ohResult;
537+}
538+ 
539+static OH_Huks_Result GenerateKeyPair(struct OH_Huks_ParamSet *genParamSet)
540+{
541+ OH_Huks_Result ohResult;
542+
543+ /* 设备A生成密钥 */
544+ ohResult = OH_Huks_GenerateKeyItem(&g_keyAlias01001, genParamSet, nullptr);
545+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
546+ return ohResult;
547+ }
548+
549+ /* 设备B生成密钥 */
550+ ohResult = OH_Huks_GenerateKeyItem(&g_keyAlias02001, genParamSet, nullptr);
551+ return ohResult;
552+}
553+ 
554+static OH_Huks_Result KeyAgreement(struct OH_Huks_Blob *g_keyAlias,
555+ struct OH_Huks_Blob *publicKey,
556+ struct OH_Huks_Blob *outData,
557+ struct OH_Huks_ParamSet *initParamSet,
558+ struct OH_Huks_ParamSet *finishParamSet)
559+{
560+ OH_Huks_Result ohResult;
561+
562+ ohResult = MallocAndCheckBlobData(outData, outData->size);
563+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
564+ return ohResult;
565+ }
566+ /* 协商密钥 */
567+ ohResult = HksX25519AgreeFinish(g_keyAlias, publicKey, initParamSet, finishParamSet, outData);
568+ return ohResult;
569+}
570+ 
571+static void CleanKey(struct OH_Huks_Blob *genKeyAlias,
572+ struct OH_Huks_Blob *genKeyAliasFinal,
573+ struct OH_Huks_ParamSet *genParamSet,
574+ struct OH_Huks_ParamSet **initParamSet,
575+ struct OH_Huks_ParamSet **finishParamSet)
576+{
577+ OH_Huks_DeleteKeyItem(genKeyAlias, genParamSet);
578+ OH_Huks_DeleteKeyItem(genKeyAliasFinal, genParamSet);
579+ OH_Huks_FreeParamSet(initParamSet);
580+ OH_Huks_FreeParamSet(finishParamSet);
581+}
582+ 
583+/* 协商密钥整体流程 */
584+napi_value X25519AgreeKey(napi_env env, napi_callback_info info)
585+{
586+ struct OH_Huks_ParamSet *genParamSet = nullptr;
587+ struct OH_Huks_ParamSet *initParamSet01 = nullptr;
588+ struct OH_Huks_ParamSet *finishParamSet01 = nullptr;
589+ struct OH_Huks_ParamSet *initParamSet02 = nullptr;
590+ struct OH_Huks_ParamSet *finishParamSet02 = nullptr;
591+ struct OH_Huks_Blob publicKey01 = {.size = OH_HUKS_AES_KEY_SIZE_256, .data = nullptr};
592+ struct OH_Huks_Blob publicKey02 = {.size = OH_HUKS_AES_KEY_SIZE_256, .data = nullptr};
593+ struct OH_Huks_Blob outData01 = {.size = X25519_COMMON_SIZE, .data = nullptr};
594+ struct OH_Huks_Blob outData02 = {.size = X25519_COMMON_SIZE, .data = nullptr};
595+ OH_Huks_Result ohResult;
596+ do {
597+ /* 1.确定密钥别名集成密钥参数集 */
598+ ohResult = InitializeAgreeParamSets(&genParamSet, &initParamSet01, &finishParamSet01,
599+ &initParamSet02, &finishParamSet02);
600+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
601+ break;
602+ }
603+ /* 2.设备A和设备B生成密钥 */
604+ ohResult = GenerateKeyPair(genParamSet);
605+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
606+ break;
607+ }
608+ ohResult = MallocAndCheckBlobData(&publicKey01, publicKey01.size);
609+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
610+ break;
611+ }
612+ ohResult = MallocAndCheckBlobData(&publicKey02, publicKey02.size);
613+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
614+ break;
615+ }
616+ /* 3.设备A、B导出公钥 */
617+ ohResult = HksX25519AgreeExport(&g_keyAlias01001, &g_keyAlias02001, &publicKey01, &publicKey02, genParamSet);
618+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
619+ break;
620+ }
621+ /* 4.设备A、B执行密钥协商 */
622+ ohResult = KeyAgreement(&g_keyAlias01001, &publicKey02, &outData01, initParamSet01, finishParamSet01);
623+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
624+ break;
625+ }
626+ ohResult = KeyAgreement(&g_keyAlias02001, &publicKey01, &outData02, initParamSet02, finishParamSet02);
627+ } while (0);
628+ free(publicKey01.data);
629+ free(publicKey02.data);
630+ free(outData01.data);
631+ free(outData02.data);
632+ /* 5.设备A、B删除密钥 */
633+ CleanKey(&g_keyAlias01001, &g_keyAliasFinal1001, genParamSet, &initParamSet01, &finishParamSet01);
634+ CleanKey(&g_keyAlias02001, &g_keyAliasFinal2001, genParamSet, &initParamSet02, &finishParamSet02);
635+ OH_Huks_FreeParamSet(&genParamSet);
636+ 
637+ napi_value ret;
638+ napi_create_int32(env, ohResult.errorCode, &ret);
639+ return ret;
640+}
641+```
642+ 
643+## PBKDF2派生密钥
644+ 
645+### 开发步骤
646+ 
647+**生成密钥**
648+ 
649+1. 指定密钥别名,密钥别名命名规范参考[密钥生成介绍及算法规格](huks-key-generation-overview.md)。
650+ 
651+2. 密钥生成时,指定参数[OH_HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit//capi-native-huks-type-h.md#oh_huks_tag),用于生成群组密钥。
652+ 
653+3. 调用[generateKeyItem](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksgeneratekeyitem9)生成密钥,具体请参考[密钥生成](huks-key-generation-overview.md)。
654+ 
655+除此之外,开发者也可以参考[密钥导入](huks-key-import-overview.md),导入已有的密钥。
656+ 
657+**密钥派生**
658+ 
659+1. 获取密钥别名,指定对应的属性参数HuksOptions,添加参数[OH_HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit//capi-native-huks-type-h.md#oh_huks_tag),用于派生群组密钥。
660+ 
661+2. 调用[initSession](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksinitsession9)初始化密钥会话,并获取会话的句柄handle。
662+ 
663+3. 调用[updateSession](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksupdatesession9)更新密钥会话。
664+ 
665+4. 调用[finishSession](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksfinishsession9)结束密钥会话,完成派生。
666+ 
667+**删除密钥**
668+ 
669+当密钥废弃不用时,需要调用[deleteKeyItem](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksdeletekeyitem9)删除密钥,具体请参考[密钥删除](huks-delete-key-arkts.md)。
670+ 
671+删除密钥时,指定参数[OH_HUKS_TAG_KEY_ACCESS_GROUP](../../reference/apis-universal-keystore-kit//capi-native-huks-type-h.md#oh_huks_tag),用于删除群组密钥。
672+ 
673+### 开发示例
674+ 
675+```c++
676+#include "huks/native_huks_api.h"
677+#include "huks/native_huks_param.h"
678+#include "napi/native_api.h"
679+#include <cstring>
680+ 
681+OH_Huks_Result InitParamSet(struct OH_Huks_ParamSet **paramSet, const struct OH_Huks_Param *params,
682+ uint32_t paramCount)
683+{
684+ OH_Huks_Result ret = OH_Huks_InitParamSet(paramSet);
685+ if (ret.errorCode != OH_HUKS_SUCCESS) {
686+ return ret;
687+ }
688+ ret = OH_Huks_AddParams(*paramSet, params, paramCount);
689+ if (ret.errorCode != OH_HUKS_SUCCESS) {
690+ OH_Huks_FreeParamSet(paramSet);
691+ return ret;
692+ }
693+ ret = OH_Huks_BuildParamSet(paramSet);
694+ if (ret.errorCode != OH_HUKS_SUCCESS) {
695+ OH_Huks_FreeParamSet(paramSet);
696+ return ret;
697+ }
698+ return ret;
699+}
700+static const uint32_t DERIVE_KEY_SIZE_32 = 32;
701+static const uint32_t DERIVE_KEY_SIZE_256 = 256;
702+static const uint32_t DERIVE_KEY_ITERATION = 10000;
703+static const uint32_t SALT_SIZE = 8;
704+static const char DERIVE_KEY_SALT[SALT_SIZE] = "mysalt1";
705+static struct OH_Huks_Blob g_deriveKeyAlias = {(uint32_t)strlen("test_derive"), (uint8_t *)"test_derive"};
706+static struct OH_Huks_Blob g_group = {(uint32_t)strlen("ohos.test.group"), (uint8_t *)"ohos.test.group"};
707+static struct OH_Huks_Param g_genDeriveParams[] = {
708+ {.tag = OH_HUKS_TAG_ALGORITHM, .uint32Param = OH_HUKS_ALG_AES},
709+ {.tag = OH_HUKS_TAG_PURPOSE, .uint32Param = OH_HUKS_KEY_PURPOSE_DERIVE},
710+ {.tag = OH_HUKS_TAG_DIGEST, .uint32Param = OH_HUKS_DIGEST_SHA256},
711+ {.tag = OH_HUKS_TAG_KEY_SIZE, .uint32Param = OH_HUKS_AES_KEY_SIZE_256},
712+ {.tag = OH_HUKS_TAG_KEY_ACCESS_GROUP, .blob = g_group}
713+};
714+static struct OH_Huks_Param g_hkdfParams[] = {
715+ {.tag = OH_HUKS_TAG_ALGORITHM, .uint32Param = OH_HUKS_ALG_PBKDF2},
716+ {.tag = OH_HUKS_TAG_PURPOSE, .uint32Param = OH_HUKS_KEY_PURPOSE_DERIVE},
717+ {.tag = OH_HUKS_TAG_DIGEST, .uint32Param = OH_HUKS_DIGEST_SHA256},
718+ {.tag = OH_HUKS_TAG_DERIVE_KEY_SIZE, .uint32Param = DERIVE_KEY_SIZE_32},
719+ {.tag = OH_HUKS_TAG_ITERATION, .uint32Param = DERIVE_KEY_ITERATION},
720+ {.tag = OH_HUKS_TAG_SALT, .blob = {.size = SALT_SIZE, .data = (uint8_t *) DERIVE_KEY_SALT}},
721+ {.tag = OH_HUKS_TAG_KEY_ACCESS_GROUP, .blob = g_group}
722+};
723+static struct OH_Huks_Param g_hkdfFinishParams[] = {
724+ {.tag = OH_HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG, .uint32Param = OH_HUKS_STORAGE_ONLY_USED_IN_HUKS},
725+ {.tag = OH_HUKS_TAG_KEY_ALIAS, .blob = g_deriveKeyAlias},
726+ {.tag = OH_HUKS_TAG_ALGORITHM, .uint32Param = OH_HUKS_ALG_AES},
727+ {.tag = OH_HUKS_TAG_KEY_SIZE, .uint32Param = DERIVE_KEY_SIZE_256},
728+ {.tag = OH_HUKS_TAG_PURPOSE, .uint32Param = OH_HUKS_KEY_PURPOSE_DERIVE},
729+ {.tag = OH_HUKS_TAG_DIGEST, .uint32Param = OH_HUKS_DIGEST_NONE},
730+ {.tag = OH_HUKS_TAG_PADDING, .uint32Param = OH_HUKS_PADDING_NONE},
731+ {.tag = OH_HUKS_TAG_BLOCK_MODE, .uint32Param = OH_HUKS_MODE_ECB},
732+ {.tag = OH_HUKS_TAG_KEY_ACCESS_GROUP, .blob = g_group}
733+};
734+static const uint32_t COMMON_SIZE = 1024;
735+static const char *G_DERIVE_IN_DATA = "Hks_PBKDF2_Derive_Test_0_string";
736+static OH_Huks_Result PerformPbkdfDerivation(const struct OH_Huks_Blob *genAlias,
737+ struct OH_Huks_ParamSet *hkdfParamSet,
738+ struct OH_Huks_ParamSet *hkdfFinishParamSet,
739+ const struct OH_Huks_Blob &inData)
740+{
741+ OH_Huks_Result ohResult;
742+ // Init
743+ uint8_t handleD[sizeof(uint64_t)] = {0};
744+ struct OH_Huks_Blob handleDerive = {sizeof(uint64_t), handleD};
745+ ohResult = OH_Huks_InitSession(genAlias, hkdfParamSet, &handleDerive, nullptr);
746+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
747+ return ohResult;
748+ }
749+ // Update
750+ uint8_t tmpOut[COMMON_SIZE] = {0};
751+ struct OH_Huks_Blob outData = {COMMON_SIZE, tmpOut};
752+ ohResult = OH_Huks_UpdateSession(&handleDerive, hkdfParamSet, &inData, &outData);
753+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
754+ return ohResult;
755+ }
756+ // Finish
757+ uint8_t outDataD[COMMON_SIZE] = {0};
758+ struct OH_Huks_Blob outDataDerive = {COMMON_SIZE, outDataD};
759+ ohResult = OH_Huks_FinishSession(&handleDerive, hkdfFinishParamSet, &inData, &outDataDerive);
760+ return ohResult;
761+}
762+ 
763+napi_value PbkdfDeriveKey(napi_env env, napi_callback_info info)
764+{
765+ struct OH_Huks_Blob genAlias = {(uint32_t)strlen("test_signVerify"), (uint8_t *)"test_signVerify"};
766+ struct OH_Huks_Blob inData = {(uint32_t)strlen(G_DERIVE_IN_DATA), (uint8_t *)G_DERIVE_IN_DATA};
767+ struct OH_Huks_ParamSet *genParamSet = nullptr;
768+ struct OH_Huks_ParamSet *hkdfParamSet = nullptr;
769+ struct OH_Huks_ParamSet *hkdfFinishParamSet = nullptr;
770+ OH_Huks_Result ohResult;
771+ do {
772+ ohResult = InitParamSet(&genParamSet, g_genDeriveParams, sizeof(g_genDeriveParams) /
773+ sizeof(OH_Huks_Param));
774+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
775+ break;
776+ }
777+ ohResult = InitParamSet(&hkdfParamSet, g_hkdfParams, sizeof(g_hkdfParams) /
778+ sizeof(OH_Huks_Param));
779+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
780+ break;
781+ }
782+ ohResult =InitParamSet(&hkdfFinishParamSet, g_hkdfFinishParams, sizeof(g_hkdfFinishParams) /
783+ sizeof(OH_Huks_Param));
784+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
785+ break;
786+ }
787+ /* 1. 生成密钥 */
788+ ohResult = OH_Huks_GenerateKeyItem(&genAlias, genParamSet, nullptr);
789+ if (ohResult.errorCode != OH_HUKS_SUCCESS) {
790+ break;
791+ }
792+ /* 2. 派生密钥 */
793+ ohResult = PerformPbkdfDerivation(&genAlias, hkdfParamSet, hkdfFinishParamSet, inData);
794+ } while (0);
795+ (void)OH_Huks_DeleteKeyItem(&genAlias, genParamSet);
796+ (void)OH_Huks_DeleteKeyItem(&g_deriveKeyAlias, genParamSet);
797+ OH_Huks_FreeParamSet(&genParamSet);
798+ OH_Huks_FreeParamSet(&hkdfParamSet);
799+ OH_Huks_FreeParamSet(&hkdfFinishParamSet);
800+ 
801+ napi_value ret;
802+ napi_create_int32(env, ohResult.errorCode, &ret);
803+ return ret;
804+}
805+```
@@ -0,0 +1,35 @@
1+# 群组密钥介绍
2+ 
3+<!--Kit: Universal Keystore Kit-->
4+<!--Subsystem: Security-->
5+<!--Owner: @wutiantian-gitee-->
6+<!--Designer: @HighLowWorld-->
7+<!--Tester: @wxy1234564846-->
8+<!--Adviser: @zengyawen-->
9+ 
10+从API 23开始,HUKS支持群组密钥功能,该功能是针对同一开发者开发的多个HAP应用,提供的跨应用密钥共享能力。
11+ 
12+当多个HAP在配置中指定相同的组标识时,可共享同一组密钥资源,实现密钥在开发者自有应用生态内的安全复用,无需重复生成或手动传递密钥,简化跨应用加密场景的密钥管理流程。
13+ 
14+> **说明:**
15+>
16+> - 仅在<!--RP1-->标准设备<!--RP1End-->上支持群组密钥功能。
17+> - 群组密钥严格限定在同一开发者相同组的HAP范围内。不同开发者的相同组或者相同开发者的不同组,都无法相互访问对方的群组密钥,从而保障密钥的隔离性与安全性。
18+ 
lcy_lovebug
lcy_lovebuglcy_lovebug2025年11月24日

统一介绍规格说明,跳转到各个接口位置

likedislike
19+## 规格说明
20+| 支持的本地密钥操作 | API级别 | 说明 |
21+| ---- | ---- | ---- |
22+| [生成密钥](huks-key-generation-overview.md) | 23+ | 支持生成群组密钥。 |
23+| [导入密钥](huks-key-import-overview.md) | 23+ | 支持导入群组密钥。 |
24+| [加密/解密](huks-encryption-decryption-overview.md) | 23+ | 支持使用群组密钥进行加密/解密。 |
25+| [签名/验签](huks-signing-signature-verification-overview.md) | 23+ | 支持使用群组密钥进行签名/验签。 |
26+| [密钥协商](huks-key-agreement-overview.md) | 23+ | 支持使用群组密钥进行密钥协商。 |
27+| [密钥派生](huks-key-derivation-overview.md) | 23+ | 支持使用群组密钥进行密钥派生。 |
28+| [访问控制](huks-identity-authentication-overview.md) | 23+ | 支持使用群组密钥进行二次访问控制。 |
29+| [HMAC](huks-hmac-overview.md) | 23+ | 支持使用群组密钥进行HMAC。 |
30+| [密钥删除](huks-delete-key-arkts.md) | 23+ | 支持删除群组密钥。 |
31+| [密钥证明](huks-key-attestation-overview.md) | 23+ | 支持群组密钥的合法性证明。 |
32+| [查询密钥是否存在](huks-check-key-arkts.md) | 23+ | 支持查询群组密钥是否存在。 |
33+| [获取密钥属性](huks-obtain-key-properties-arkts.md) | 23+ | 支持查询群组密钥的属性。支持获取DeveloperID和GroupID信息。 |
34+| [密钥导出](huks-export-key-arkts.md) | 23+ | 支持导出群组密钥。 |
35+| [查询密钥别名集](huks-list-aliases-arkts.md) | 23+ | 支持查询群组密钥别名集。 |
@@ -9,6 +9,8 @@
9 9 
10MAC(Message Authentication Code)提供了一种在不可靠介质上检验传输或存储信息完整性的方法,HMAC是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code),是一种基于Hash函数和密钥进行消息认证的方法。HMAC可以与任何加密哈希函数(例如SHA256、SM3等)结合使用,HUKS支持了HMAC结合主流的摘要算法进行使用。10MAC(Message Authentication Code)提供了一种在不可靠介质上检验传输或存储信息完整性的方法,HMAC是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code),是一种基于Hash函数和密钥进行消息认证的方法。HMAC可以与任何加密哈希函数(例如SHA256、SM3等)结合使用,HUKS支持了HMAC结合主流的摘要算法进行使用。
11 11 
12+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
13+ 
12## 支持的算法14## 支持的算法
13 15 
14以下为HMAC支持的规格说明。16以下为HMAC支持的规格说明。
@@ -16,8 +16,11 @@ HUKS提供了完备的密钥访问控制能力,以保证存储在HUKS中的密
16- 支持严格限制密钥的使用用途,如支持只允许AES密钥进行加密解密,只允许RSA密钥进行签名验签。16- 支持严格限制密钥的使用用途,如支持只允许AES密钥进行加密解密,只允许RSA密钥进行签名验签。
17 17 
18> **说明:**18> **说明:**
19+>
19> <!--RP3-->轻量级设备<!--RP3End-->不支持用户身份认证访问控制功能。20> <!--RP3-->轻量级设备<!--RP3End-->不支持用户身份认证访问控制功能。
20 21 
22+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
23+ 
21## 使用场景及开发流程24## 使用场景及开发流程
22 25 
23整个用户身份认证访问控制,涉及多个环节,介绍如下。26整个用户身份认证访问控制,涉及多个环节,介绍如下。
@@ -12,8 +12,11 @@
12两台设备间进行密钥协商,双方各准备一个非对称密钥,并互换非对称密钥的公钥,以对端公钥与己端私钥协商出一个密钥,该密钥在两台设备相同。12两台设备间进行密钥协商,双方各准备一个非对称密钥,并互换非对称密钥的公钥,以对端公钥与己端私钥协商出一个密钥,该密钥在两台设备相同。
13 13 
14> **说明:**14> **说明:**
15-> - <!--RP1-->轻量级设备<!--RP1End-->不支持密钥协商功能。15+>
16-> - 使用现有密钥别名作为协商结果密钥别名会把现有密钥覆盖16+> * <!--RP1-->轻量级设备<!--RP1End-->不支持密钥协商功能
17+> * 使用现有密钥别名作为协商结果密钥别名会把现有密钥覆盖。
18+ 
19+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
17 20 
18## 支持的算法21## 支持的算法
19 22 
@@ -12,10 +12,13 @@ HUKS为密钥提供合法性证明能力,主要应用于非对称密钥的公
12基于PKI证书链技术,HUKS可以为存储在HUKS中的非对称密钥对的公钥签发证书,证明其公钥的合法性。业务可以通过系统提供的根CA证书,逐级验证HUKS签发的密钥证明证书,来确保证书中的公钥以及对应的私钥,确实来自合法的硬件设备,且存储管理在HUKS中。12基于PKI证书链技术,HUKS可以为存储在HUKS中的非对称密钥对的公钥签发证书,证明其公钥的合法性。业务可以通过系统提供的根CA证书,逐级验证HUKS签发的密钥证明证书,来确保证书中的公钥以及对应的私钥,确实来自合法的硬件设备,且存储管理在HUKS中。
13 13 
14> **说明:**14> **说明:**
15-> 1. 当调用方为系统服务且APL等级为normal时,暂不支持密钥证明,此种情况下,processName与APL字段将置空。15+>
16-> 2. 密钥证明功能在模拟器场景不支持16+> * 当调用方为系统服务且APL等级为normal时,暂不支持密钥证明,此种情况下,processName与APL字段将置空
17-> 3. <!--RP1-->轻量级设备<!--RP1End-->不支持密钥证明功能。17+> * 密钥证明功能在模拟器场景不支持
18-> 4. 支持生成密钥和导入密钥进行密钥证明,业务方在服务器侧需要通过业务证书中的密钥来源字段校验密钥来源是否符合预期18+> * <!--RP1-->轻量级设备<!--RP1End-->不支持密钥证明功能
19+> * 支持生成密钥和导入密钥进行密钥证明,业务方在服务器侧需要通过业务证书中的密钥来源字段校验密钥来源是否符合预期。
20+ 
21+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
19 22 
20密钥证明扩展域段为Asn.1 DER标准编码格式,数据结构定义如下:23密钥证明扩展域段为Asn.1 DER标准编码格式,数据结构定义如下:
21```24```
@@ -52,6 +55,7 @@ ApplicationIDType ::= SEQUENCE {
52 55 
53<!--Del-->56<!--Del-->
54> **说明:**57> **说明:**
58+>
55> OEM厂商可基于实际情况决定某些字段是否实现。59> OEM厂商可基于实际情况决定某些字段是否实现。
56<!--DelEnd-->60<!--DelEnd-->
57 61 
@@ -9,11 +9,14 @@
9 9 
10在密码学中,密钥派生函数(Key derivation function,KDF)使用伪随机函数从诸如主密码或密码的秘密值中派生出一个或多个密钥。10在密码学中,密钥派生函数(Key derivation function,KDF)使用伪随机函数从诸如主密码或密码的秘密值中派生出一个或多个密钥。
11 11 
12-> **说明:** 12+> **说明:**
13+>
13> * 在HUKS中只能通过HUKS托管的密钥进行密钥派生。 14> * 在HUKS中只能通过HUKS托管的密钥进行密钥派生。
14> * <!--RP2-->轻量级设备<!--RP2End-->不支持密钥派生功能。15> * <!--RP2-->轻量级设备<!--RP2End-->不支持密钥派生功能。
15> * 使用现有密钥别名作为派生结果密钥别名会把现有密钥覆盖。16> * 使用现有密钥别名作为派生结果密钥别名会把现有密钥覆盖。
16 17 
18+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
19+ 
17## 支持的算法20## 支持的算法
18 21 
19以下为密钥派生支持的规格说明。22以下为密钥派生支持的规格说明。
@@ -26,6 +29,7 @@
26派生密钥是业务基于三段式得到密钥会话结果,业务可决定派生密钥是否由HUKS管理(即密钥不出[TEE](huks-concepts.md))亦或是业务独立管理。29派生密钥是业务基于三段式得到密钥会话结果,业务可决定派生密钥是否由HUKS管理(即密钥不出[TEE](huks-concepts.md))亦或是业务独立管理。
27 30 
28> **说明:**31> **说明:**
32+>
29> PBKDF2/HKDF仅支持HUKS托管密钥的派生,不支持直接基于非HUKS托管的密钥进行派生,如:用户的口令,密钥托管参考[密钥导入](huks-key-import-overview.md)。33> PBKDF2/HKDF仅支持HUKS托管密钥的派生,不支持直接基于非HUKS托管的密钥进行派生,如:用户的口令,密钥托管参考[密钥导入](huks-key-import-overview.md)。
30 34 
31| 算法/摘要 | 派生密钥的算法/长度 | 派生结果密钥可用算法/长度 | API级别 | <!--DelCol5-->是否必选规格 |35| 算法/摘要 | 派生密钥的算法/长度 | 派生结果密钥可用算法/长度 | API级别 | <!--DelCol5-->是否必选规格 |
@@ -27,6 +27,7 @@
273. 调用[generateKeyItem](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksgeneratekeyitem9),传入密钥别名和密钥属性集,生成密钥。273. 调用[generateKeyItem](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksgeneratekeyitem9),传入密钥别名和密钥属性集,生成密钥。
28 28 
29> **说明:**29> **说明:**
30+>
30> 如果业务再次使用相同别名调用HUKS生成密钥,HUKS将生成新密钥并直接覆盖历史的密钥文件。31> 如果业务再次使用相同别名调用HUKS生成密钥,HUKS将生成新密钥并直接覆盖历史的密钥文件。
31 32 
32```ts33```ts
@@ -27,6 +27,7 @@ target_link_libraries(entry PUBLIC libhuks_ndk.z.so)
273. 调用[OH_Huks_GenerateKeyItem](../../reference/apis-universal-keystore-kit/capi-native-huks-api-h.md#oh_huks_generatekeyitem),传入密钥别名和密钥属性集,生成密钥。273. 调用[OH_Huks_GenerateKeyItem](../../reference/apis-universal-keystore-kit/capi-native-huks-api-h.md#oh_huks_generatekeyitem),传入密钥别名和密钥属性集,生成密钥。
28 28 
29> **说明:**29> **说明:**
30+>
30> 如果业务再次使用相同别名调用HUKS生成密钥,HUKS将生成新密钥并直接覆盖历史的密钥文件。31> 如果业务再次使用相同别名调用HUKS生成密钥,HUKS将生成新密钥并直接覆盖历史的密钥文件。
31 32 
32```c++33```c++
@@ -8,12 +8,14 @@
8<!--Adviser: @zengyawen-->8<!--Adviser: @zengyawen-->
9 9 
10当业务需要使用HUKS生成随机密钥,并由HUKS进行安全保存时,可以调用HUKS的接口生成密钥。10当业务需要使用HUKS生成随机密钥,并由HUKS进行安全保存时,可以调用HUKS的接口生成密钥。
11-> **注意:**11+> **说明:**
12>12>
13-> - 密钥别名长度最大为128字节。13+> * 密钥别名长度最大为128字节。
14-> - 密钥别名中禁止包含个人数据等敏感信息。不建议包含加密算法、密钥长度、加密模式等信息。14+> * 密钥别名中禁止包含个人数据等敏感信息。不建议包含加密算法、密钥长度、加密模式等信息。
15-> - 使用当前业务已有的密钥别名作为生成的密钥别名默认会把现有密钥覆盖,可以使用[HUKS_TAG_KEY_OVERRIDE](../../reference/apis-universal-keystore-kit/js-apis-huks.md#hukstag)指定当密钥别名冲突时返回错误。15+> * 使用当前业务已有的密钥别名作为生成的密钥别名默认会把现有密钥覆盖,可以使用[HUKS_TAG_KEY_OVERRIDE](../../reference/apis-universal-keystore-kit/js-apis-huks.md#hukstag)指定当密钥别名冲突时返回错误。
16-> - 对于不同业务生成的密钥将基于业务身份信息进行存储路径隔离,避免不同业务因密钥别名相同导致冲突。16+> * 对于不同业务生成的密钥将基于业务身份信息进行存储路径隔离,避免不同业务因密钥别名相同导致冲突。
17+ 
18+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
17 19 
18- 随机生成:指HUKS在生成密钥时,利用密码学安全的伪随机数,提高密钥的随机性、不可预测性以及不可重现性,确保生成的密钥难以被推测。20- 随机生成:指HUKS在生成密钥时,利用密码学安全的伪随机数,提高密钥的随机性、不可预测性以及不可重现性,确保生成的密钥难以被推测。
19 21 
@@ -61,6 +63,7 @@
61| 3DES | 128、192 | 18+ | 是 |63| 3DES | 128、192 | 18+ | 是 |
62 64 
63> **说明:**65> **说明:**
66+>
64> DH算法采用FFDHE知名安全素数群。67> DH算法采用FFDHE知名安全素数群。
65> DES和3DES算法仅提供给特定场景使用,其他场景下不推荐使用。68> DES和3DES算法仅提供给特定场景使用,其他场景下不推荐使用。
66 69 
@@ -10,9 +10,12 @@
10如果业务在HUKS外部生成密钥(比如应用间协商生成、服务器端生成),业务可以将密钥导入到HUKS中由HUKS进行管理。密钥一旦导入到HUKS中,在密钥的生命周期内,其明文仅在安全环境中进行访问操作,不会传递出安全环境。10如果业务在HUKS外部生成密钥(比如应用间协商生成、服务器端生成),业务可以将密钥导入到HUKS中由HUKS进行管理。密钥一旦导入到HUKS中,在密钥的生命周期内,其明文仅在安全环境中进行访问操作,不会传递出安全环境。
11 11 
12密钥导入的方式包含明文导入和加密导入两种方式。12密钥导入的方式包含明文导入和加密导入两种方式。
13-> **注意:**13+> **说明:**
14+>
14> 使用现有密钥别名作为导入的密钥别名会把现有密钥覆盖。15> 使用现有密钥别名作为导入的密钥别名会把现有密钥覆盖。
15 16 
17+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
18+ 
16## 明文导入19## 明文导入
17 20 
18该方式直接将密钥明文导入HUKS,在导入过程中密钥明文会暴露在非安全环境中,一般适用于<!--RP2-->轻量级设备<!--RP2End-->或低安业务。21该方式直接将密钥明文导入HUKS,在导入过程中密钥明文会暴露在非安全环境中,一般适用于<!--RP2-->轻量级设备<!--RP2End-->或低安业务。
@@ -21,6 +24,7 @@
21 24 
22- 不推荐使用该方式导入的密钥类型:对称密钥、非对称密钥对。25- 不推荐使用该方式导入的密钥类型:对称密钥、非对称密钥对。
23 > **说明:**26 > **说明:**
27+ >
24 > <!--RP2-->轻量级设备<!--RP2End-->只支持明文导入,不支持加密导入。28 > <!--RP2-->轻量级设备<!--RP2End-->只支持明文导入,不支持加密导入。
25 29 
26## 加密导入30## 加密导入
@@ -43,6 +47,7 @@
43导出密钥接口返回的[公钥明文材料是按照**X.509**格式封装](huks-concepts.md#公钥材料格式),导入加密密钥接口中的密钥材料需满足**Length<sub>Data</sub>-Data**的格式封装,形如:[(Length<sub>part1</sub>Data<sub>part1</sub>)……(Length<sub>partn</sub>Data<sub>partn</sub>)]。47导出密钥接口返回的[公钥明文材料是按照**X.509**格式封装](huks-concepts.md#公钥材料格式),导入加密密钥接口中的密钥材料需满足**Length<sub>Data</sub>-Data**的格式封装,形如:[(Length<sub>part1</sub>Data<sub>part1</sub>)……(Length<sub>partn</sub>Data<sub>partn</sub>)]。
44 48 
45> **说明:**49> **说明:**
50+>
46> 1. 加密导入密钥时,协商算法支持ECDH和X25519,协商后的Shared_Key使用AES-GCM算法加密Caller_Kek。对应算法套件定义见[HuksUnwrapSuite](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksunwrapsuite9)。51> 1. 加密导入密钥时,协商算法支持ECDH和X25519,协商后的Shared_Key使用AES-GCM算法加密Caller_Kek。对应算法套件定义见[HuksUnwrapSuite](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksunwrapsuite9)。
47> 2. 加密导入不支持X.509格式。52> 2. 加密导入不支持X.509格式。
48> 3. <!--RP2-->轻量级设备<!--RP2End-->只支持明文导入,不支持加密导入。53> 3. <!--RP2-->轻量级设备<!--RP2End-->只支持明文导入,不支持加密导入。
@@ -82,6 +87,7 @@
82<!--DelEnd-->87<!--DelEnd-->
83 88 
84> **说明:**89> **说明:**
90+>
85> 导入RSA密钥时,公钥必须大于或者等于65537。91> 导入RSA密钥时,公钥必须大于或者等于65537。
86 92 
87**<!--RP1-->标准设备<!--RP1End-->规格**93**<!--RP1-->标准设备<!--RP1End-->规格**
@@ -19,6 +19,8 @@
19 19 
20本章节提供了以上常用密钥操作的示例,这部分示例均没有设置二次身份访问控制,如设置了密钥访问控制请参考[密钥访问控制](huks-identity-authentication-overview.md)用法。20本章节提供了以上常用密钥操作的示例,这部分示例均没有设置二次身份访问控制,如设置了密钥访问控制请参考[密钥访问控制](huks-identity-authentication-overview.md)用法。
21 21 
22+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
23+ 
22## 通用开发流程24## 通用开发流程
23 25 
24HUKS基于密钥会话来操作数据,使用密钥时基于以下流程:26HUKS基于密钥会话来操作数据,使用密钥时基于以下流程:
@@ -10,8 +10,11 @@
10HUKS提供了接口供应用查询密钥别名集。10HUKS提供了接口供应用查询密钥别名集。
11 11 
12>**说明:**12>**说明:**
13+>
13> <!--RP1-->轻量级设备<!--RP1End-->不支持查询密钥别名集功能。14> <!--RP1-->轻量级设备<!--RP1End-->不支持查询密钥别名集功能。
14 15 
16+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
17+ 
15## 开发步骤18## 开发步骤
16 19 
171. 初始化密钥属性集,用于查询指定密钥别名集TAG。TAG仅支持[HUKS_TAG_AUTH_STORAGE_LEVEL](../../reference/apis-universal-keystore-kit/capi-native-huks-type-h.md#oh_huks_authstoragelevel)。201. 初始化密钥属性集,用于查询指定密钥别名集TAG。TAG仅支持[HUKS_TAG_AUTH_STORAGE_LEVEL](../../reference/apis-universal-keystore-kit/capi-native-huks-type-h.md#oh_huks_authstoragelevel)。
@@ -10,8 +10,11 @@
10HUKS提供了接口供应用查询密钥别名集。10HUKS提供了接口供应用查询密钥别名集。
11 11 
12>**说明:**12>**说明:**
13+>
13> <!--RP1-->轻量级设备<!--RP1End-->不支持查询密钥别名集功能。14> <!--RP1-->轻量级设备<!--RP1End-->不支持查询密钥别名集功能。
14 15 
16+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
17+ 
15## 在CMake脚本中链接相关动态库18## 在CMake脚本中链接相关动态库
16```txt19```txt
17target_link_libraries(entry PUBLIC libhuks_ndk.z.so)20target_link_libraries(entry PUBLIC libhuks_ndk.z.so)
@@ -9,8 +9,11 @@
9 9 
10HUKS提供了接口供业务获取指定密钥的相关属性。在获取指定密钥属性前,需要确保已在HUKS中生成或导入持久化存储的密钥。10HUKS提供了接口供业务获取指定密钥的相关属性。在获取指定密钥属性前,需要确保已在HUKS中生成或导入持久化存储的密钥。
11>**说明:**11>**说明:**
12+>
12> <!--RP1-->轻量级设备<!--RP1End-->不支持获取密钥属性功能。13> <!--RP1-->轻量级设备<!--RP1End-->不支持获取密钥属性功能。
13 14 
15+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
16+ 
14## 开发步骤17## 开发步骤
15 18 
161. 指定待查询的密钥别名keyAlias,密钥别名最大长度为128字节。191. 指定待查询的密钥别名keyAlias,密钥别名最大长度为128字节。
@@ -9,8 +9,11 @@
9 9 
10HUKS提供了接口供业务获取指定密钥的相关属性。在获取指定密钥属性前,需要确保已在HUKS中生成或导入持久化存储的密钥。10HUKS提供了接口供业务获取指定密钥的相关属性。在获取指定密钥属性前,需要确保已在HUKS中生成或导入持久化存储的密钥。
11>**说明:**11>**说明:**
12+>
12> 轻量级设备不支持获取密钥属性功能。13> 轻量级设备不支持获取密钥属性功能。
13 14 
15+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
16+ 
14## 在CMake脚本中链接相关动态库17## 在CMake脚本中链接相关动态库
15```txt18```txt
16target_link_libraries(entry PUBLIC libhuks_ndk.z.so)19target_link_libraries(entry PUBLIC libhuks_ndk.z.so)
@@ -14,6 +14,7 @@
14使用该功能仅需在密钥生成阶段,通过额外指定用于细粒度用户身份认证访问控制的HuksTag:HUKS_TAG_KEY_AUTH_PURPOSE,来指定在某种算法用途的情况下需要使用用户身份认证访问控制能力。14使用该功能仅需在密钥生成阶段,通过额外指定用于细粒度用户身份认证访问控制的HuksTag:HUKS_TAG_KEY_AUTH_PURPOSE,来指定在某种算法用途的情况下需要使用用户身份认证访问控制能力。
15 15 
16> **说明:**16> **说明:**
17+>
17> 对于对称加解密场景,仅AES/CBC、AES/GCM、SM4/CBC模式支持细粒度访问控制。18> 对于对称加解密场景,仅AES/CBC、AES/GCM、SM4/CBC模式支持细粒度访问控制。
18 19 
19## 开发步骤20## 开发步骤
@@ -9,6 +9,8 @@
9 9 
10为实现数据完整性保护和防抵赖,可使用生成/导入的密钥,对数据进行签名验签操作。10为实现数据完整性保护和防抵赖,可使用生成/导入的密钥,对数据进行签名验签操作。
11 11 
12+从API 23开始支持[群组密钥](huks-group-key-overview.md)特性。
13+ 
12## 支持的算法14## 支持的算法
13 15 
14以下为密钥签名/验签支持的规格说明。16以下为密钥签名/验签支持的规格说明。