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