1# 密钥协商(C/C++)
2
3
4以协商密钥类型为ECDH,并密钥仅在HUKS内使用为例,完成密钥协商。具体的场景介绍及支持的算法规格,请参考[密钥生成支持的算法](huks-key-generation-overview.md#支持的算法)。
5
6## 在CMake脚本中链接相关动态库
7```txt
8   target_link_libraries(entry PUBLIC libhuks_ndk.z.so)
9```
10
11## 开发步骤
12
13**生成密钥**
14
15设备A、设备B各自生成一个非对称密钥,具体请参考[密钥生成](huks-key-generation-overview.md)或[密钥导入](huks-key-import-overview.md)。
16
17密钥生成时,可指定参数,OH_HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG(可选),用于标识此步骤生成的密钥是否由HUKS管理。
18
19**导出密钥**
20
21设备A、B导出非对称密钥对的公钥材料,具体请参考[密钥导出](huks-export-key-arkts.md)。
22
23**密钥协商**
24
25设备A、B分别基于本端私钥和对端设备的公钥,协商出共享密钥。
26
27密钥协商时,可指定参数OH_HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG(可选),用于标识协商得到的密钥是否由HUKS管理。
28
29- 当TAG设置为OH_HUKS_STORAGE_ONLY_USED_IN_HUKS时,表示基于该密钥协商出的密钥,由HUKS管理,可保证协商密钥全生命周期不出安全环境。
30
31- 当TAG设置为OH_HUKS_STORAGE_KEY_EXPORT_ALLOWED时,表示基于该密钥协商出的密钥,返回给调用方管理,由业务自行保证密钥安全。
32
33- 若业务未设置TAG的具体值,表示基于该密钥协商出的密钥,既可由HUKS管理,也可返回给调用方管理,业务可在后续协商时再选择使用何种方式保护密钥。
34
35| 生成 | 协商 | 规格 |
36| -------- | -------- | -------- |
37| OH_HUKS_STORAGE_ONLY_USED_IN_HUKS | OH_HUKS_STORAGE_ONLY_USED_IN_HUKS | 密钥由HUKS管理 |
38| OH_HUKS_STORAGE_KEY_EXPORT_ALLOWED | OH_HUKS_STORAGE_KEY_EXPORT_ALLOWED | 密钥返回给调用方管理 |
39| 未指定TAG具体值 | OH_HUKS_STORAGE_ONLY_USED_IN_HUKS | 密钥由HUKS管理 |
40| 未指定TAG具体值 | OH_HUKS_STORAGE_KEY_EXPORT_ALLOWED | 密钥返回给调用方管理 |
41| 未指定TAG具体值 | 未指定TAG具体值 | 密钥返回给调用方管理 |
42
43注:协商时指定的TAG值,不可与生成时指定的TAG值冲突。表格中仅列举有效的指定方式。
44
45**删除密钥**
46
47当密钥废弃不用时,设备A、B均需要删除密钥,具体请参考[密钥删除](huks-delete-key-ndk.md)。
48
49```c++
50#include "huks/native_huks_api.h"
51#include "huks/native_huks_param.h"
52#include <string.h>
53/* 初始化参数 */
54OH_Huks_Result InitParamSet(
55    struct OH_Huks_ParamSet **paramSet,
56    const struct OH_Huks_Param *params,
57    uint32_t paramCount)
58{
59    OH_Huks_Result ret = OH_Huks_InitParamSet(paramSet);
60    if (ret.errorCode != OH_HUKS_SUCCESS) {
61        return ret;
62    }
63    ret = OH_Huks_AddParams(*paramSet, params, paramCount);
64    if (ret.errorCode != OH_HUKS_SUCCESS) {
65        OH_Huks_FreeParamSet(paramSet);
66        return ret;
67    }
68    ret = OH_Huks_BuildParamSet(paramSet);
69    if (ret.errorCode != OH_HUKS_SUCCESS) {
70        OH_Huks_FreeParamSet(paramSet);
71        return ret;
72    }
73    return ret;
74}
75static const uint32_t IV_SIZE = 16;
76static uint8_t IV[IV_SIZE] = { 0 }; // this is a test value, for real use the iv should be different every time
77static struct OH_Huks_Blob g_keyAliasFinal1001 = {
78    (uint32_t)strlen("HksECDHAgreeKeyAliasTest001_1_final"),
79    (uint8_t *)"HksECDHAgreeKeyAliasTest001_1_final"
80};
81/* 集成密钥参数集 */
82static struct OH_Huks_Param g_genAgreeParams[] = {
83    {
84        .tag = OH_HUKS_TAG_ALGORITHM,
85        .uint32Param = OH_HUKS_ALG_ECC
86    }, {
87        .tag = OH_HUKS_TAG_PURPOSE,
88        .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE
89    }, {
90        .tag = OH_HUKS_TAG_KEY_SIZE,
91        .uint32Param = OH_HUKS_ECC_KEY_SIZE_256
92    }, {
93        .tag = OH_HUKS_TAG_DIGEST,
94        .uint32Param = OH_HUKS_DIGEST_NONE
95    }
96};
97static struct OH_Huks_Param g_agreeParamsInit01[] = {
98    {
99        .tag = OH_HUKS_TAG_ALGORITHM,
100        .uint32Param = OH_HUKS_ALG_ECDH
101    }, {
102        .tag = OH_HUKS_TAG_PURPOSE,
103        .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE
104    }, {
105        .tag = OH_HUKS_TAG_KEY_SIZE,
106        .uint32Param = OH_HUKS_ECC_KEY_SIZE_256
107    }
108};
109static struct OH_Huks_Param g_agreeParamsFinish01[] = {
110    {
111        .tag = OH_HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
112        .uint32Param = OH_HUKS_STORAGE_ONLY_USED_IN_HUKS
113    }, {
114        .tag = OH_HUKS_TAG_ALGORITHM,
115        .uint32Param = OH_HUKS_ALG_AES
116    }, {
117        .tag = OH_HUKS_TAG_KEY_SIZE,
118        .uint32Param = OH_HUKS_AES_KEY_SIZE_256
119    }, {
120        .tag = OH_HUKS_TAG_PURPOSE,
121        .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE
122    }, {
123        .tag = OH_HUKS_TAG_KEY_ALIAS,
124        .blob = g_keyAliasFinal1001
125    }, {
126        .tag = OH_HUKS_TAG_PADDING,
127        .uint32Param = OH_HUKS_PADDING_NONE
128    }, {
129        .tag = OH_HUKS_TAG_BLOCK_MODE,
130        .uint32Param = OH_HUKS_MODE_CBC
131    }
132};
133static struct OH_Huks_Blob g_keyAliasFinal2001 = {
134    (uint32_t)strlen("HksECDHAgreeKeyAliasTest001_2_final"),
135    (uint8_t *)"HksECDHAgreeKeyAliasTest001_2_final"
136};
137static struct OH_Huks_Param g_agreeParamsInit02[] = {
138    {
139        .tag = OH_HUKS_TAG_ALGORITHM,
140        .uint32Param = OH_HUKS_ALG_ECDH
141    }, {
142        .tag = OH_HUKS_TAG_PURPOSE,
143        .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE
144    }, {
145        .tag = OH_HUKS_TAG_KEY_SIZE,
146        .uint32Param = OH_HUKS_ECC_KEY_SIZE_256
147    }
148};
149static struct OH_Huks_Param g_agreeParamsFinish02[] = {
150    {
151        .tag = OH_HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
152        .uint32Param = OH_HUKS_STORAGE_ONLY_USED_IN_HUKS
153    }, {
154        .tag = OH_HUKS_TAG_ALGORITHM,
155        .uint32Param = OH_HUKS_ALG_AES
156    }, {
157        .tag = OH_HUKS_TAG_KEY_SIZE,
158        .uint32Param = OH_HUKS_AES_KEY_SIZE_256
159    }, {
160        .tag = OH_HUKS_TAG_PURPOSE,
161        .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE
162    }, {
163        .tag = OH_HUKS_TAG_KEY_ALIAS,
164        .blob = g_keyAliasFinal2001
165    }, {
166        .tag = OH_HUKS_TAG_PADDING,
167        .uint32Param = OH_HUKS_PADDING_NONE
168    }, {
169        .tag = OH_HUKS_TAG_BLOCK_MODE,
170        .uint32Param = OH_HUKS_MODE_CBC
171    }
172};
173static const uint32_t ECDH_COMMON_SIZE = 1024;
174static struct OH_Huks_Blob g_keyAlias01001 = {
175    (uint32_t)strlen("HksECDHAgreeKeyAliasTest001_1"),
176    (uint8_t *)"HksECDHAgreeKeyAliasTest001_1"
177};
178static struct OH_Huks_Blob g_keyAlias02001 = {
179    (uint32_t)strlen("HksECDHAgreeKeyAliasTest001_2"),
180    (uint8_t *)"HksECDHAgreeKeyAliasTest001_2"
181};
182OH_Huks_Result MallocAndCheckBlobData(
183    struct OH_Huks_Blob *blob,
184    const uint32_t blobSize)
185{
186    struct OH_Huks_Result ret;
187    ret.errorCode = OH_HUKS_SUCCESS;
188    blob->data = (uint8_t *)malloc(blobSize);
189    if (blob->data == NULL) {
190        ret.errorCode = OH_HUKS_ERR_CODE_INTERNAL_ERROR;
191    }
192    return ret;
193}
194/* 导出密钥 */
195OH_Huks_Result HksEcdhAgreeExport(const struct OH_Huks_Blob *keyAlias1, const struct OH_Huks_Blob *keyAlias2,
196    struct OH_Huks_Blob *publicKey1, struct OH_Huks_Blob *publicKey2, const struct OH_Huks_ParamSet *genParamSet)
197{
198    OH_Huks_Result ret = OH_Huks_ExportPublicKeyItem(keyAlias1, genParamSet, publicKey1);
199    if (ret.errorCode != OH_HUKS_SUCCESS) {
200        return ret;
201    }
202    ret = OH_Huks_ExportPublicKeyItem(keyAlias2, genParamSet, publicKey2);
203    if (ret.errorCode != OH_HUKS_SUCCESS) {
204        return ret;
205    }
206    return ret;
207}
208static const char *g_inData = "Hks_ECDH_Agree_Test_000000000000000000000000000000000000000000000000000000000000"
209                                    "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
210                                    "0000000000000000000000000000000000000000000000000000000000000000000000000_string";
211/* 协商密钥操作 */
212OH_Huks_Result HksEcdhAgreeFinish(const struct OH_Huks_Blob *keyAlias, const struct OH_Huks_Blob *publicKey,
213    const struct OH_Huks_ParamSet *initParamSet, const struct OH_Huks_ParamSet *finishParamSet, struct OH_Huks_Blob *outData)
214{
215    struct OH_Huks_Blob inData = {
216        (uint32_t)strlen(g_inData),
217        (uint8_t *)g_inData
218    };
219    uint8_t handleU[sizeof(uint64_t)] = {0};
220    struct OH_Huks_Blob handle = { sizeof(uint64_t), handleU };
221    OH_Huks_Result ret = OH_Huks_InitSession(keyAlias, initParamSet, &handle, nullptr);
222    if (ret.errorCode != OH_HUKS_SUCCESS) {
223        return ret;
224    }
225    uint8_t outDataU[ECDH_COMMON_SIZE] = {0};
226    struct OH_Huks_Blob outDataUpdate = { ECDH_COMMON_SIZE, outDataU };
227    ret = OH_Huks_UpdateSession(&handle, initParamSet, publicKey, &outDataUpdate);
228    if (ret.errorCode != OH_HUKS_SUCCESS) {
229        return ret;
230    }
231    ret = OH_Huks_FinishSession(&handle, finishParamSet, &inData, outData);
232    if (ret.errorCode != OH_HUKS_SUCCESS) {
233        return ret;
234    }
235    return ret;
236}
237/* 协商密钥整体流程 */
238static napi_value AgreeKey(napi_env env, napi_callback_info info)
239{
240    struct OH_Huks_ParamSet *genParamSet = nullptr;
241    struct OH_Huks_ParamSet *initParamSet01 = nullptr;
242    struct OH_Huks_ParamSet *finishParamSet01 = nullptr;
243    struct OH_Huks_ParamSet *initParamSet02 = nullptr;
244    struct OH_Huks_ParamSet *finishParamSet02 = nullptr;
245    struct OH_Huks_Blob publicKey01 = { .size = OH_HUKS_ECC_KEY_SIZE_256, .data = nullptr };
246    struct OH_Huks_Blob publicKey02 = { .size = OH_HUKS_ECC_KEY_SIZE_256, .data = nullptr };
247    struct OH_Huks_Blob outData01 = { .size = ECDH_COMMON_SIZE, .data = nullptr };
248    struct OH_Huks_Blob outData02 = { .size = ECDH_COMMON_SIZE, .data = nullptr };
249    OH_Huks_Result ohResult;
250    do {
251        /* 1.确定密钥别名集成密钥参数集 */
252        ohResult = InitParamSet(&genParamSet, g_genAgreeParams, sizeof(g_genAgreeParams) / sizeof(OH_Huks_Param));
253        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
254            break;
255        }
256        ohResult = InitParamSet(&initParamSet01, g_agreeParamsInit01, sizeof(g_agreeParamsInit01) / sizeof(OH_Huks_Param));
257        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
258            break;
259        }
260        ohResult = InitParamSet(&finishParamSet01, g_agreeParamsFinish01,
261            sizeof(g_agreeParamsFinish01) / sizeof(OH_Huks_Param));
262        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
263            break;
264        }
265        ohResult = InitParamSet(&initParamSet02, g_agreeParamsInit02, sizeof(g_agreeParamsInit02) / sizeof(OH_Huks_Param));
266        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
267            break;
268        }
269        ohResult = InitParamSet(&finishParamSet02, g_agreeParamsFinish02,
270            sizeof(g_agreeParamsFinish02) / sizeof(OH_Huks_Param));
271        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
272            break;
273        }
274        /* 2.设备A生成密钥 */
275        ohResult = OH_Huks_GenerateKeyItem(&g_keyAlias01001, genParamSet, nullptr);
276        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
277            break;
278        }
279        /* 3.设备B生成密钥 */
280        ohResult = OH_Huks_GenerateKeyItem(&g_keyAlias02001, genParamSet, nullptr);
281        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
282            break;
283        }
284        ohResult = MallocAndCheckBlobData(&publicKey01, publicKey01.size);
285        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
286            break;
287        }
288        ohResult = MallocAndCheckBlobData(&publicKey02, publicKey02.size);
289        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
290            break;
291        }
292        /* 4.设备A、B导出公钥 */
293        ohResult = HksEcdhAgreeExport(&g_keyAlias01001, &g_keyAlias02001, &publicKey01, &publicKey02, genParamSet);
294        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
295            break;
296        }
297        ohResult = MallocAndCheckBlobData(&outData01, outData01.size);
298        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
299            break;
300        }
301        ohResult = MallocAndCheckBlobData(&outData02, outData02.size);
302        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
303            break;
304        }
305        /* 5.设备A协商密钥 */
306        ohResult = HksEcdhAgreeFinish(&g_keyAlias01001, &publicKey02, initParamSet01, finishParamSet01, &outData01);
307        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
308            break;
309        }
310        /* 5.设备B协商密钥 */
311        ohResult = HksEcdhAgreeFinish(&g_keyAlias02001, &publicKey01, initParamSet02, finishParamSet02, &outData02);
312    } while (0);
313    free(publicKey01.data);
314    free(publicKey02.data);
315    free(outData01.data);
316    free(outData02.data);
317    /* 6.设备A、B删除密钥 */
318    OH_Huks_DeleteKeyItem(&g_keyAlias01001, genParamSet);
319    OH_Huks_DeleteKeyItem(&g_keyAlias02001, genParamSet);
320    OH_Huks_DeleteKeyItem(&g_keyAliasFinal1001, NULL);
321    OH_Huks_DeleteKeyItem(&g_keyAliasFinal2001, NULL);
322    OH_Huks_FreeParamSet(&genParamSet);
323    OH_Huks_FreeParamSet(&initParamSet01);
324    OH_Huks_FreeParamSet(&finishParamSet01);
325    OH_Huks_FreeParamSet(&initParamSet02);
326    OH_Huks_FreeParamSet(&finishParamSet02);
327
328    napi_value ret;
329    napi_create_int32(env, ohResult.errorCode, &ret);
330    return ret;
331}
332```
333