416 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			416 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Copyright (C) 2015-2016 Virgil Security Inc.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Lead Maintainer: Virgil Security Inc. <support@virgilsecurity.com>
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * All rights reserved.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Redistribution and use in source and binary forms, with or without
							 | 
						||
| 
								 | 
							
								 * modification, are permitted provided that the following conditions are
							 | 
						||
| 
								 | 
							
								 * met:
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *     (1) Redistributions of source code must retain the above copyright
							 | 
						||
| 
								 | 
							
								 *     notice, this list of conditions and the following disclaimer.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *     (2) Redistributions in binary form must reproduce the above copyright
							 | 
						||
| 
								 | 
							
								 *     notice, this list of conditions and the following disclaimer in
							 | 
						||
| 
								 | 
							
								 *     the documentation and/or other materials provided with the
							 | 
						||
| 
								 | 
							
								 *     distribution.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *     (3) Neither the name of the copyright holder nor the names of its
							 | 
						||
| 
								 | 
							
								 *     contributors may be used to endorse or promote products derived from
							 | 
						||
| 
								 | 
							
								 *     this software without specific prior written permission.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR
							 | 
						||
| 
								 | 
							
								 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
							 | 
						||
| 
								 | 
							
								 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
							 | 
						||
| 
								 | 
							
								 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
							 | 
						||
| 
								 | 
							
								 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
							 | 
						||
| 
								 | 
							
								 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
							 | 
						||
| 
								 | 
							
								 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
							 | 
						||
| 
								 | 
							
								 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
							 | 
						||
| 
								 | 
							
								 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
							 | 
						||
| 
								 | 
							
								 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
							 | 
						||
| 
								 | 
							
								 * POSSIBILITY OF SUCH DAMAGE.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * This file is part of extension to mbed TLS (https://tls.mbed.org)
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Implementation is based on the standard ISO 18033-2.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if !defined(MBEDTLS_CONFIG_FILE)
							 | 
						||
| 
								 | 
							
								#include "mbedtls/config.h"
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								#include MBEDTLS_CONFIG_FILE
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if defined(MBEDTLS_ECIES_C)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "mbedtls/ecies.h"
							 | 
						||
| 
								 | 
							
								#include "mbedtls/ecies_internal.h"
							 | 
						||
| 
								 | 
							
								#include "mbedtls/ecies_envelope.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "mbedtls/cipher.h"
							 | 
						||
| 
								 | 
							
								#include "mbedtls/md.h"
							 | 
						||
| 
								 | 
							
								#include "mbedtls/kdf.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if defined(MBEDTLS_PLATFORM_C)
							 | 
						||
| 
								 | 
							
								#include "mbedtls/platform.h"
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#define mbedtls_calloc    calloc
							 | 
						||
| 
								 | 
							
								#define mbedtls_free      free
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define INVOKE_AND_CHECK(result,invocation) \
							 | 
						||
| 
								 | 
							
								    if ((result = invocation) < 0) goto exit;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define ACCUMULATE_AND_CHECK(result, len, invocation) \
							 | 
						||
| 
								 | 
							
								do { \
							 | 
						||
| 
								 | 
							
								    if ((result = invocation) < 0) { \
							 | 
						||
| 
								 | 
							
								        goto exit; \
							 | 
						||
| 
								 | 
							
								    } else { \
							 | 
						||
| 
								 | 
							
								        len += result; \
							 | 
						||
| 
								 | 
							
								        result = 0; \
							 | 
						||
| 
								 | 
							
								    } \
							 | 
						||
| 
								 | 
							
								} while (0)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define ECIES_OCTET_SIZE 8
							 | 
						||
| 
								 | 
							
								#define ECIES_SIZE_TO_OCTETS(size) ((size + 7) / ECIES_OCTET_SIZE)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define ECIES_ENVELOPE_VERSION 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int mbedtls_ecies_encrypt(void *key, const mbedtls_ecies_info_t* info,
							 | 
						||
| 
								 | 
							
								        const unsigned char *input, size_t ilen,
							 | 
						||
| 
								 | 
							
								        unsigned char *output, size_t *olen, size_t osize,
							 | 
						||
| 
								 | 
							
								        int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    int result = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const mbedtls_md_info_t *md_info = NULL;
							 | 
						||
| 
								 | 
							
								    const mbedtls_kdf_info_t *kdf_info = NULL;
							 | 
						||
| 
								 | 
							
								    const mbedtls_md_info_t *hmac_info = NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    void* ephemeral_key = NULL; // MUST be released
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    unsigned char *shared_key = NULL; // MUST be released
							 | 
						||
| 
								 | 
							
								    size_t shared_key_len = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    unsigned char *kdf_value = NULL; // MUST be released
							 | 
						||
| 
								 | 
							
								    size_t hmac_len = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    unsigned char *hmac = NULL; // MUST be released
							 | 
						||
| 
								 | 
							
								    size_t kdf_len = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    unsigned char *cipher_key = NULL; // pointer inside data: kdf_value
							 | 
						||
| 
								 | 
							
								    size_t cipher_key_len = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    unsigned char *cipher_iv = NULL; // MUST be released
							 | 
						||
| 
								 | 
							
								    size_t cipher_iv_len = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    unsigned char *hmac_key = NULL; // pointer inside data: kdf_value
							 | 
						||
| 
								 | 
							
								    size_t hmac_key_len = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    mbedtls_cipher_context_t cipher_ctx;
							 | 
						||
| 
								 | 
							
								    size_t cipher_block_size = 0;
							 | 
						||
| 
								 | 
							
								    size_t cipher_enc_data_len = 0;
							 | 
						||
| 
								 | 
							
								    size_t cipher_enc_header_len = 0;
							 | 
						||
| 
								 | 
							
								    unsigned char *cipher_enc_data = NULL; // pointer inside data: output
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (key == NULL || info == NULL || input == NULL || output == NULL || olen == NULL) {
							 | 
						||
| 
								 | 
							
								        return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Init structures.
							 | 
						||
| 
								 | 
							
								    *olen = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    md_info = mbedtls_md_info_from_type(MBEDTLS_ECIES_MD_TYPE);
							 | 
						||
| 
								 | 
							
								    kdf_info = mbedtls_kdf_info_from_type(MBEDTLS_ECIES_KDF_TYPE);
							 | 
						||
| 
								 | 
							
								    hmac_info = mbedtls_md_info_from_type(MBEDTLS_ECIES_HMAC_TYPE);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    mbedtls_cipher_init(&cipher_ctx);
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_cipher_setup(&cipher_ctx, mbedtls_cipher_info_from_type(MBEDTLS_ECIES_CIPHER_TYPE))
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    cipher_iv_len = mbedtls_cipher_get_iv_size(&cipher_ctx);
							 | 
						||
| 
								 | 
							
								    cipher_key_len = ECIES_SIZE_TO_OCTETS(mbedtls_cipher_get_key_bitlen(&cipher_ctx));
							 | 
						||
| 
								 | 
							
								    hmac_len = mbedtls_md_get_size(hmac_info);
							 | 
						||
| 
								 | 
							
								    hmac_key_len = hmac_len;
							 | 
						||
| 
								 | 
							
								    kdf_len = cipher_key_len + hmac_key_len;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    kdf_value = mbedtls_calloc(1, kdf_len);
							 | 
						||
| 
								 | 
							
								    if (kdf_value == NULL) {
							 | 
						||
| 
								 | 
							
								        INVOKE_AND_CHECK(result, MBEDTLS_ERR_ECIES_ALLOC_FAILED)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    cipher_key = kdf_value;
							 | 
						||
| 
								 | 
							
								    hmac_key = kdf_value + cipher_key_len;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // 1. Generate ephemeral keypair.
							 | 
						||
| 
								 | 
							
								    ephemeral_key = info->key_alloc_func();
							 | 
						||
| 
								 | 
							
								    if (ephemeral_key == NULL) {
							 | 
						||
| 
								 | 
							
								        INVOKE_AND_CHECK(result, MBEDTLS_ERR_ECIES_ALLOC_FAILED)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        info->key_gen_ephemeral_func(key, ephemeral_key, f_rng, p_rng)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    // 2. Compute shared secret key.
							 | 
						||
| 
								 | 
							
								    shared_key_len = info->key_get_shared_len_func(key);
							 | 
						||
| 
								 | 
							
								    shared_key = mbedtls_calloc(1, shared_key_len);
							 | 
						||
| 
								 | 
							
								    if (shared_key == NULL) {
							 | 
						||
| 
								 | 
							
								        INVOKE_AND_CHECK(result, MBEDTLS_ERR_ECIES_ALLOC_FAILED)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        info->key_compute_shared_func(key, ephemeral_key, shared_key, shared_key_len, f_rng, p_rng)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    // 3. Derive keys (encryption key and hmac key).
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_kdf(kdf_info, md_info, shared_key, shared_key_len,
							 | 
						||
| 
								 | 
							
								                kdf_value, kdf_len)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    // 4. Encrypt given message.
							 | 
						||
| 
								 | 
							
								    cipher_iv = mbedtls_calloc(1, cipher_iv_len);
							 | 
						||
| 
								 | 
							
								    if (cipher_iv == NULL) {
							 | 
						||
| 
								 | 
							
								        INVOKE_AND_CHECK(result, MBEDTLS_ERR_ECIES_ALLOC_FAILED)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        f_rng(p_rng, cipher_iv, cipher_iv_len)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_cipher_setkey(&cipher_ctx, cipher_key,
							 | 
						||
| 
								 | 
							
								                cipher_key_len * ECIES_OCTET_SIZE, MBEDTLS_ENCRYPT)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_cipher_set_padding_mode(&cipher_ctx, MBEDTLS_ECIES_CIPHER_PADDING)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_cipher_reset(&cipher_ctx)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    cipher_block_size = mbedtls_cipher_get_block_size(&cipher_ctx);
							 | 
						||
| 
								 | 
							
								    cipher_enc_data_len = ilen + cipher_block_size;
							 | 
						||
| 
								 | 
							
								    if (osize < cipher_enc_data_len) {
							 | 
						||
| 
								 | 
							
								        result = MBEDTLS_ERR_ECIES_OUTPUT_TOO_SMALL;
							 | 
						||
| 
								 | 
							
								        goto exit;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    cipher_enc_data = output + osize - cipher_enc_data_len;
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_cipher_crypt(&cipher_ctx, cipher_iv, cipher_iv_len, input, ilen,
							 | 
						||
| 
								 | 
							
								                cipher_enc_data, &cipher_enc_data_len)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    // 5. Get HMAC for encrypted message.
							 | 
						||
| 
								 | 
							
								    hmac = mbedtls_calloc(1, hmac_len);
							 | 
						||
| 
								 | 
							
								    if (hmac == NULL) {
							 | 
						||
| 
								 | 
							
								        INVOKE_AND_CHECK(result, MBEDTLS_ERR_ECIES_ALLOC_FAILED)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_md_hmac(hmac_info, hmac_key, hmac_key_len,
							 | 
						||
| 
								 | 
							
								                cipher_enc_data, cipher_enc_data_len, hmac)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    // 6. Write envelope.
							 | 
						||
| 
								 | 
							
								    cipher_enc_header_len = 0;
							 | 
						||
| 
								 | 
							
								    ACCUMULATE_AND_CHECK(result, cipher_enc_header_len,
							 | 
						||
| 
								 | 
							
								        mbedtls_ecies_write_content_info(&cipher_enc_data, output, MBEDTLS_ECIES_CIPHER_TYPE,
							 | 
						||
| 
								 | 
							
								                cipher_iv, cipher_iv_len, cipher_enc_data_len)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    ACCUMULATE_AND_CHECK(result, cipher_enc_header_len,
							 | 
						||
| 
								 | 
							
								        mbedtls_ecies_write_hmac(&cipher_enc_data, output, mbedtls_md_get_type(hmac_info),
							 | 
						||
| 
								 | 
							
								                hmac, hmac_len)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    ACCUMULATE_AND_CHECK(result, cipher_enc_header_len,
							 | 
						||
| 
								 | 
							
								        mbedtls_ecies_write_kdf(&cipher_enc_data, output, mbedtls_kdf_get_type(kdf_info),
							 | 
						||
| 
								 | 
							
								                mbedtls_md_get_type(md_info))
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    ACCUMULATE_AND_CHECK(result, cipher_enc_header_len,
							 | 
						||
| 
								 | 
							
								        info->key_write_pub_asn1_func(&cipher_enc_data, output, ephemeral_key)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    ACCUMULATE_AND_CHECK(result, cipher_enc_header_len,
							 | 
						||
| 
								 | 
							
								        mbedtls_ecies_write_version(&cipher_enc_data, output, ECIES_ENVELOPE_VERSION)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    ACCUMULATE_AND_CHECK(result, cipher_enc_header_len,
							 | 
						||
| 
								 | 
							
								        mbedtls_ecies_write_envelope(&cipher_enc_data, output, cipher_enc_header_len)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    memmove(output, cipher_enc_data, cipher_enc_header_len);
							 | 
						||
| 
								 | 
							
								    memset(output + cipher_enc_header_len, 0, osize - cipher_enc_header_len);
							 | 
						||
| 
								 | 
							
								exit:
							 | 
						||
| 
								 | 
							
								    *olen = cipher_enc_header_len;
							 | 
						||
| 
								 | 
							
								    info->key_free_func(ephemeral_key);
							 | 
						||
| 
								 | 
							
								    mbedtls_cipher_free(&cipher_ctx);
							 | 
						||
| 
								 | 
							
								    if (shared_key != NULL) {
							 | 
						||
| 
								 | 
							
								        mbedtls_free(shared_key);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (kdf_value != NULL) {
							 | 
						||
| 
								 | 
							
								        mbedtls_free(kdf_value);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (cipher_iv != NULL) {
							 | 
						||
| 
								 | 
							
								        mbedtls_free(cipher_iv);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (hmac != NULL) {
							 | 
						||
| 
								 | 
							
								        mbedtls_free(hmac);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return result;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int mbedtls_ecies_decrypt(void *key, const mbedtls_ecies_info_t* info,
							 | 
						||
| 
								 | 
							
								         const unsigned char *input, size_t ilen,
							 | 
						||
| 
								 | 
							
								        unsigned char *output, size_t *olen, size_t osize,
							 | 
						||
| 
								 | 
							
								        int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    int result = 0;
							 | 
						||
| 
								 | 
							
								    int version = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    void *ephemeral_key = NULL; // MUST be released
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    mbedtls_md_type_t md_type = MBEDTLS_MD_NONE;
							 | 
						||
| 
								 | 
							
								    mbedtls_kdf_type_t kdf_type = MBEDTLS_KDF_NONE;
							 | 
						||
| 
								 | 
							
								    mbedtls_md_type_t hmac_type = MBEDTLS_MD_NONE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    unsigned char *shared_key = NULL; // MUST be released
							 | 
						||
| 
								 | 
							
								    size_t shared_key_len = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    unsigned char *kdf_value = NULL; // MUST be released
							 | 
						||
| 
								 | 
							
								    size_t kdf_len = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    unsigned char *hmac_base = NULL; // pointer inside data: input
							 | 
						||
| 
								 | 
							
								    size_t hmac_base_len = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    unsigned char *hmac = NULL; // MUST be released
							 | 
						||
| 
								 | 
							
								    size_t hmac_len = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    unsigned char *cipher_key = NULL; // pointer inside data: kdf_value
							 | 
						||
| 
								 | 
							
								    size_t cipher_key_len = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    unsigned char *hmac_key = NULL; // pointer inside data: kdf_value
							 | 
						||
| 
								 | 
							
								    size_t hmac_key_len = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    unsigned char *cipher_iv = NULL; // pointer inside data: input
							 | 
						||
| 
								 | 
							
								    size_t cipher_iv_len = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    mbedtls_cipher_type_t cipher_type = MBEDTLS_CIPHER_NONE;
							 | 
						||
| 
								 | 
							
								    mbedtls_cipher_context_t cipher_ctx;
							 | 
						||
| 
								 | 
							
								    size_t cipher_enc_data_len = 0;
							 | 
						||
| 
								 | 
							
								    size_t cipher_enc_header_len = 0;
							 | 
						||
| 
								 | 
							
								    unsigned char *cipher_enc_data = NULL; // pointer inside data: input
							 | 
						||
| 
								 | 
							
								    unsigned char *cipher_enc_header = NULL; // pointer inside data: input
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (key == NULL || info == NULL || input == NULL || output == NULL || olen == NULL) {
							 | 
						||
| 
								 | 
							
								        return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Init structures.
							 | 
						||
| 
								 | 
							
								    *olen = 0;
							 | 
						||
| 
								 | 
							
								    mbedtls_cipher_init(&cipher_ctx);
							 | 
						||
| 
								 | 
							
								    cipher_enc_header = (unsigned char *)input;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ephemeral_key = info->key_alloc_func();
							 | 
						||
| 
								 | 
							
								    if (ephemeral_key == NULL) {
							 | 
						||
| 
								 | 
							
								        INVOKE_AND_CHECK(result, MBEDTLS_ERR_ECIES_ALLOC_FAILED)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Read envelope.
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_ecies_read_envelope(&cipher_enc_header, input + ilen,
							 | 
						||
| 
								 | 
							
								                &cipher_enc_header_len)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_ecies_read_version(&cipher_enc_header, input + ilen, &version)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    if (version != ECIES_ENVELOPE_VERSION) {
							 | 
						||
| 
								 | 
							
								        result = MBEDTLS_ERR_ECIES_MALFORMED_DATA;
							 | 
						||
| 
								 | 
							
								        goto exit;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        info->key_read_pub_asn1_func(&cipher_enc_header, input + ilen, ephemeral_key)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_ecies_read_kdf(&cipher_enc_header, input + ilen, &kdf_type, &md_type)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_ecies_read_hmac(&cipher_enc_header, input + ilen, &hmac_type,
							 | 
						||
| 
								 | 
							
								                &hmac_base, &hmac_base_len)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_ecies_read_content_info(&cipher_enc_header, input + ilen, &cipher_type,
							 | 
						||
| 
								 | 
							
								                &cipher_iv, &cipher_iv_len, &cipher_enc_data,
							 | 
						||
| 
								 | 
							
								                &cipher_enc_data_len)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_cipher_setup(&cipher_ctx, mbedtls_cipher_info_from_type(cipher_type))
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    cipher_key_len = ECIES_SIZE_TO_OCTETS(mbedtls_cipher_get_key_bitlen(&cipher_ctx));
							 | 
						||
| 
								 | 
							
								    hmac_len = mbedtls_md_get_size(mbedtls_md_info_from_type(hmac_type));
							 | 
						||
| 
								 | 
							
								    hmac_key_len = hmac_len;
							 | 
						||
| 
								 | 
							
								    kdf_len = cipher_key_len + hmac_key_len;
							 | 
						||
| 
								 | 
							
								    kdf_value = mbedtls_calloc(1, kdf_len);
							 | 
						||
| 
								 | 
							
								    if (kdf_value == NULL) {
							 | 
						||
| 
								 | 
							
								        INVOKE_AND_CHECK(result, MBEDTLS_ERR_ECIES_ALLOC_FAILED)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    cipher_key = kdf_value;
							 | 
						||
| 
								 | 
							
								    hmac_key = kdf_value + cipher_key_len;
							 | 
						||
| 
								 | 
							
								    hmac = mbedtls_calloc(1, hmac_len);
							 | 
						||
| 
								 | 
							
								    if (hmac == NULL) {
							 | 
						||
| 
								 | 
							
								        INVOKE_AND_CHECK(result, MBEDTLS_ERR_ECIES_ALLOC_FAILED)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // 1. Compute shared secret key.
							 | 
						||
| 
								 | 
							
								    shared_key_len = info->key_get_shared_len_func(key);
							 | 
						||
| 
								 | 
							
								    shared_key = mbedtls_calloc(1, shared_key_len);
							 | 
						||
| 
								 | 
							
								    if (shared_key == NULL) {
							 | 
						||
| 
								 | 
							
								        INVOKE_AND_CHECK(result, MBEDTLS_ERR_ECIES_ALLOC_FAILED)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        info->key_compute_shared_func(ephemeral_key, key, shared_key, shared_key_len, f_rng, p_rng)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    // 2. Derive keys (encryption key and hmac key).
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_kdf(mbedtls_kdf_info_from_type(kdf_type), mbedtls_md_info_from_type(md_type),
							 | 
						||
| 
								 | 
							
								                shared_key, shared_key_len, kdf_value, kdf_len)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    // 3. Get HMAC for encrypted message and compare it.
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_md_hmac(mbedtls_md_info_from_type(hmac_type), hmac_key, hmac_key_len,
							 | 
						||
| 
								 | 
							
								                cipher_enc_data, cipher_enc_data_len, hmac)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    if (hmac_base_len != hmac_len || memcmp(hmac_base, hmac, hmac_len) != 0) {
							 | 
						||
| 
								 | 
							
								        result = MBEDTLS_ERR_ECIES_MALFORMED_DATA;
							 | 
						||
| 
								 | 
							
								        goto exit;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    // 4. Decrypt given message.
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_cipher_setkey(&cipher_ctx, cipher_key,
							 | 
						||
| 
								 | 
							
								                cipher_key_len * ECIES_OCTET_SIZE, MBEDTLS_DECRYPT)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_cipher_set_padding_mode(&cipher_ctx, MBEDTLS_ECIES_CIPHER_PADDING)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_cipher_reset(&cipher_ctx)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    if (osize < cipher_enc_data_len) {
							 | 
						||
| 
								 | 
							
								        result = MBEDTLS_ERR_ECIES_OUTPUT_TOO_SMALL;
							 | 
						||
| 
								 | 
							
								        goto exit;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    INVOKE_AND_CHECK(result,
							 | 
						||
| 
								 | 
							
								        mbedtls_cipher_crypt(&cipher_ctx, cipher_iv, cipher_iv_len, cipher_enc_data,
							 | 
						||
| 
								 | 
							
								                cipher_enc_data_len, output, olen)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								exit:
							 | 
						||
| 
								 | 
							
								    mbedtls_cipher_free(&cipher_ctx);
							 | 
						||
| 
								 | 
							
								    info->key_free_func(ephemeral_key);
							 | 
						||
| 
								 | 
							
								    if (shared_key != NULL) {
							 | 
						||
| 
								 | 
							
								        mbedtls_free(shared_key);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (kdf_value != NULL) {
							 | 
						||
| 
								 | 
							
								        mbedtls_free(kdf_value);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (hmac != NULL) {
							 | 
						||
| 
								 | 
							
								        mbedtls_free(hmac);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return result;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif /* defined(MBEDTLS_ECIES_C) */
							 |