1# Key Derivation (C/C++)
2
3
4This topic walks you through on how to derive a 256-bit key using HKDF. 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
151. Set the key alias.
16
172. Initialize the key property set. You can set **OH_HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG** (optional) to specify how the key derived from this key is managed.
18
19    - If this tag is set to **OH_HUKS_STORAGE_ONLY_USED_IN_HUKS**, the derived key is managed by HUKS. That is, the derived key is always in a secure environment throughout its lifecycle.
20
21    - If this tag is set to **OH_HUKS_STORAGE_KEY_EXPORT_ALLOWED**, the derived key will be returned to the caller for management. That is, the service side ensures the key security.
22
23    - If this tag is not set, the derived key can be either managed by HUKS or returned to the caller for management. The key protection mode can be set in the subsequent key derivation on the service side.
24
253. Use [OH_Huks_GenerateKeyItem](../../reference/apis-universal-keystore-kit/_huks_key_api.md#oh_huks_generatekeyitem) to generate a key. For details, see [Key Generation Overview and Algorithm Specifications](huks-key-generation-overview.md).
26
27Alternatively, you can [import a key](huks-key-import-overview.md).
28
29**Key Derivation**
30
311. Obtain the key alias and set the **HuksOptions** parameter.
32
33   You can set **OH_HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG** to specify how the derived key is managed.
34
35    | Key Generation| Key Derivation| 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 derivation should not conflict with the tag value set in key generation. The above table lists only valid settings.
44
452. Use [OH_Huks_InitSession](../../reference/apis-universal-keystore-kit/_huks_key_api.md#oh_huks_initsession) to initialize a key session. The session handle is returned after the initialization.
46
473. Use [OH_Huks_UpdateSession](../../reference/apis-universal-keystore-kit/_huks_key_api.md#oh_huks_updatesession)n to process data.
48
494. Use [OH_Huks_FinishSession](../../reference/apis-universal-keystore-kit/_huks_key_api.md#oh_huks_finishsession) to derive a key.
50
51**Key Deletion**
52
53Use **OH_Huks_DeleteKeyItem** to delete the key that is 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 <string.h>
59OH_Huks_Result InitParamSet(
60    struct OH_Huks_ParamSet **paramSet,
61    const struct OH_Huks_Param *params,
62    uint32_t paramCount)
63{
64    OH_Huks_Result ret = OH_Huks_InitParamSet(paramSet);
65    if (ret.errorCode != OH_HUKS_SUCCESS) {
66        return ret;
67    }
68    ret = OH_Huks_AddParams(*paramSet, params, paramCount);
69    if (ret.errorCode != OH_HUKS_SUCCESS) {
70        OH_Huks_FreeParamSet(paramSet);
71        return ret;
72    }
73    ret = OH_Huks_BuildParamSet(paramSet);
74    if (ret.errorCode != OH_HUKS_SUCCESS) {
75        OH_Huks_FreeParamSet(paramSet);
76        return ret;
77    }
78    return ret;
79}
80static const uint32_t DERIVE_KEY_SIZE_32 = 32;
81static const uint32_t DERIVE_KEY_SIZE_256 = 256;
82static struct OH_Huks_Blob g_deriveKeyAlias = {
83    (uint32_t)strlen("test_derive"),
84    (uint8_t *)"test_derive"
85};
86static struct OH_Huks_Param g_genDeriveParams[] = {
87    {
88        .tag =  OH_HUKS_TAG_ALGORITHM,
89        .uint32Param = OH_HUKS_ALG_AES
90    }, {
91        .tag =  OH_HUKS_TAG_PURPOSE,
92        .uint32Param = OH_HUKS_KEY_PURPOSE_DERIVE
93    }, {
94        .tag =  OH_HUKS_TAG_DIGEST,
95        .uint32Param = OH_HUKS_DIGEST_SHA256
96    }, {
97        .tag =  OH_HUKS_TAG_KEY_SIZE,
98        .uint32Param = OH_HUKS_AES_KEY_SIZE_256
99    }
100};
101static struct OH_Huks_Param g_hkdfParams[] = {
102    {
103        .tag =  OH_HUKS_TAG_ALGORITHM,
104        .uint32Param = OH_HUKS_ALG_HKDF
105    }, {
106        .tag =  OH_HUKS_TAG_PURPOSE,
107        .uint32Param = OH_HUKS_KEY_PURPOSE_DERIVE
108    }, {
109        .tag =  OH_HUKS_TAG_DIGEST,
110        .uint32Param = OH_HUKS_DIGEST_SHA256
111    }, {
112        .tag =  OH_HUKS_TAG_DERIVE_KEY_SIZE,
113        .uint32Param = DERIVE_KEY_SIZE_32
114    }
115};
116static struct OH_Huks_Param g_hkdfFinishParams[] = {
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_KEY_ALIAS,
122        .blob = g_deriveKeyAlias
123    }, {
124        .tag =  OH_HUKS_TAG_ALGORITHM,
125        .uint32Param = OH_HUKS_ALG_AES
126    }, {
127        .tag =  OH_HUKS_TAG_KEY_SIZE,
128        .uint32Param = DERIVE_KEY_SIZE_256
129    }, {
130        .tag =  OH_HUKS_TAG_PURPOSE,
131        .uint32Param = OH_HUKS_KEY_PURPOSE_DERIVE
132    }, {
133        .tag =  OH_HUKS_TAG_DIGEST,
134        .uint32Param = OH_HUKS_DIGEST_SHA256
135    }
136};
137static const uint32_t COMMON_SIZE = 2048;
138static const char *g_deriveInData = "Hks_HKDF_Derive_Test_00000000000000000000000000000000000000000000000000000000000"
139                                    "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
140                                    "0000000000000000000000000000000000000000000000000000000000000000000000000_string";
141static napi_value DeriveKey(napi_env env, napi_callback_info info)
142{
143    struct OH_Huks_Blob genAlias = {
144        (uint32_t)strlen("test_signVerify"),
145        (uint8_t *)"test_signVerify"
146    };
147    struct OH_Huks_Blob inData = {
148        (uint32_t)strlen(g_deriveInData),
149        (uint8_t *)g_deriveInData
150    };
151    struct OH_Huks_ParamSet *genParamSet = nullptr;
152    struct OH_Huks_ParamSet *hkdfParamSet = nullptr;
153    struct OH_Huks_ParamSet *hkdfFinishParamSet = nullptr;
154    OH_Huks_Result ohResult;
155    do {
156        ohResult = InitParamSet(&genParamSet, g_genDeriveParams, sizeof(g_genDeriveParams) / sizeof(OH_Huks_Param));
157        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
158            break;
159        }
160
161        ohResult = InitParamSet(&hkdfParamSet, g_hkdfParams, sizeof(g_hkdfParams) / sizeof(OH_Huks_Param));
162        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
163           break;
164        }
165
166        // finish paramset
167        ohResult = InitParamSet(&hkdfFinishParamSet, g_hkdfFinishParams, sizeof(g_hkdfFinishParams) / sizeof(OH_Huks_Param));
168        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
169            break;
170        }
171
172        /* 1. Generate Key */
173        ohResult = OH_Huks_GenerateKeyItem(&genAlias, genParamSet, nullptr);
174        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
175            break;
176        }
177        /* 2. Derive */
178        // Init
179        uint8_t handleD[sizeof(uint64_t)] = {0};
180        struct OH_Huks_Blob handleDerive = { sizeof(uint64_t), handleD };
181        ohResult = OH_Huks_InitSession(&genAlias, hkdfParamSet, &handleDerive, nullptr);
182        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
183            break;
184        }
185        // Update
186        uint8_t tmpOut[COMMON_SIZE] = {0};
187        struct OH_Huks_Blob outData = { COMMON_SIZE, tmpOut };
188        ohResult = OH_Huks_UpdateSession(&handleDerive, hkdfParamSet, &inData, &outData);
189        if (ohResult.errorCode != OH_HUKS_SUCCESS) {
190            break;
191        }
192        // Finish
193        uint8_t outDataD[COMMON_SIZE] = {0};
194        struct OH_Huks_Blob outDataDerive = { COMMON_SIZE, outDataD };
195        ohResult = OH_Huks_FinishSession(&handleDerive, hkdfFinishParamSet, &inData, &outDataDerive);
196    } while (0);
197    (void)OH_Huks_DeleteKeyItem(&genAlias, nullptr);
198    (void)OH_Huks_DeleteKeyItem(&g_deriveKeyAlias, nullptr);
199    OH_Huks_FreeParamSet(&genParamSet);
200    OH_Huks_FreeParamSet(&hkdfParamSet);
201    OH_Huks_FreeParamSet(&hkdfFinishParamSet);
202
203    napi_value ret;
204    napi_create_int32(env, ohResult.errorCode, &ret);
205    return ret;
206}
207```
208