2 * @file /cryptron/ecies.c
4 * @brief ECIES encryption/decryption functions.
6 * $Author: Ladar Levison $
7 * $Website: http://lavabit.com $
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__)
20 const size_t nEnvKeyLen = 16 + 20; // EVP_CIPHER_key_length(EVP_aes_128_cbc()) + EVP_MD_size(EVP_ripemd160())
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 */
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,
39 if (sinfolen > ECDH_KDF_MAX || outlen > ECDH_KDF_MAX || Zlen > ECDH_KDF_MAX)
41 mdlen = EVP_MD_size(md);
42 EVP_MD_CTX_init(&mctx);
45 unsigned char mtmp[EVP_MAX_MD_SIZE];
46 EVP_DigestInit_ex(&mctx, md, NULL);
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))
53 if (!EVP_DigestUpdate(&mctx, ctr, sizeof(ctr)))
55 if (!EVP_DigestUpdate(&mctx, sinfo, sinfolen))
59 if (!EVP_DigestFinal(&mctx, out, NULL))
68 if (!EVP_DigestFinal(&mctx, mtmp, NULL))
70 memcpy(out, mtmp, outlen);
71 OPENSSL_cleanse(mtmp, mdlen);
77 EVP_MD_CTX_cleanup(&mctx);
81 static EC_KEY * ecies_key_create(const EC_KEY *user, char *error) {
83 const EC_GROUP *group;
86 if (!(key = EC_KEY_new())) {
87 SET_OSSL_ERROR("EC_KEY_new failed");
91 if (!(group = EC_KEY_get0_group(user))) {
92 SET_ERROR("The user key does not have group");
97 if (EC_KEY_set_group(key, group) != 1) {
98 SET_OSSL_ERROR("EC_KEY_set_group failed");
103 if (EC_KEY_generate_key(key) != 1) {
104 SET_OSSL_ERROR("EC_KEY_generate_key failed");
112 static unsigned char *prepare_envelope_key(const ies_ctx_t *ctx, cryptogram_t *cryptogram, char *error)
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;
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");
128 if (!(ephemeral = ecies_key_create(ctx->user_key, error))) {
132 /* key agreement and KDF
133 * reference: openssl/crypto/ec/ec_pmeth.c */
134 ktmp = (unsigned char *) OPENSSL_malloc(ecdh_key_len);
136 SET_ERROR("No memory for ECDH temporary key");
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");
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");
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,
160 if (written_length == 0) {
161 SET_OSSL_ERROR("Error while recording the public portion of the envelope key");
164 if (written_length != ctx->stored_key_length) {
165 SET_ERROR("Written envelope key length does not match with expected");
169 EC_KEY_free(ephemeral);
170 OPENSSL_cleanse(ktmp, ecdh_key_len);
177 EC_KEY_free(ephemeral);
179 OPENSSL_cleanse(envelope_key, nEnvKeyLen);
180 OPENSSL_free(envelope_key);
183 OPENSSL_cleanse(ktmp, ecdh_key_len);
189 static int store_cipher_body(
190 const ies_ctx_t *ctx,
191 const unsigned char *envelope_key,
192 const unsigned char *data,
194 cryptogram_t *cryptogram,
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;
203 /* For now we use an empty initialization vector. */
204 memset(iv, 0, EVP_MAX_IV_LENGTH);
206 EVP_CIPHER_CTX_init(&cipher);
207 body = cryptogram_body_data(cryptogram);
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);
216 if (expected_len < (size_t)out_len) {
217 SET_ERROR("The symmetric cipher overflowed");
218 EVP_CIPHER_CTX_cleanup(&cipher);
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);
231 EVP_CIPHER_CTX_cleanup(&cipher);
233 if (expected_len < (size_t)len_sum) {
234 SET_ERROR("The symmetric cipher overflowed");
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;
248 HMAC_CTX_init(&hmac);
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);
259 HMAC_CTX_cleanup(&hmac);
261 if (out_len != mac_length) {
262 SET_ERROR("MAC length expectation does not meet");
269 cryptogram_t * ecies_encrypt(const ies_ctx_t *ctx, const unsigned char *data, size_t length, char *error) {
271 if (!ctx || !data || !length) {
272 SET_ERROR("Invalid arguments");
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;
281 if (block_length == 0 || block_length > EVP_MAX_BLOCK_LENGTH) {
282 SET_ERROR("Derived block size is incorrect");
286 cryptogram = cryptogram_alloc(ctx->stored_key_length,
288 length + (length % block_length ? (block_length - (length % block_length)) : 0));
290 SET_ERROR("Unable to allocate a cryptogram_t buffer to hold the encrypted result.");
294 if ((envelope_key = prepare_envelope_key(ctx, cryptogram, error)) == NULL) {
298 if (!store_cipher_body(ctx, envelope_key, data, length, cryptogram, error)) {
302 if (!store_mac_tag(ctx, envelope_key, cryptogram, error)) {
306 OPENSSL_cleanse(envelope_key, nEnvKeyLen);
307 OPENSSL_free(envelope_key);
313 cryptogram_free(cryptogram);
315 OPENSSL_cleanse(envelope_key, nEnvKeyLen);
316 OPENSSL_free(envelope_key);
321 static EC_KEY *ecies_key_create_public_octets(EC_KEY *user, unsigned char *octets, size_t length, char *error) {
324 EC_POINT *point = NULL;
325 const EC_GROUP *group = NULL;
327 if (!(key = EC_KEY_new())) {
328 SET_OSSL_ERROR("Cannot create instance for ephemeral key");
332 if (!(group = EC_KEY_get0_group(user))) {
333 SET_ERROR("Cannot get group from user key");
338 if (EC_KEY_set_group(key, group) != 1) {
339 SET_OSSL_ERROR("EC_KEY_set_group failed");
344 if (!(point = EC_POINT_new(group))) {
345 SET_OSSL_ERROR("EC_POINT_new failed");
350 if (EC_POINT_oct2point(group, point, octets, length, NULL) != 1) {
351 SET_OSSL_ERROR("EC_POINT_oct2point failed");
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);
363 EC_POINT_free(point);
365 if (EC_KEY_check_key(key) != 1) {
366 SET_OSSL_ERROR("EC_KEY_check_key failed");
374 unsigned char *restore_envelope_key(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, char *error)
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;
381 if ((envelope_key = (unsigned char *) OPENSSL_malloc(nEnvKeyLen)) == NULL) {
382 SET_ERROR("Failed to allocate memory for envelope_key");
386 if (!(user_copy = EC_KEY_new())) {
387 SET_OSSL_ERROR("Failed to create instance for user key copy");
391 if (!(EC_KEY_copy(user_copy, ctx->user_key))) {
392 SET_OSSL_ERROR("Failed to copy user key");
396 if (!(ephemeral = ecies_key_create_public_octets(user_copy, cryptogram_key_data(cryptogram), cryptogram_key_length(cryptogram), error))) {
400 /* key agreement and KDF
401 * reference: openssl/crypto/ec/ec_pmeth.c */
402 ktmp = (unsigned char *) OPENSSL_malloc(ecdh_key_len);
404 SET_ERROR("No memory for ECDH temporary key");
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");
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");
420 EC_KEY_free(user_copy);
421 EC_KEY_free(ephemeral);
422 OPENSSL_cleanse(ktmp, ecdh_key_len);
429 EC_KEY_free(ephemeral);
431 EC_KEY_free(user_copy);
433 OPENSSL_cleanse(envelope_key, nEnvKeyLen);
434 OPENSSL_free(envelope_key);
437 OPENSSL_cleanse(ktmp, ecdh_key_len);
443 static int verify_mac(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, const unsigned char * envelope_key, char *error)
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;
450 unsigned char md[EVP_MAX_MD_SIZE];
452 HMAC_CTX_init(&hmac);
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);
463 HMAC_CTX_cleanup(&hmac);
465 if (out_len != mac_length) {
466 SET_ERROR("MAC length expectation does not meet");
470 if (memcmp(md, cryptogram_mac_data(cryptogram), mac_length) != 0) {
471 SET_ERROR("MAC tag verification failed");
478 unsigned char *decrypt_body(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, const unsigned char *envelope_key, size_t *length, char *error)
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;
486 if (!(output = (unsigned char*)malloc(body_length + 1))) {
487 SET_ERROR("Failed to allocate memory for clear text");
491 /* For now we use an empty initialization vector */
492 memset(iv, 0, EVP_MAX_IV_LENGTH);
493 memset(output, 0, body_length + 1);
495 EVP_CIPHER_CTX_init(&cipher);
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);
505 output_sum = out_len;
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);
514 output_sum += out_len;
516 EVP_CIPHER_CTX_cleanup(&cipher);
518 *length = output_sum;
523 unsigned char * ecies_decrypt(const ies_ctx_t *ctx, const cryptogram_t *cryptogram, size_t *length, char *error)
525 unsigned char *envelope_key = NULL, *output = NULL;
527 if (!ctx || !cryptogram || !length || !error) {
528 SET_ERROR("Invalid argument");
532 envelope_key = restore_envelope_key(ctx, cryptogram, error);
533 if (envelope_key == NULL) {
537 if (!verify_mac(ctx, cryptogram, envelope_key, error)) {
541 if ((output = decrypt_body(ctx, cryptogram, envelope_key, length, error)) == NULL) {
546 OPENSSL_cleanse(envelope_key, nEnvKeyLen);
547 OPENSSL_free(envelope_key);
552 ies_ctx_t *create_context(EC_KEY *user_key)
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;
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