1# Key Agreement (C/C++)
2
3
4This topic walks you through on how to agree on an ECDH key that is used only in HUKS. For details about the scenarios and supported algorithms, see [Supported Algorithms](huks-key-generation-overview.md#supported-algorithms).
5
6## Add the dynamic library in the CMake script.
7```txt
8   target_link_libraries(entry PUBLIC libhuks_ndk.z.so)
9```
10
11## How to Develop
12
13**Key Generation**
14
15Generate an asymmetric key for device A and device B each. For details, see [Key Generation](huks-key-generation-overview.md) or [Key Import](huks-key-import-overview.md).
16
17When generating a key, you can set the **OH_HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG** parameter (optional) to specify whether the key generated is managed by HUKS.
18
19**Key Export**
20
21Export the public key of the asymmetric key pair of device A and device B. For details, see [Key Export](huks-export-key-arkts.md).
22
23**Key Agreement**
24
25Perform key agreement using the public key of the peer device and private key of the local device (that is, public key of device B and private key of device A for device A, and public key of device A and private key of device B for device B) to produce a shared secret.
26
27During key agreement, you can set **OH_HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG** (optional) to specify how the shared secret generated is managed.
28
29- If this tag is set to **OH_HUKS_STORAGE_ONLY_USED_IN_HUKS**, the shared secret is managed by HUKS. That is, the shared secret is always in a secure environment throughout its lifecycle.
30
31- If this tag is set to **OH_HUKS_STORAGE_KEY_EXPORT_ALLOWED**, the shared secret generated will be returned to the caller for management. That is, the service side ensures the key security.
32
33- If this tag is not set, the shared secret generated can be either managed by HUKS or returned to the caller for management. The key protection mode can be set in the subsequent key agreement on the service side.
34
35| Key Generation| Key Agreement| Specifications|
36| -------- | -------- | -------- |
37| OH_HUKS_STORAGE_ONLY_USED_IN_HUKS | OH_HUKS_STORAGE_ONLY_USED_IN_HUKS | The key is managed by HUKS.|
38| OH_HUKS_STORAGE_KEY_EXPORT_ALLOWED | OH_HUKS_STORAGE_KEY_EXPORT_ALLOWED | The key is returned to the caller for management.|
39| The tag is not set.| OH_HUKS_STORAGE_ONLY_USED_IN_HUKS | The key is managed by HUKS.|
40| The tag is not set.| OH_HUKS_STORAGE_KEY_EXPORT_ALLOWED | The key is returned to the caller for management.|
41| The tag is not set.| The tag is not set.| The key is returned to the caller for management.|
42
43>**NOTE**<br>The tag value set in key agreement should not conflict with the tag value set in key generation. The above table lists only valid settings.
44
45**Key Deletion**
46
47Delete the keys from device A and device B when the keys are not required. For details, see [Deleting a Key](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/* Initialize parameters. */
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/* Set the key parameter set. */
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/* Export a key. */
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/* Perform key agreement. */
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/* Key agreement process. */
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. Set the key alias and key parameter set. */
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. Generate an asymmetric key pair for device A. */
275        ohResult = OH_Huks_GenerateKeyItem(&g_keyAlias01001, genParamSet, nullptr);
276        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
277            break;
278        }
279        /* 3. Generate an asymmetric key pair for device 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. Export the public key from device A and device B separately. */
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. Perform key agreement for device A. */
306        ohResult = HksEcdhAgreeFinish(&g_keyAlias01001, &publicKey02, initParamSet01, finishParamSet01, &outData01);
307        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
308            break;
309        }
310        /* 5. Perform key agreement for device 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. Delete keys from device A and device 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