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