Skip to content

Commit 8e203bf

Browse files
committed
Example for key wrap using ECDH, HKDF and AES GCM.
1 parent d091791 commit 8e203bf

2 files changed

Lines changed: 311 additions & 0 deletions

File tree

crypto/keywrap/keywrap.c

Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
/* Example showing ECC shared secret and HKDF to generate a symmetric key */
2+
/*
3+
gcc -Wall -okeywrap -lwolfssl keywrap.c
4+
*/
5+
#include <stdio.h>
6+
#include <stdint.h>
7+
8+
#include <wolfssl/options.h>
9+
#include <wolfssl/wolfcrypt/settings.h>
10+
#include <wolfssl/wolfcrypt/random.h>
11+
#include <wolfssl/wolfcrypt/ecc.h>
12+
#include <wolfssl/wolfcrypt/error-crypt.h>
13+
#include <wolfssl/wolfcrypt/asn_public.h>
14+
#include <wolfssl/wolfcrypt/hmac.h>
15+
#include <wolfssl/wolfcrypt/sha512.h>
16+
#include <wolfssl/wolfcrypt/aes.h>
17+
18+
#if defined(HAVE_ECC) && !defined(NO_HMAC) && defined(HAVE_HKDF) && defined(HAVE_AESGCM)
19+
20+
#define ECC_CURVE_ID ECC_SECP384R1
21+
#define USE_PEM /* USE_PEM, USE_DER else KeyGen */
22+
23+
/* from server-ecc384-key.pem */
24+
#ifdef USE_PEM
25+
static const char* privKeyPem =
26+
"-----BEGIN PRIVATE KEY-----\n"
27+
"MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCk5QboBhY+q4n4YEPA\n"
28+
"YCXbunv+GTUIVWV24tzgAYtraN/Pb4ASznk36yuce8RoHHShZANiAATqz5NPLAm7\n"
29+
"ORQPVmTDQLTfDmOu5XFLAMwEl//h6TiWu1+RsmrMtTlfj3BZ8QH2WisBbGgLz1Ul\n"
30+
"r22YSAqodMmpF6AMw/vTI2j+BDxjUIg7uU98ZzT3O6lz5xvDUV4iGOw=\n"
31+
"-----END PRIVATE KEY-----";
32+
#endif
33+
#ifdef USE_DER
34+
static const uint8_t privKeyDer[] = {
35+
0x30, 0x81, 0xA4, 0x02, 0x01, 0x01, 0x04, 0x30, 0xA4, 0xE5, 0x06, 0xE8, 0x06,
36+
0x16, 0x3E, 0xAB, 0x89, 0xF8, 0x60, 0x43, 0xC0, 0x60, 0x25, 0xDB, 0xBA, 0x7B,
37+
0xFE, 0x19, 0x35, 0x08, 0x55, 0x65, 0x76, 0xE2, 0xDC, 0xE0, 0x01, 0x8B, 0x6B,
38+
0x68, 0xDF, 0xCF, 0x6F, 0x80, 0x12, 0xCE, 0x79, 0x37, 0xEB, 0x2B, 0x9C, 0x7B,
39+
0xC4, 0x68, 0x1C, 0x74, 0xA0, 0x07, 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22,
40+
0xA1, 0x64, 0x03, 0x62, 0x00, 0x04, 0xEA, 0xCF, 0x93, 0x4F, 0x2C, 0x09, 0xBB,
41+
0x39, 0x14, 0x0F, 0x56, 0x64, 0xC3, 0x40, 0xB4, 0xDF, 0x0E, 0x63, 0xAE, 0xE5,
42+
0x71, 0x4B, 0x00, 0xCC, 0x04, 0x97, 0xFF, 0xE1, 0xE9, 0x38, 0x96, 0xBB, 0x5F,
43+
0x91, 0xB2, 0x6A, 0xCC, 0xB5, 0x39, 0x5F, 0x8F, 0x70, 0x59, 0xF1, 0x01, 0xF6,
44+
0x5A, 0x2B, 0x01, 0x6C, 0x68, 0x0B, 0xCF, 0x55, 0x25, 0xAF, 0x6D, 0x98, 0x48,
45+
0x0A, 0xA8, 0x74, 0xC9, 0xA9, 0x17, 0xA0, 0x0C, 0xC3, 0xFB, 0xD3, 0x23, 0x68,
46+
0xFE, 0x04, 0x3C, 0x63, 0x50, 0x88, 0x3B, 0xB9, 0x4F, 0x7C, 0x67, 0x34, 0xF7,
47+
0x3B, 0xA9, 0x73, 0xE7, 0x1B, 0xC3, 0x51, 0x5E, 0x22, 0x18, 0xEC
48+
};
49+
#endif
50+
51+
/* from client-ecc384-key.pem */
52+
#ifdef USE_PEM
53+
/* openssl ec -in ./certs/client-ecc384-key.pem -pubout -text */
54+
static const char* pubKeyPem =
55+
"-----BEGIN PUBLIC KEY-----\n"
56+
"MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEZsQIPWanoRXUUwojs60Lzo/I9Jgdptiy\n"
57+
"biIR+rnvmcD6KT5IAPn+wqZKG6cSqGuQTBy7rF1uDmLOcCD3Q3fYl8d002j+iex3\n"
58+
"yxkviUodd/mXS2YCaKVir5WBy+MkNuuF\n"
59+
"-----END PUBLIC KEY-----";
60+
#endif
61+
#ifdef USE_DER
62+
static uint8_t pubKeyDer[] = {
63+
0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01,
64+
0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0x66, 0xC4,
65+
0x08, 0x3D, 0x66, 0xA7, 0xA1, 0x15, 0xD4, 0x53, 0x0A, 0x23, 0xB3, 0xAD, 0x0B,
66+
0xCE, 0x8F, 0xC8, 0xF4, 0x98, 0x1D, 0xA6, 0xD8, 0xB2, 0x6E, 0x22, 0x11, 0xFA,
67+
0xB9, 0xEF, 0x99, 0xC0, 0xFA, 0x29, 0x3E, 0x48, 0x00, 0xF9, 0xFE, 0xC2, 0xA6,
68+
0x4A, 0x1B, 0xA7, 0x12, 0xA8, 0x6B, 0x90, 0x4C, 0x1C, 0xBB, 0xAC, 0x5D, 0x6E,
69+
0x0E, 0x62, 0xCE, 0x70, 0x20, 0xF7, 0x43, 0x77, 0xD8, 0x97, 0xC7, 0x74, 0xD3,
70+
0x68, 0xFE, 0x89, 0xEC, 0x77, 0xCB, 0x19, 0x2F, 0x89, 0x4A, 0x1D, 0x77, 0xF9,
71+
0x97, 0x4B, 0x66, 0x02, 0x68, 0xA5, 0x62, 0xAF, 0x95, 0x81, 0xCB, 0xE3, 0x24,
72+
0x36, 0xEB, 0x85
73+
};
74+
#endif
75+
76+
static void print_bin(char* desc, uint8_t* s, int sLen)
77+
{
78+
int i;
79+
printf("%s: ", desc);
80+
for (i = 0; i < sLen; i++)
81+
printf("%02x", s[i]);
82+
printf("\n");
83+
}
84+
85+
86+
int do_ecdh(WC_RNG* rng, int devId, uint8_t* secret, uint32_t* secretLen)
87+
{
88+
int ret;
89+
ecc_key myKey, peerKey;
90+
#if defined(USE_PEM) || defined(USE_DER)
91+
uint32_t idx;
92+
#ifdef USE_PEM
93+
uint8_t der[ECC_BUFSIZE];
94+
uint32_t derSz = (uint32_t)sizeof(der);
95+
#else
96+
uint8_t* der;
97+
uint32_t derSz;
98+
#endif
99+
#endif
100+
101+
memset(&myKey, 0, sizeof(myKey));
102+
memset(&peerKey, 0, sizeof(peerKey));
103+
104+
ret = wc_ecc_init_ex(&myKey, NULL, devId);
105+
if (ret == 0)
106+
ret = wc_ecc_init_ex(&peerKey, NULL, devId);
107+
108+
/* load (or generate) private key */
109+
if (ret == 0) {
110+
#ifdef USE_PEM
111+
ret = wc_KeyPemToDer((const uint8_t*)privKeyPem, strlen(privKeyPem),
112+
der, derSz, NULL);
113+
if (ret > 0) {
114+
derSz = ret;
115+
ret = 0;
116+
}
117+
#elif defined(USE_DER)
118+
der = (uint8_t*)privKeyDer;
119+
derSz = sizeof(privKeyDer);
120+
#endif
121+
}
122+
if (ret == 0) {
123+
#if defined(USE_DER) || defined(USE_PEM)
124+
idx = 0;
125+
ret = wc_EccPrivateKeyDecode(der, &idx, &myKey, derSz);
126+
#else
127+
/* don't use fixed key, just generate a key to throw away (ephemeral) */
128+
ret = wc_ecc_make_key_ex(rng, 0, &myKey, ECC_CURVE_ID);
129+
#endif
130+
}
131+
132+
/* load (or generate) public key */
133+
if (ret == 0) {
134+
#ifdef USE_PEM
135+
ret = wc_PubKeyPemToDer((const uint8_t*)pubKeyPem, strlen(pubKeyPem),
136+
der, derSz);
137+
if (ret > 0) {
138+
derSz = ret;
139+
ret = 0;
140+
}
141+
#elif defined(USE_DER)
142+
der = (uint8_t*)pubKeyDer;
143+
derSz = sizeof(pubKeyDer);
144+
#endif
145+
}
146+
if (ret == 0) {
147+
#if defined(USE_DER) || defined(USE_PEM)
148+
idx = 0;
149+
ret = wc_EccPublicKeyDecode(der, &idx, &peerKey, derSz);
150+
#else
151+
/* don't use fixed key, just generate a key to throw away (ephemeral) */
152+
ret = wc_ecc_make_key_ex(rng, 0, &peerKey, ECC_CURVE_ID);
153+
#endif
154+
}
155+
156+
/* compute shared secret */
157+
if (ret == 0) {
158+
*secretLen = wc_ecc_size(&myKey);
159+
wc_ecc_set_rng(&myKey, rng);
160+
ret = wc_ecc_shared_secret(&myKey, &peerKey, secret, secretLen);
161+
}
162+
163+
wc_ecc_free(&peerKey);
164+
wc_ecc_free(&myKey);
165+
166+
return ret;
167+
}
168+
169+
#if 0
170+
int wc_HKDF(int type, const uint8_t* inKey, uint32_t inKeySz,
171+
const uint8_t* salt, uint32_t saltSz,
172+
const uint8_t* info, uint32_t infoSz,
173+
uint8_t* out, uint32_t outSz)
174+
#endif
175+
176+
int do_example(void)
177+
{
178+
int ret;
179+
uint8_t secret[MAX_ECC_BYTES];
180+
uint32_t secretLen = (uint32_t)sizeof(secret);
181+
const uint8_t* kdfSalt = NULL; /* optional salt for kdf */
182+
const uint8_t* kdfInfo = NULL; /* optional info for kdf */
183+
uint32_t kdfSaltSz = 0; /* size of kdfSalt */
184+
uint32_t kdfInfoSz = 0; /* size of kdfInfo */
185+
WC_RNG rng;
186+
uint8_t key[AES_256_KEY_SIZE];
187+
int keyLen = (int)sizeof(key);
188+
uint8_t wrapKey[AES_256_KEY_SIZE];
189+
uint8_t wrapKeyEnc[AES_256_KEY_SIZE];
190+
int wrapKeyLen = (int)sizeof(wrapKey);
191+
Aes aes;
192+
uint8_t tag[AES_BLOCK_SIZE];
193+
uint8_t iv[GCM_NONCE_MID_SZ];
194+
uint8_t* aad = NULL; /* optional additional auth used in tag generation */
195+
uint32_t aadLen = 0;
196+
int devId = INVALID_DEVID;
197+
198+
199+
ret = wc_InitRng_ex(&rng, NULL, devId);
200+
if (ret != 0) {
201+
printf("RNG Init failed! %d (%s)\n", ret, wc_GetErrorString(ret));
202+
return ret;
203+
}
204+
205+
206+
/* create a shared secret between a private and public key */
207+
ret = do_ecdh(&rng, devId, secret, &secretLen);
208+
if (ret == 0) {
209+
print_bin("ECDH Secret", secret, (int)secretLen);
210+
}
211+
else {
212+
printf("ECDH failed! %d (%s)\n", ret, wc_GetErrorString(ret));
213+
goto exit;
214+
}
215+
216+
/* derive a key that can be used for symmetric */
217+
ret = wc_HKDF(WC_SHA384,
218+
secret, secretLen,
219+
kdfSalt, kdfSaltSz,
220+
kdfInfo, kdfInfoSz,
221+
key, (uint32_t)keyLen
222+
);
223+
if (ret == 0) {
224+
print_bin("HKDF Derived Key", key, keyLen);
225+
}
226+
else {
227+
printf("HKDF failed! %d (%s)\n", ret, wc_GetErrorString(ret));
228+
goto exit;
229+
}
230+
231+
/* generate random value */
232+
ret = wc_RNG_GenerateBlock(&rng, wrapKey, wrapKeyLen);
233+
if (ret == 0) {
234+
print_bin("Random Key", wrapKey, wrapKeyLen);
235+
}
236+
else {
237+
printf("Random Key failed! %d (%s)\n", ret, wc_GetErrorString(ret));
238+
goto exit;
239+
}
240+
241+
/* IV */
242+
memset(iv, 0, sizeof(iv));
243+
244+
/* encrypt random value */
245+
ret = wc_AesInit(&aes, NULL, devId);
246+
if (ret == 0) {
247+
ret = wc_AesGcmSetKey(&aes, key, keyLen);
248+
if (ret == 0) {
249+
ret = wc_AesGcmEncrypt(&aes,
250+
wrapKeyEnc, wrapKey, wrapKeyLen, /* out, in, len */
251+
iv, sizeof(iv), /* IV = should be unique for each key, this will use zero's */
252+
tag, sizeof(tag), /* output: tag used to validate integrity of data */
253+
aad, aadLen /* additional authentication data (optional) and mixed with tag */
254+
);
255+
}
256+
wc_AesFree(&aes);
257+
}
258+
if (ret == 0) {
259+
print_bin("AES GCM Key Wrap", wrapKeyEnc, wrapKeyLen);
260+
}
261+
else {
262+
printf("AES GCM Key Wrap failed! %d (%s)\n", ret, wc_GetErrorString(ret));
263+
goto exit;
264+
}
265+
266+
/* test decrypt */
267+
ret = wc_AesInit(&aes, NULL, devId);
268+
if (ret == 0) {
269+
ret = wc_AesGcmSetKey(&aes, key, keyLen);
270+
if (ret == 0) {
271+
ret = wc_AesGcmDecrypt(&aes,
272+
wrapKey, wrapKeyEnc, wrapKeyLen, /* out, in, len */
273+
iv, sizeof(iv), /* IV = should be unique for each key, this will use zero's */
274+
tag, sizeof(tag), /* output: tag used to validate integrity of data */
275+
aad, aadLen /* additional authentication data (optional) and mixed with tag */
276+
);
277+
}
278+
wc_AesFree(&aes);
279+
}
280+
if (ret == 0) {
281+
print_bin("Decrypted Random Key", wrapKey, wrapKeyLen);
282+
}
283+
else {
284+
printf("AES GCM Key Unwrap failed! %d (%s)\n", ret, wc_GetErrorString(ret));
285+
goto exit;
286+
}
287+
288+
/* PKCS7 create bundle using my key and cert */
289+
/* see: pkcs7/authEnvelopedData-ktri.c */
290+
291+
292+
exit:
293+
wc_FreeRng(&rng);
294+
295+
return ret;
296+
}
297+
#endif
298+
299+
int main(int argc, char** argv)
300+
{
301+
int ret;
302+
#if defined(HAVE_ECC) && !defined(NO_HMAC) && defined(HAVE_HKDF) && defined(HAVE_AESGCM)
303+
ret = do_example();
304+
#else
305+
printf("Example requires ECC, HMAC, HKDF and AES GCM\n");
306+
ret = -1;
307+
#endif
308+
return ret;
309+
}

pk/ecdh_generate_secret/ecdh_gen_secret.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,13 @@ int do_ecc(void)
9191
goto all_three;
9292

9393
secretLen = ECC_256_BIT_FIELD; /* explicit set */
94+
wc_ecc_set_rng(&AliceKey, &rng);
9495
ret = wc_ecc_shared_secret(&AliceKey, &BobKey, AliceSecret, &secretLen);
9596
if (ret != 0)
9697
goto all_three;
9798

9899
secretLen = ECC_256_BIT_FIELD; /* explicit reset for best practice */
100+
wc_ecc_set_rng(&BobKey, &rng);
99101
ret = wc_ecc_shared_secret(&BobKey, &AliceKey, BobSecret, &secretLen);
100102
if (ret == 0) {
101103
if (XMEMCMP(AliceSecret, BobSecret, secretLen))

0 commit comments

Comments
 (0)