• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Key Agreement (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
10This topic uses ECDH as an example to demonstrate how to perform key agreement for HUKS-managed keys. For details about the scenarios and supported algorithms, see [Supported Algorithms](huks-key-generation-overview.md#supported-algorithms).
11
12## Add the dynamic library in the CMake script.
13```txt
14target_link_libraries(entry PUBLIC libhuks_ndk.z.so)
15```
16
17## How to Develop
18
19**Key Generation**
20
21Generate 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).
22
23When generating a key, you can specify the **OH_HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG** parameter (optional) to indicate whether the key generated is managed by HUKS.
24
25**Key Export**
26
27Export the public key of the asymmetric key pair of device A and device B. For details, see [Key Export](huks-export-key-arkts.md).
28
29**Key Agreement**
30
31Perform 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.
32
33During key agreement, you can set **OH_HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG** (optional) to specify how the shared secret generated is managed.
34
35- 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.
36
37- 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.
38
39- 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.
40
41| Key Generation| Key Agreement| Specifications|
42| -------- | -------- | -------- |
43| OH_HUKS_STORAGE_ONLY_USED_IN_HUKS | OH_HUKS_STORAGE_ONLY_USED_IN_HUKS | The key is managed by HUKS.|
44| OH_HUKS_STORAGE_KEY_EXPORT_ALLOWED | OH_HUKS_STORAGE_KEY_EXPORT_ALLOWED | The key is returned to the caller for management.|
45| The tag is not set.| OH_HUKS_STORAGE_ONLY_USED_IN_HUKS | The key is managed by HUKS.|
46| The tag is not set.| OH_HUKS_STORAGE_KEY_EXPORT_ALLOWED | The key is returned to the caller for management.|
47| The tag is not set.| The tag is not set.| The key is returned to the caller for management.|
48
49Note: 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.
50
51**Key Deletion**
52
53Delete 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).
54
55```c++
56#include "huks/native_huks_api.h"
57#include "huks/native_huks_param.h"
58#include "napi/native_api.h"
59#include <string.h>
60/* Initialize parameters. */
61OH_Huks_Result InitParamSet(
62    struct OH_Huks_ParamSet **paramSet,
63    const struct OH_Huks_Param *params,
64    uint32_t paramCount)
65{
66    OH_Huks_Result ret = OH_Huks_InitParamSet(paramSet);
67    if (ret.errorCode != OH_HUKS_SUCCESS) {
68        return ret;
69    }
70    ret = OH_Huks_AddParams(*paramSet, params, paramCount);
71    if (ret.errorCode != OH_HUKS_SUCCESS) {
72        OH_Huks_FreeParamSet(paramSet);
73        return ret;
74    }
75    ret = OH_Huks_BuildParamSet(paramSet);
76    if (ret.errorCode != OH_HUKS_SUCCESS) {
77        OH_Huks_FreeParamSet(paramSet);
78        return ret;
79    }
80    return ret;
81}
82static const uint32_t IV_SIZE = 16;
83static uint8_t IV[IV_SIZE] = { 0 }; // this is a test value, for real use the iv should be different every time.
84static struct OH_Huks_Blob g_keyAliasFinal1001 = {
85    (uint32_t)strlen("HksECDHAgreeKeyAliasTest001_1_final"),
86    (uint8_t *)"HksECDHAgreeKeyAliasTest001_1_final"
87};
88/* Set the key parameter set. */
89static struct OH_Huks_Param g_genAgreeParams[] = {
90    {
91        .tag = OH_HUKS_TAG_ALGORITHM,
92        .uint32Param = OH_HUKS_ALG_ECC
93    }, {
94        .tag = OH_HUKS_TAG_PURPOSE,
95        .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE
96    }, {
97        .tag = OH_HUKS_TAG_KEY_SIZE,
98        .uint32Param = OH_HUKS_ECC_KEY_SIZE_256
99    }, {
100        .tag = OH_HUKS_TAG_DIGEST,
101        .uint32Param = OH_HUKS_DIGEST_NONE
102    }
103};
104static struct OH_Huks_Param g_agreeParamsInit01[] = {
105    {
106        .tag = OH_HUKS_TAG_ALGORITHM,
107        .uint32Param = OH_HUKS_ALG_ECDH
108    }, {
109        .tag = OH_HUKS_TAG_PURPOSE,
110        .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE
111    }, {
112        .tag = OH_HUKS_TAG_KEY_SIZE,
113        .uint32Param = OH_HUKS_ECC_KEY_SIZE_256
114    }
115};
116static struct OH_Huks_Param g_agreeParamsFinish01[] = {
117    {
118        .tag = OH_HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
119        .uint32Param = OH_HUKS_STORAGE_ONLY_USED_IN_HUKS
120    }, {
121        .tag = OH_HUKS_TAG_ALGORITHM,
122        .uint32Param = OH_HUKS_ALG_AES
123    }, {
124        .tag = OH_HUKS_TAG_KEY_SIZE,
125        .uint32Param = OH_HUKS_AES_KEY_SIZE_256
126    }, {
127        .tag = OH_HUKS_TAG_PURPOSE,
128        .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE
129    }, {
130        .tag = OH_HUKS_TAG_KEY_ALIAS,
131        .blob = g_keyAliasFinal1001
132    }, {
133        .tag = OH_HUKS_TAG_PADDING,
134        .uint32Param = OH_HUKS_PADDING_NONE
135    }, {
136        .tag = OH_HUKS_TAG_BLOCK_MODE,
137        .uint32Param = OH_HUKS_MODE_CBC
138    }
139};
140static struct OH_Huks_Blob g_keyAliasFinal2001 = {
141    (uint32_t)strlen("HksECDHAgreeKeyAliasTest001_2_final"),
142    (uint8_t *)"HksECDHAgreeKeyAliasTest001_2_final"
143};
144static struct OH_Huks_Param g_agreeParamsInit02[] = {
145    {
146        .tag = OH_HUKS_TAG_ALGORITHM,
147        .uint32Param = OH_HUKS_ALG_ECDH
148    }, {
149        .tag = OH_HUKS_TAG_PURPOSE,
150        .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE
151    }, {
152        .tag = OH_HUKS_TAG_KEY_SIZE,
153        .uint32Param = OH_HUKS_ECC_KEY_SIZE_256
154    }
155};
156static struct OH_Huks_Param g_agreeParamsFinish02[] = {
157    {
158        .tag = OH_HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
159        .uint32Param = OH_HUKS_STORAGE_ONLY_USED_IN_HUKS
160    }, {
161        .tag = OH_HUKS_TAG_ALGORITHM,
162        .uint32Param = OH_HUKS_ALG_AES
163    }, {
164        .tag = OH_HUKS_TAG_KEY_SIZE,
165        .uint32Param = OH_HUKS_AES_KEY_SIZE_256
166    }, {
167        .tag = OH_HUKS_TAG_PURPOSE,
168        .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE
169    }, {
170        .tag = OH_HUKS_TAG_KEY_ALIAS,
171        .blob = g_keyAliasFinal2001
172    }, {
173        .tag = OH_HUKS_TAG_PADDING,
174        .uint32Param = OH_HUKS_PADDING_NONE
175    }, {
176        .tag = OH_HUKS_TAG_BLOCK_MODE,
177        .uint32Param = OH_HUKS_MODE_CBC
178    }
179};
180static const uint32_t ECDH_COMMON_SIZE = 1024;
181static struct OH_Huks_Blob g_keyAlias01001 = {
182    (uint32_t)strlen("HksECDHAgreeKeyAliasTest001_1"),
183    (uint8_t *)"HksECDHAgreeKeyAliasTest001_1"
184};
185static struct OH_Huks_Blob g_keyAlias02001 = {
186    (uint32_t)strlen("HksECDHAgreeKeyAliasTest001_2"),
187    (uint8_t *)"HksECDHAgreeKeyAliasTest001_2"
188};
189OH_Huks_Result MallocAndCheckBlobData(
190    struct OH_Huks_Blob *blob,
191    const uint32_t blobSize)
192{
193    struct OH_Huks_Result ret;
194    ret.errorCode = OH_HUKS_SUCCESS;
195    blob->data = (uint8_t *)malloc(blobSize);
196    if (blob->data == NULL) {
197        ret.errorCode = OH_HUKS_ERR_CODE_INTERNAL_ERROR;
198    }
199    return ret;
200}
201/* Export a key. */
202OH_Huks_Result HksEcdhAgreeExport(const struct OH_Huks_Blob *keyAlias1, const struct OH_Huks_Blob *keyAlias2,
203    struct OH_Huks_Blob *publicKey1, struct OH_Huks_Blob *publicKey2, const struct OH_Huks_ParamSet *genParamSet)
204{
205    OH_Huks_Result ret = OH_Huks_ExportPublicKeyItem(keyAlias1, genParamSet, publicKey1);
206    if (ret.errorCode != OH_HUKS_SUCCESS) {
207        return ret;
208    }
209    ret = OH_Huks_ExportPublicKeyItem(keyAlias2, genParamSet, publicKey2);
210    if (ret.errorCode != OH_HUKS_SUCCESS) {
211        return ret;
212    }
213    return ret;
214}
215static const char *g_inData = "Hks_ECDH_Agree_Test_000000000000000000000000000000000000000000000000000000000000"
216                                    "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
217                                    "0000000000000000000000000000000000000000000000000000000000000000000000000_string";
218/* Perform key agreement. */
219OH_Huks_Result HksEcdhAgreeFinish(const struct OH_Huks_Blob *keyAlias, const struct OH_Huks_Blob *publicKey,
220    const struct OH_Huks_ParamSet *initParamSet, const struct OH_Huks_ParamSet *finishParamSet, struct OH_Huks_Blob *outData)
221{
222    struct OH_Huks_Blob inData = {
223        (uint32_t)strlen(g_inData),
224        (uint8_t *)g_inData
225    };
226    uint8_t handleU[sizeof(uint64_t)] = {0};
227    struct OH_Huks_Blob handle = { sizeof(uint64_t), handleU };
228    OH_Huks_Result ret = OH_Huks_InitSession(keyAlias, initParamSet, &handle, nullptr);
229    if (ret.errorCode != OH_HUKS_SUCCESS) {
230        return ret;
231    }
232    uint8_t outDataU[ECDH_COMMON_SIZE] = {0};
233    struct OH_Huks_Blob outDataUpdate = { ECDH_COMMON_SIZE, outDataU };
234    ret = OH_Huks_UpdateSession(&handle, initParamSet, publicKey, &outDataUpdate);
235    if (ret.errorCode != OH_HUKS_SUCCESS) {
236        return ret;
237    }
238    ret = OH_Huks_FinishSession(&handle, finishParamSet, &inData, outData);
239    if (ret.errorCode != OH_HUKS_SUCCESS) {
240        return ret;
241    }
242    return ret;
243}
244/* Key agreement process. */
245static napi_value AgreeKey(napi_env env, napi_callback_info info)
246{
247    struct OH_Huks_ParamSet *genParamSet = nullptr;
248    struct OH_Huks_ParamSet *initParamSet01 = nullptr;
249    struct OH_Huks_ParamSet *finishParamSet01 = nullptr;
250    struct OH_Huks_ParamSet *initParamSet02 = nullptr;
251    struct OH_Huks_ParamSet *finishParamSet02 = nullptr;
252    struct OH_Huks_Blob publicKey01 = { .size = OH_HUKS_ECC_KEY_SIZE_256, .data = nullptr };
253    struct OH_Huks_Blob publicKey02 = { .size = OH_HUKS_ECC_KEY_SIZE_256, .data = nullptr };
254    struct OH_Huks_Blob outData01 = { .size = ECDH_COMMON_SIZE, .data = nullptr };
255    struct OH_Huks_Blob outData02 = { .size = ECDH_COMMON_SIZE, .data = nullptr };
256    OH_Huks_Result ohResult;
257    do {
258        /* 1. Set the key alias and key parameter set. */
259        ohResult = InitParamSet(&genParamSet, g_genAgreeParams, sizeof(g_genAgreeParams) / sizeof(OH_Huks_Param));
260        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
261            break;
262        }
263        ohResult = InitParamSet(&initParamSet01, g_agreeParamsInit01, sizeof(g_agreeParamsInit01) / sizeof(OH_Huks_Param));
264        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
265            break;
266        }
267        ohResult = InitParamSet(&finishParamSet01, g_agreeParamsFinish01,
268            sizeof(g_agreeParamsFinish01) / sizeof(OH_Huks_Param));
269        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
270            break;
271        }
272        ohResult = InitParamSet(&initParamSet02, g_agreeParamsInit02, sizeof(g_agreeParamsInit02) / sizeof(OH_Huks_Param));
273        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
274            break;
275        }
276        ohResult = InitParamSet(&finishParamSet02, g_agreeParamsFinish02,
277            sizeof(g_agreeParamsFinish02) / sizeof(OH_Huks_Param));
278        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
279            break;
280        }
281        /* 2. Generate an asymmetric key pair for device A. */
282        ohResult = OH_Huks_GenerateKeyItem(&g_keyAlias01001, genParamSet, nullptr);
283        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
284            break;
285        }
286        /* 3. Generate an asymmetric key pair for device B. */
287        ohResult = OH_Huks_GenerateKeyItem(&g_keyAlias02001, genParamSet, nullptr);
288        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
289            break;
290        }
291        ohResult = MallocAndCheckBlobData(&publicKey01, publicKey01.size);
292        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
293            break;
294        }
295        ohResult = MallocAndCheckBlobData(&publicKey02, publicKey02.size);
296        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
297            break;
298        }
299        /* 4. Export the public key from device A and device B separately. */
300        ohResult = HksEcdhAgreeExport(&g_keyAlias01001, &g_keyAlias02001, &publicKey01, &publicKey02, genParamSet);
301        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
302            break;
303        }
304        ohResult = MallocAndCheckBlobData(&outData01, outData01.size);
305        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
306            break;
307        }
308        ohResult = MallocAndCheckBlobData(&outData02, outData02.size);
309        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
310            break;
311        }
312        /* 5. Perform key agreement for device A. */
313        ohResult = HksEcdhAgreeFinish(&g_keyAlias01001, &publicKey02, initParamSet01, finishParamSet01, &outData01);
314        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
315            break;
316        }
317        /* 5. Perform key agreement for device B. */
318        ohResult = HksEcdhAgreeFinish(&g_keyAlias02001, &publicKey01, initParamSet02, finishParamSet02, &outData02);
319    } while (0);
320    free(publicKey01.data);
321    free(publicKey02.data);
322    free(outData01.data);
323    free(outData02.data);
324    /* 6. Delete keys from device A and device B. */
325    OH_Huks_DeleteKeyItem(&g_keyAlias01001, genParamSet);
326    OH_Huks_DeleteKeyItem(&g_keyAlias02001, genParamSet);
327    OH_Huks_DeleteKeyItem(&g_keyAliasFinal1001, NULL);
328    OH_Huks_DeleteKeyItem(&g_keyAliasFinal2001, NULL);
329    OH_Huks_FreeParamSet(&genParamSet);
330    OH_Huks_FreeParamSet(&initParamSet01);
331    OH_Huks_FreeParamSet(&finishParamSet01);
332    OH_Huks_FreeParamSet(&initParamSet02);
333    OH_Huks_FreeParamSet(&finishParamSet02);
334
335    napi_value ret;
336    napi_create_int32(env, ohResult.errorCode, &ret);
337    return ret;
338}
339```
340