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