101b32267a3aafba728ce63b18963565df25387f
[novacoin.git] / src / ecies.cpp
1 /**
2  * @file /cryptron/ecies.c
3  *
4  * @brief ECIES encryption/decryption functions.
5  *
6  * $Author: Ladar Levison $
7  * $Website: http://lavabit.com $
8  *
9  */
10
11 #include "ies.h"
12 #include <new>
13 #include <vector>
14
15 #define SET_ERROR(string) \
16     sprintf(error, "%s %s:%d", (string), __FILE__, __LINE__)
17 #define SET_OSSL_ERROR(string) \
18     sprintf(error, "%s {error = %s} %s:%d", (string), ERR_error_string(ERR_get_error(), NULL), __FILE__, __LINE__)
19
20 const size_t nEnvKeyLen = 16 + 20; // EVP_CIPHER_key_length(EVP_aes_128_cbc()) + EVP_MD_size(EVP_ripemd160())
21
22 /* Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved.
23  * Taken from openssl/crypto/ecdh/ech_kdf.c in github:openssl/openssl
24  * ffa08b3242e0f10f1fef3c93ef3f0b51de8c27a9 */
25
26 /* Key derivation function from X9.62/SECG */
27 /* Way more than we will ever need */
28 #define ECDH_KDF_MAX (1 << 30)
29 int ECDH_KDF_X9_62(unsigned char *out, size_t outlen,
30                    const unsigned char *Z, size_t Zlen,
31                    const unsigned char *sinfo, size_t sinfolen,
32                    const EVP_MD *md)
33 {
34     EVP_MD_CTX mctx;
35     int rv = 0;
36     unsigned int i;
37     size_t mdlen;
38     unsigned char ctr[4];
39     if (sinfolen > ECDH_KDF_MAX || outlen > ECDH_KDF_MAX || Zlen > ECDH_KDF_MAX)
40         return 0;
41     mdlen = EVP_MD_size(md);
42     EVP_MD_CTX_init(&mctx);
43     for (i = 1;;i++)
44     {
45         unsigned char mtmp[EVP_MAX_MD_SIZE];
46         EVP_DigestInit_ex(&mctx, md, NULL);
47         ctr[3] = i & 0xFF;
48         ctr[2] = (i >> 8) & 0xFF;
49         ctr[1] = (i >> 16) & 0xFF;
50         ctr[0] = (i >> 24) & 0xFF;
51         if (!EVP_DigestUpdate(&mctx, Z, Zlen))
52             goto err;
53         if (!EVP_DigestUpdate(&mctx, ctr, sizeof(ctr)))
54             goto err;
55         if (!EVP_DigestUpdate(&mctx, sinfo, sinfolen))
56             goto err;
57         if (outlen >= mdlen)
58         {
59             if (!EVP_DigestFinal(&mctx, out, NULL))
60                 goto err;
61             outlen -= mdlen;
62             if (outlen == 0)
63                 break;
64             out += mdlen;
65         }
66         else
67         {
68             if (!EVP_DigestFinal(&mctx, mtmp, NULL))
69                 goto err;
70             memcpy(out, mtmp, outlen);
71             OPENSSL_cleanse(mtmp, mdlen);
72             break;
73         }
74     }
75     rv = 1;
76   err:
77     EVP_MD_CTX_cleanup(&mctx);
78     return rv;
79 }
80
81 static EC_KEY * ecies_key_create(const EC_KEY *user, char *error) {
82
83     const EC_GROUP *group;
84     EC_KEY *key = NULL;
85
86     if (!(key = EC_KEY_new())) {
87         SET_OSSL_ERROR("EC_KEY_new failed");
88         return NULL;
89     }
90
91     if (!(group = EC_KEY_get0_group(user))) {
92         SET_ERROR("The user key does not have group");
93         EC_KEY_free(key);
94         return NULL;
95     }
96
97     if (EC_KEY_set_group(key, group) != 1) {
98         SET_OSSL_ERROR("EC_KEY_set_group failed");
99         EC_KEY_free(key);
100         return NULL;
101     }
102
103     if (EC_KEY_generate_key(key) != 1) {
104         SET_OSSL_ERROR("EC_KEY_generate_key failed");
105         EC_KEY_free(key);
106         return NULL;
107     }
108
109     return key;
110 }
111
112 static unsigned char *prepare_envelope_key(const ies_ctx_t *ctx, cryptogram_t *cryptogram, char *error)
113 {
114
115     const size_t ecdh_key_len = (EC_GROUP_get_degree(EC_KEY_get0_group(ctx->user_key)) + 7) / 8;
116     unsigned char *envelope_key = NULL, *ktmp = NULL;
117     EC_KEY *ephemeral = NULL;
118     size_t written_length;
119
120     /* High-level ECDH via EVP does not allow use of arbitrary KDF function.
121      * We should use low-level API for KDF2
122      * c.f. openssl/crypto/ec/ec_pmeth.c */
123     if ((envelope_key = (unsigned char *) OPENSSL_malloc(nEnvKeyLen)) == NULL) {
124         SET_ERROR("Failed to allocate memory for envelope_key");
125         goto err;
126     }
127
128     if (!(ephemeral = ecies_key_create(ctx->user_key, error))) {
129         goto err;
130     }
131
132     /* key agreement and KDF
133      * reference: openssl/crypto/ec/ec_pmeth.c */
134     ktmp = (unsigned char *) OPENSSL_malloc(ecdh_key_len);
135     if (ktmp == NULL) {
136         SET_ERROR("No memory for ECDH temporary key");
137         goto err;
138     }
139
140     if (ECDH_compute_key(ktmp, ecdh_key_len, EC_KEY_get0_public_key(ctx->user_key), ephemeral, NULL)
141         != (int)ecdh_key_len) {
142         SET_OSSL_ERROR("An error occurred while ECDH_compute_key");
143         goto err;
144     }
145
146     /* equals to ISO 18033-2 KDF2 */
147     if (!ECDH_KDF_X9_62(envelope_key, nEnvKeyLen, ktmp, ecdh_key_len, 0, 0, ctx->kdf_md)) {
148         SET_OSSL_ERROR("Failed to stretch with KDF2");
149         goto err;
150     }
151
152     /* Store the public key portion of the ephemeral key. */
153     written_length = EC_POINT_point2oct(
154         EC_KEY_get0_group(ephemeral),
155         EC_KEY_get0_public_key(ephemeral),
156         POINT_CONVERSION_COMPRESSED,
157         cryptogram_key_data(cryptogram),
158         ctx->stored_key_length,
159         NULL);
160     if (written_length == 0) {
161         SET_OSSL_ERROR("Error while recording the public portion of the envelope key");
162         goto err;
163     }
164     if (written_length != ctx->stored_key_length) {
165         SET_ERROR("Written envelope key length does not match with expected");
166         goto err;
167     }
168
169     EC_KEY_free(ephemeral);
170     OPENSSL_cleanse(ktmp, ecdh_key_len);
171     OPENSSL_free(ktmp);
172
173     return envelope_key;
174
175   err:
176     if (ephemeral)
177         EC_KEY_free(ephemeral);
178     if (envelope_key) {
179         OPENSSL_cleanse(envelope_key, nEnvKeyLen);
180         OPENSSL_free(envelope_key);
181     }
182     if (ktmp) {
183         OPENSSL_cleanse(ktmp, ecdh_key_len);
184         OPENSSL_free(ktmp);
185     }
186     return NULL;
187 }
188
189 static int store_cipher_body(
190     const ies_ctx_t *ctx,
191     const unsigned char *envelope_key,
192     const unsigned char *data,
193     size_t length,
194     cryptogram_t *cryptogram,
195     char *error)
196 {
197     int out_len, len_sum = 0;
198     size_t expected_len = cryptogram_body_length(cryptogram);
199     unsigned char iv[EVP_MAX_IV_LENGTH];
200     EVP_CIPHER_CTX cipher;
201     unsigned char *body;
202
203     /* For now we use an empty initialization vector. */
204     memset(iv, 0, EVP_MAX_IV_LENGTH);
205
206     EVP_CIPHER_CTX_init(&cipher);
207     body = cryptogram_body_data(cryptogram);
208
209     if (EVP_EncryptInit_ex(&cipher, ctx->cipher, NULL, envelope_key, iv) != 1
210         || EVP_EncryptUpdate(&cipher, body, &out_len, data, length) != 1) {
211         SET_OSSL_ERROR("Error while trying to secure the data using the symmetric cipher");
212         EVP_CIPHER_CTX_cleanup(&cipher);
213         return 0;
214     }
215
216     if (expected_len < (size_t)out_len) {
217         SET_ERROR("The symmetric cipher overflowed");
218         EVP_CIPHER_CTX_cleanup(&cipher);
219         return 0;
220     }
221
222     body += out_len;
223     len_sum += out_len;
224     if (EVP_EncryptFinal_ex(&cipher, body, &out_len) != 1) {
225         SET_OSSL_ERROR("Error while finalizing the data using the symmetric cipher");
226         EVP_CIPHER_CTX_cleanup(&cipher);
227         cryptogram_free(cryptogram);
228         return 0;
229     }
230
231     EVP_CIPHER_CTX_cleanup(&cipher);
232
233     if (expected_len < (size_t)len_sum) {
234         SET_ERROR("The symmetric cipher overflowed");
235         return 0;
236     }
237
238     return 1;
239 }
240
241 static int store_mac_tag(const ies_ctx_t *ctx, const unsigned char *envelope_key, cryptogram_t *cryptogram, char *error) {
242     const size_t key_offset = EVP_CIPHER_key_length(ctx->cipher);
243     const size_t key_length = EVP_MD_size(ctx->md);
244     const size_t mac_length = cryptogram_mac_length(cryptogram);
245     unsigned int out_len;
246     HMAC_CTX hmac;
247
248     HMAC_CTX_init(&hmac);
249
250     /* Generate hash tag using encrypted data */
251     if (HMAC_Init_ex(&hmac, envelope_key + key_offset, key_length, ctx->md, NULL) != 1
252         || HMAC_Update(&hmac, cryptogram_body_data(cryptogram), cryptogram_body_length(cryptogram)) != 1
253         || HMAC_Final(&hmac, cryptogram_mac_data(cryptogram), &out_len) != 1) {
254         SET_OSSL_ERROR("Unable to generate tag");
255         HMAC_CTX_cleanup(&hmac);
256         return 0;
257     }
258
259     HMAC_CTX_cleanup(&hmac);
260
261     if (out_len != mac_length) {
262         SET_ERROR("MAC length expectation does not meet");
263         return 0;
264     }
265
266     return 1;
267 }
268
269 cryptogram_t * ecies_encrypt(const ies_ctx_t *ctx, const unsigned char *data, size_t length, char *error) {
270
271     if (!ctx || !data || !length) {
272         SET_ERROR("Invalid arguments");
273         return NULL;
274     }
275
276     const size_t block_length = EVP_CIPHER_block_size(ctx->cipher);
277     const size_t mac_length = EVP_MD_size(ctx->md);
278     cryptogram_t *cryptogram = NULL;
279     unsigned char *envelope_key = NULL;
280
281     if (block_length == 0 || block_length > EVP_MAX_BLOCK_LENGTH) {
282         SET_ERROR("Derived block size is incorrect");
283         return NULL;
284     }
285
286     cryptogram = cryptogram_alloc(ctx->stored_key_length,
287                                   mac_length,
288                                   length + (length % block_length ? (block_length - (length % block_length)) : 0));
289     if (!cryptogram) {
290         SET_ERROR("Unable to allocate a cryptogram_t buffer to hold the encrypted result.");
291         goto err;
292     }
293
294     if ((envelope_key = prepare_envelope_key(ctx, cryptogram, error)) == NULL) {
295         goto err;
296     }
297
298     if (!store_cipher_body(ctx, envelope_key, data, length, cryptogram, error)) {
299         goto err;
300     }
301
302     if (!store_mac_tag(ctx, envelope_key, cryptogram, error)) {
303         goto err;
304     }
305
306     OPENSSL_cleanse(envelope_key, nEnvKeyLen);
307     OPENSSL_free(envelope_key);
308
309     return cryptogram;
310
311   err:
312     if (cryptogram)
313         cryptogram_free(cryptogram);
314     if (envelope_key) {
315         OPENSSL_cleanse(envelope_key, nEnvKeyLen);
316         OPENSSL_free(envelope_key);
317     }
318     return NULL;
319 }
320
321 static EC_KEY *ecies_key_create_public_octets(EC_KEY *user, unsigned char *octets, size_t length, char *error) {
322
323     EC_KEY *key = NULL;
324     EC_POINT *point = NULL;
325     const EC_GROUP *group = NULL;
326
327     if (!(key = EC_KEY_new())) {
328         SET_OSSL_ERROR("Cannot create instance for ephemeral key");
329         return NULL;
330     }
331
332     if (!(group = EC_KEY_get0_group(user))) {
333         SET_ERROR("Cannot get group from user key");
334         EC_KEY_free(key);
335         return NULL;
336     }
337
338     if (EC_KEY_set_group(key, group) != 1) {
339         SET_OSSL_ERROR("EC_KEY_set_group failed");
340         EC_KEY_free(key);
341         return NULL;
342     }
343
344     if (!(point = EC_POINT_new(group))) {
345         SET_OSSL_ERROR("EC_POINT_new failed");
346         EC_KEY_free(key);
347         return NULL;
348     }
349
350     if (EC_POINT_oct2point(group, point, octets, length, NULL) != 1) {
351         SET_OSSL_ERROR("EC_POINT_oct2point failed");
352         EC_KEY_free(key);
353         return NULL;
354     }
355
356     if (EC_KEY_set_public_key(key, point) != 1) {
357         SET_OSSL_ERROR("EC_KEY_set_public_key failed");
358         EC_POINT_free(point);
359         EC_KEY_free(key);
360         return NULL;
361     }
362
363     EC_POINT_free(point);
364
365     if (EC_KEY_check_key(key) != 1) {
366         SET_OSSL_ERROR("EC_KEY_check_key failed");
367         EC_KEY_free(key);
368         return NULL;
369     }
370
371     return key;
372 }
373
374 unsigned char *restore_envelope_key(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, char *error)
375 {
376
377     const size_t ecdh_key_len = (EC_GROUP_get_degree(EC_KEY_get0_group(ctx->user_key)) + 7) / 8;
378     EC_KEY *ephemeral = NULL, *user_copy = NULL;
379     unsigned char *envelope_key = NULL, *ktmp = NULL;
380
381     if ((envelope_key = (unsigned char *) OPENSSL_malloc(nEnvKeyLen)) == NULL) {
382         SET_ERROR("Failed to allocate memory for envelope_key");
383         goto err;
384     }
385
386     if (!(user_copy = EC_KEY_new())) {
387         SET_OSSL_ERROR("Failed to create instance for user key copy");
388         goto err;
389     }
390
391     if (!(EC_KEY_copy(user_copy, ctx->user_key))) {
392         SET_OSSL_ERROR("Failed to copy user key");
393         goto err;
394     }
395
396     if (!(ephemeral = ecies_key_create_public_octets(user_copy, cryptogram_key_data(cryptogram), cryptogram_key_length(cryptogram), error))) {
397         goto err;
398     }
399
400     /* key agreement and KDF
401      * reference: openssl/crypto/ec/ec_pmeth.c */
402     ktmp = (unsigned char *) OPENSSL_malloc(ecdh_key_len);
403     if (ktmp == NULL) {
404         SET_ERROR("No memory for ECDH temporary key");
405         goto err;
406     }
407
408     if (ECDH_compute_key(ktmp, ecdh_key_len, EC_KEY_get0_public_key(ephemeral), user_copy, NULL)
409         != (int)ecdh_key_len) {
410         SET_OSSL_ERROR("An error occurred while ECDH_compute_key");
411         goto err;
412     }
413
414     /* equals to ISO 18033-2 KDF2 */
415     if (!ECDH_KDF_X9_62(envelope_key, nEnvKeyLen, ktmp, ecdh_key_len, 0, 0, ctx->kdf_md)) {
416         SET_OSSL_ERROR("Failed to stretch with KDF2");
417         goto err;
418     }
419
420     EC_KEY_free(user_copy);
421     EC_KEY_free(ephemeral);
422     OPENSSL_cleanse(ktmp, ecdh_key_len);
423     OPENSSL_free(ktmp);
424
425     return envelope_key;
426
427   err:
428     if (ephemeral)
429         EC_KEY_free(ephemeral);
430     if (user_copy)
431         EC_KEY_free(user_copy);
432     if (envelope_key) {
433         OPENSSL_cleanse(envelope_key, nEnvKeyLen);
434         OPENSSL_free(envelope_key);
435     }
436     if (ktmp) {
437         OPENSSL_cleanse(ktmp, ecdh_key_len);
438         OPENSSL_free(ktmp);
439     }
440     return NULL;
441 }
442
443 static int verify_mac(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, const unsigned char * envelope_key, char *error)
444 {
445     const size_t key_offset = EVP_CIPHER_key_length(ctx->cipher);
446     const size_t key_length = EVP_MD_size(ctx->md);
447     const size_t mac_length = cryptogram_mac_length(cryptogram);
448     unsigned int out_len;
449     HMAC_CTX hmac;
450     unsigned char md[EVP_MAX_MD_SIZE];
451
452     HMAC_CTX_init(&hmac);
453
454     /* Generate hash tag using encrypted data */
455     if (HMAC_Init_ex(&hmac, envelope_key + key_offset, key_length, ctx->md, NULL) != 1
456         || HMAC_Update(&hmac, cryptogram_body_data(cryptogram), cryptogram_body_length(cryptogram)) != 1
457         || HMAC_Final(&hmac, md, &out_len) != 1) {
458         SET_OSSL_ERROR("Unable to generate tag");
459         HMAC_CTX_cleanup(&hmac);
460         return 0;
461     }
462
463     HMAC_CTX_cleanup(&hmac);
464
465     if (out_len != mac_length) {
466         SET_ERROR("MAC length expectation does not meet");
467         return 0;
468     }
469
470     if (memcmp(md, cryptogram_mac_data(cryptogram), mac_length) != 0) {
471         SET_ERROR("MAC tag verification failed");
472         return 0;
473     }
474
475     return 1;
476 }
477
478 unsigned char *decrypt_body(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, const unsigned char *envelope_key, size_t *length, char *error)
479 {
480     int out_len;
481     size_t output_sum;
482     const size_t body_length = cryptogram_body_length(cryptogram);
483     unsigned char iv[EVP_MAX_IV_LENGTH], *block, *output;
484     EVP_CIPHER_CTX cipher;
485
486     if (!(output = (unsigned char*)malloc(body_length + 1))) {
487         SET_ERROR("Failed to allocate memory for clear text");
488         return NULL;
489     }
490
491     /* For now we use an empty initialization vector */
492     memset(iv, 0, EVP_MAX_IV_LENGTH);
493     memset(output, 0, body_length + 1);
494
495     EVP_CIPHER_CTX_init(&cipher);
496
497     block = output;
498     if (EVP_DecryptInit_ex(&cipher, ctx->cipher, NULL, envelope_key, iv) != 1
499         || EVP_DecryptUpdate(&cipher, block, &out_len, cryptogram_body_data(cryptogram), body_length) != 1) {
500         SET_OSSL_ERROR("Unable to decrypt");
501         EVP_CIPHER_CTX_cleanup(&cipher);
502         free(output);
503         return NULL;
504     }
505     output_sum = out_len;
506
507     block += output_sum;
508     if (EVP_DecryptFinal_ex(&cipher, block, &out_len) != 1) {
509         printf("Unable to decrypt the data using the chosen symmetric cipher. {error = %s}\n", ERR_error_string(ERR_get_error(), NULL));
510         EVP_CIPHER_CTX_cleanup(&cipher);
511         free(output);
512         return NULL;
513     }
514     output_sum += out_len;
515
516     EVP_CIPHER_CTX_cleanup(&cipher);
517
518     *length = output_sum;
519
520     return output;
521 }
522
523 unsigned char * ecies_decrypt(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, size_t *length, char *error)
524 {
525     unsigned char *envelope_key = NULL, *output = NULL;
526
527     if (!ctx || !cryptogram || !length || !error) {
528         SET_ERROR("Invalid argument");
529         goto err;
530     }
531
532     envelope_key = restore_envelope_key(ctx, cryptogram, error);
533     if (envelope_key == NULL) {
534         goto err;
535     }
536
537     if (!verify_mac(ctx, cryptogram, envelope_key, error)) {
538         goto err;
539     }
540
541     if ((output = decrypt_body(ctx, cryptogram, envelope_key, length, error)) == NULL) {
542         goto err;
543     }
544
545   err:
546     OPENSSL_cleanse(envelope_key, nEnvKeyLen);
547     OPENSSL_free(envelope_key);
548
549     return output;
550 }
551
552 ies_ctx_t *create_context(EC_KEY *user_key)
553 {
554     try {
555       ies_ctx_t* ctx = new ies_ctx_t;
556       ctx->cipher = EVP_aes_128_cbc();
557       ctx->md = EVP_ripemd160();
558       ctx->kdf_md = EVP_ripemd160();
559       ctx->stored_key_length = 33;
560       ctx->user_key = user_key;
561       return ctx;
562     }
563     catch (const std::bad_alloc& e) {
564       printf("Error: %s in %s:%d\n", e.what(), __FILE__, __LINE__);
565 // TODO: add checking to NULL where necessary
566       return NULL;
567     }
568 }