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