93a89002be12d31c00af31a305a1aa29c3bc6170
[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         return 0;
228     }
229
230     EVP_CIPHER_CTX_cleanup(&cipher);
231
232     if (expected_len < (size_t)len_sum) {
233         SET_ERROR("The symmetric cipher overflowed");
234         return 0;
235     }
236
237     return 1;
238 }
239
240 static int store_mac_tag(const ies_ctx_t *ctx, const unsigned char *envelope_key, cryptogram_t *cryptogram, char *error) {
241     const size_t key_offset = EVP_CIPHER_key_length(ctx->cipher);
242     const size_t key_length = EVP_MD_size(ctx->md);
243     const size_t mac_length = cryptogram_mac_length(cryptogram);
244     unsigned int out_len;
245     HMAC_CTX hmac;
246
247     HMAC_CTX_init(&hmac);
248
249     /* Generate hash tag using encrypted data */
250     if (HMAC_Init_ex(&hmac, envelope_key + key_offset, key_length, ctx->md, NULL) != 1
251         || HMAC_Update(&hmac, cryptogram_body_data(cryptogram), cryptogram_body_length(cryptogram)) != 1
252         || HMAC_Final(&hmac, cryptogram_mac_data(cryptogram), &out_len) != 1) {
253         SET_OSSL_ERROR("Unable to generate tag");
254         HMAC_CTX_cleanup(&hmac);
255         return 0;
256     }
257
258     HMAC_CTX_cleanup(&hmac);
259
260     if (out_len != mac_length) {
261         SET_ERROR("MAC length expectation does not meet");
262         return 0;
263     }
264
265     return 1;
266 }
267
268 cryptogram_t * ecies_encrypt(const ies_ctx_t *ctx, const unsigned char *data, size_t length, char *error) {
269
270     if (!ctx || !data || !length) {
271         SET_ERROR("Invalid arguments");
272         return NULL;
273     }
274
275     const size_t block_length = EVP_CIPHER_block_size(ctx->cipher);
276     const size_t mac_length = EVP_MD_size(ctx->md);
277     cryptogram_t *cryptogram = NULL;
278     unsigned char *envelope_key = NULL;
279
280     if (block_length == 0 || block_length > EVP_MAX_BLOCK_LENGTH) {
281         SET_ERROR("Derived block size is incorrect");
282         return NULL;
283     }
284
285     cryptogram = cryptogram_alloc(ctx->stored_key_length,
286                                   mac_length,
287                                   length + (length % block_length ? (block_length - (length % block_length)) : 0));
288     if (!cryptogram) {
289         SET_ERROR("Unable to allocate a cryptogram_t buffer to hold the encrypted result.");
290         goto err;
291     }
292
293     if ((envelope_key = prepare_envelope_key(ctx, cryptogram, error)) == NULL) {
294         goto err;
295     }
296
297     if (!store_cipher_body(ctx, envelope_key, data, length, cryptogram, error)) {
298         goto err;
299     }
300
301     if (!store_mac_tag(ctx, envelope_key, cryptogram, error)) {
302         goto err;
303     }
304
305     OPENSSL_cleanse(envelope_key, nEnvKeyLen);
306     OPENSSL_free(envelope_key);
307
308     return cryptogram;
309
310   err:
311     if (cryptogram)
312         cryptogram_free(cryptogram);
313     if (envelope_key) {
314         OPENSSL_cleanse(envelope_key, nEnvKeyLen);
315         OPENSSL_free(envelope_key);
316     }
317     return NULL;
318 }
319
320 static EC_KEY *ecies_key_create_public_octets(EC_KEY *user, unsigned char *octets, size_t length, char *error) {
321
322     EC_KEY *key = NULL;
323     EC_POINT *point = NULL;
324     const EC_GROUP *group = NULL;
325
326     if (!(key = EC_KEY_new())) {
327         SET_OSSL_ERROR("Cannot create instance for ephemeral key");
328         return NULL;
329     }
330
331     if (!(group = EC_KEY_get0_group(user))) {
332         SET_ERROR("Cannot get group from user key");
333         EC_KEY_free(key);
334         return NULL;
335     }
336
337     if (EC_KEY_set_group(key, group) != 1) {
338         SET_OSSL_ERROR("EC_KEY_set_group failed");
339         EC_KEY_free(key);
340         return NULL;
341     }
342
343     if (!(point = EC_POINT_new(group))) {
344         SET_OSSL_ERROR("EC_POINT_new failed");
345         EC_KEY_free(key);
346         return NULL;
347     }
348
349     if (EC_POINT_oct2point(group, point, octets, length, NULL) != 1) {
350         SET_OSSL_ERROR("EC_POINT_oct2point failed");
351         EC_KEY_free(key);
352         return NULL;
353     }
354
355     if (EC_KEY_set_public_key(key, point) != 1) {
356         SET_OSSL_ERROR("EC_KEY_set_public_key failed");
357         EC_POINT_free(point);
358         EC_KEY_free(key);
359         return NULL;
360     }
361
362     EC_POINT_free(point);
363
364     if (EC_KEY_check_key(key) != 1) {
365         SET_OSSL_ERROR("EC_KEY_check_key failed");
366         EC_KEY_free(key);
367         return NULL;
368     }
369
370     return key;
371 }
372
373 unsigned char *restore_envelope_key(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, char *error)
374 {
375
376     const size_t ecdh_key_len = (EC_GROUP_get_degree(EC_KEY_get0_group(ctx->user_key)) + 7) / 8;
377     EC_KEY *ephemeral = NULL, *user_copy = NULL;
378     unsigned char *envelope_key = NULL, *ktmp = NULL;
379
380     if ((envelope_key = (unsigned char *) OPENSSL_malloc(nEnvKeyLen)) == NULL) {
381         SET_ERROR("Failed to allocate memory for envelope_key");
382         goto err;
383     }
384
385     if (!(user_copy = EC_KEY_new())) {
386         SET_OSSL_ERROR("Failed to create instance for user key copy");
387         goto err;
388     }
389
390     if (!(EC_KEY_copy(user_copy, ctx->user_key))) {
391         SET_OSSL_ERROR("Failed to copy user key");
392         goto err;
393     }
394
395     if (!(ephemeral = ecies_key_create_public_octets(user_copy, cryptogram_key_data(cryptogram), cryptogram_key_length(cryptogram), error))) {
396         goto err;
397     }
398
399     /* key agreement and KDF
400      * reference: openssl/crypto/ec/ec_pmeth.c */
401     ktmp = (unsigned char *) OPENSSL_malloc(ecdh_key_len);
402     if (ktmp == NULL) {
403         SET_ERROR("No memory for ECDH temporary key");
404         goto err;
405     }
406
407     if (ECDH_compute_key(ktmp, ecdh_key_len, EC_KEY_get0_public_key(ephemeral), user_copy, NULL)
408         != (int)ecdh_key_len) {
409         SET_OSSL_ERROR("An error occurred while ECDH_compute_key");
410         goto err;
411     }
412
413     /* equals to ISO 18033-2 KDF2 */
414     if (!ECDH_KDF_X9_62(envelope_key, nEnvKeyLen, ktmp, ecdh_key_len, 0, 0, ctx->kdf_md)) {
415         SET_OSSL_ERROR("Failed to stretch with KDF2");
416         goto err;
417     }
418
419     EC_KEY_free(user_copy);
420     EC_KEY_free(ephemeral);
421     OPENSSL_cleanse(ktmp, ecdh_key_len);
422     OPENSSL_free(ktmp);
423
424     return envelope_key;
425
426   err:
427     if (ephemeral)
428         EC_KEY_free(ephemeral);
429     if (user_copy)
430         EC_KEY_free(user_copy);
431     if (envelope_key) {
432         OPENSSL_cleanse(envelope_key, nEnvKeyLen);
433         OPENSSL_free(envelope_key);
434     }
435     if (ktmp) {
436         OPENSSL_cleanse(ktmp, ecdh_key_len);
437         OPENSSL_free(ktmp);
438     }
439     return NULL;
440 }
441
442 static int verify_mac(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, const unsigned char * envelope_key, char *error)
443 {
444     const size_t key_offset = EVP_CIPHER_key_length(ctx->cipher);
445     const size_t key_length = EVP_MD_size(ctx->md);
446     const size_t mac_length = cryptogram_mac_length(cryptogram);
447     unsigned int out_len;
448     HMAC_CTX hmac;
449     unsigned char md[EVP_MAX_MD_SIZE];
450
451     HMAC_CTX_init(&hmac);
452
453     /* Generate hash tag using encrypted data */
454     if (HMAC_Init_ex(&hmac, envelope_key + key_offset, key_length, ctx->md, NULL) != 1
455         || HMAC_Update(&hmac, cryptogram_body_data(cryptogram), cryptogram_body_length(cryptogram)) != 1
456         || HMAC_Final(&hmac, md, &out_len) != 1) {
457         SET_OSSL_ERROR("Unable to generate tag");
458         HMAC_CTX_cleanup(&hmac);
459         return 0;
460     }
461
462     HMAC_CTX_cleanup(&hmac);
463
464     if (out_len != mac_length) {
465         SET_ERROR("MAC length expectation does not meet");
466         return 0;
467     }
468
469     if (memcmp(md, cryptogram_mac_data(cryptogram), mac_length) != 0) {
470         SET_ERROR("MAC tag verification failed");
471         return 0;
472     }
473
474     return 1;
475 }
476
477 unsigned char *decrypt_body(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, const unsigned char *envelope_key, size_t *length, char *error)
478 {
479     int out_len;
480     size_t output_sum;
481     const size_t body_length = cryptogram_body_length(cryptogram);
482     unsigned char iv[EVP_MAX_IV_LENGTH], *block, *output;
483     EVP_CIPHER_CTX cipher;
484
485     if (!(output = (unsigned char*)malloc(body_length + 1))) {
486         SET_ERROR("Failed to allocate memory for clear text");
487         return NULL;
488     }
489
490     /* For now we use an empty initialization vector */
491     memset(iv, 0, EVP_MAX_IV_LENGTH);
492     memset(output, 0, body_length + 1);
493
494     EVP_CIPHER_CTX_init(&cipher);
495
496     block = output;
497     if (EVP_DecryptInit_ex(&cipher, ctx->cipher, NULL, envelope_key, iv) != 1
498         || EVP_DecryptUpdate(&cipher, block, &out_len, cryptogram_body_data(cryptogram), body_length) != 1) {
499         SET_OSSL_ERROR("Unable to decrypt");
500         EVP_CIPHER_CTX_cleanup(&cipher);
501         free(output);
502         return NULL;
503     }
504     output_sum = out_len;
505
506     block += output_sum;
507     if (EVP_DecryptFinal_ex(&cipher, block, &out_len) != 1) {
508         printf("Unable to decrypt the data using the chosen symmetric cipher. {error = %s}\n", ERR_error_string(ERR_get_error(), NULL));
509         EVP_CIPHER_CTX_cleanup(&cipher);
510         free(output);
511         return NULL;
512     }
513     output_sum += out_len;
514
515     EVP_CIPHER_CTX_cleanup(&cipher);
516
517     *length = output_sum;
518
519     return output;
520 }
521
522 unsigned char * ecies_decrypt(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, size_t *length, char *error)
523 {
524     unsigned char *envelope_key = NULL, *output = NULL;
525
526     if (!ctx || !cryptogram || !length || !error) {
527         SET_ERROR("Invalid argument");
528         goto err;
529     }
530
531     envelope_key = restore_envelope_key(ctx, cryptogram, error);
532     if (envelope_key == NULL) {
533         goto err;
534     }
535
536     if (!verify_mac(ctx, cryptogram, envelope_key, error)) {
537         goto err;
538     }
539
540     if ((output = decrypt_body(ctx, cryptogram, envelope_key, length, error)) == NULL) {
541         goto err;
542     }
543
544   err:
545     OPENSSL_cleanse(envelope_key, nEnvKeyLen);
546     OPENSSL_free(envelope_key);
547
548     return output;
549 }
550
551 ies_ctx_t *create_context(EC_KEY *user_key)
552 {
553     try {
554       ies_ctx_t* ctx = new ies_ctx_t;
555       ctx->cipher = EVP_aes_128_cbc();
556       ctx->md = EVP_ripemd160();
557       ctx->kdf_md = EVP_ripemd160();
558       ctx->stored_key_length = 33;
559       ctx->user_key = user_key;
560       return ctx;
561     }
562     catch (const std::bad_alloc& e) {
563       printf("Error: %s in %s:%d\n", e.what(), __FILE__, __LINE__);
564 // TODO: add checking to NULL where necessary
565       return NULL;
566     }
567 }