Files
kunlun/rom/riscv/crypto/mbedtls-2.4.0/library/ecies_envelope.c
2024-09-28 14:24:04 +08:00

361 lines
10 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_envelope.h"
#include "mbedtls/asn1.h"
#include "mbedtls/asn1write.h"
#include "mbedtls/cipher.h"
#include "mbedtls/md.h"
#include "mbedtls/kdf.h"
#include "mbedtls/pk.h"
#include "mbedtls/oid.h"
#define INVOKE_AND_CHECK(result, invocation) \
do { \
if ((result = invocation) < 0) \
{ \
return MBEDTLS_ERR_ECIES_MALFORMED_DATA | result; \
} \
} while (0)
#define ACCUMULATE_AND_CHECK(result, len, invocation) \
do { \
if ((result = invocation) < 0) \
{ \
return MBEDTLS_ERR_ECIES_OUTPUT_TOO_SMALL | result; \
} \
else \
{ \
len += result; \
result = 0; \
} \
} while (0)
int mbedtls_ecies_read_envelope(unsigned char **p, const unsigned char *end,
size_t *len)
{
int result = 0;
INVOKE_AND_CHECK(result,
mbedtls_asn1_get_tag(p, end, len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
);
return result;
}
int mbedtls_ecies_read_version(unsigned char **p, const unsigned char *end,
int *version)
{
int result = 0;
if (version == NULL)
{
return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA;
}
INVOKE_AND_CHECK(result,
mbedtls_asn1_get_int(p, end, version)
);
return result;
}
int mbedtls_ecies_read_kdf(unsigned char **p, const unsigned char *end,
mbedtls_kdf_type_t *kdf_type, mbedtls_md_type_t *md_type)
{
int result = 0;
size_t len = 0;
mbedtls_asn1_buf kdf_alg;
mbedtls_asn1_buf md_alg;
if (kdf_type == NULL || md_type == NULL)
{
return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA;
}
INVOKE_AND_CHECK(result,
mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
);
if ((end - *p) < 1)
{
INVOKE_AND_CHECK(result, MBEDTLS_ERR_ASN1_OUT_OF_DATA);
}
kdf_alg.tag = **p;
INVOKE_AND_CHECK(result,
mbedtls_asn1_get_tag(p, end, &kdf_alg.len, MBEDTLS_ASN1_OID)
);
kdf_alg.p = *p;
*p += kdf_alg.len;
INVOKE_AND_CHECK(result,
mbedtls_oid_get_kdf_alg(&kdf_alg, kdf_type)
);
INVOKE_AND_CHECK(result,
mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
);
md_alg.tag = **p;
INVOKE_AND_CHECK(result,
mbedtls_asn1_get_tag(p, end, &md_alg.len, MBEDTLS_ASN1_OID)
);
md_alg.p = *p;
*p += md_alg.len;
INVOKE_AND_CHECK(result,
mbedtls_oid_get_md_alg(&md_alg, md_type)
);
INVOKE_AND_CHECK(result,
mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_NULL)
);
return result;
}
int mbedtls_ecies_read_hmac(unsigned char **p, const unsigned char *end,
mbedtls_md_type_t *hmac_type, unsigned char **hmac, size_t *hmac_len)
{
int result = 0;
size_t len = 0;
mbedtls_asn1_buf hmac_alg;
if (hmac_type == NULL || hmac == NULL)
{
return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA;
}
INVOKE_AND_CHECK(result,
mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
);
INVOKE_AND_CHECK(result,
mbedtls_asn1_get_alg_null(p, end, &hmac_alg)
);
INVOKE_AND_CHECK(result,
mbedtls_oid_get_md_alg(&hmac_alg, hmac_type)
);
INVOKE_AND_CHECK(result,
mbedtls_asn1_get_tag(p, end, hmac_len, MBEDTLS_ASN1_OCTET_STRING)
);
*hmac = *p;
*p += *hmac_len;
return result;
}
int mbedtls_ecies_read_content_info(unsigned char **p, const unsigned char *end,
mbedtls_cipher_type_t *cipher_type, unsigned char **iv, size_t *iv_len,
unsigned char **data, size_t *data_len)
{
int result = 0;
size_t len = 0;
mbedtls_asn1_buf cipher_alg;
mbedtls_asn1_buf cipher_params;
if (cipher_type == NULL || iv == NULL || iv_len == NULL || data == NULL || data_len == NULL)
{
return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA;
}
INVOKE_AND_CHECK(result,
mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
);
INVOKE_AND_CHECK(result,
mbedtls_asn1_get_alg(p, end, &cipher_alg, &cipher_params)
);
if (cipher_params.tag != MBEDTLS_ASN1_OCTET_STRING)
{
INVOKE_AND_CHECK(result, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
}
*iv = cipher_params.p;
*iv_len = cipher_params.len;
INVOKE_AND_CHECK(result,
mbedtls_oid_get_cipher_alg(&cipher_alg, cipher_type)
);
INVOKE_AND_CHECK(result,
mbedtls_asn1_get_tag(p, end, data_len, MBEDTLS_ASN1_OCTET_STRING)
);
*data = *p;
*p += *data_len;
return result;
}
int mbedtls_ecies_write_envelope(unsigned char **p, unsigned char *start, size_t len)
{
int result = 0;
size_t asn_len = 0;
ACCUMULATE_AND_CHECK(result, asn_len,
mbedtls_asn1_write_len(p, start, len)
);
ACCUMULATE_AND_CHECK(result, asn_len,
mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
);
return (int)asn_len;
}
int mbedtls_ecies_write_version(unsigned char **p, unsigned char *start, int version)
{
int result = 0;
size_t asn_len = 0;
ACCUMULATE_AND_CHECK(result, asn_len,
mbedtls_asn1_write_int(p, start, version)
);
return (int)asn_len;
}
int mbedtls_ecies_write_kdf(unsigned char **p, unsigned char *start,
mbedtls_kdf_type_t kdf_type, mbedtls_md_type_t md_type)
{
int result = 0;
int len = 0;
size_t md_par_len = 0;
size_t kdf_par_len = 0;
const char *oid = NULL;
size_t oid_len = 0;
if (kdf_type == MBEDTLS_KDF_NONE || md_type == MBEDTLS_MD_NONE)
{
return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA;
}
ACCUMULATE_AND_CHECK(result, md_par_len,
mbedtls_asn1_write_null(p, start)
);
INVOKE_AND_CHECK(result,
mbedtls_oid_get_oid_by_md(md_type, &oid, &oid_len)
);
ACCUMULATE_AND_CHECK(result, kdf_par_len,
mbedtls_asn1_write_algorithm_identifier(p, start, oid, oid_len, md_par_len)
);
INVOKE_AND_CHECK(result,
mbedtls_oid_get_oid_by_kdf_alg(kdf_type, &oid, &oid_len)
);
ACCUMULATE_AND_CHECK(result, len,
mbedtls_asn1_write_algorithm_identifier(p, start, oid, oid_len, kdf_par_len)
);
return (int)len;
}
int mbedtls_ecies_write_hmac(unsigned char **p, unsigned char *start,
mbedtls_md_type_t hmac_type, const unsigned char *hmac, size_t hmac_len)
{
int result = 0;
size_t len = 0;
size_t par_len = 0;
const char *oid = NULL;
size_t oid_len = 0;
if (hmac_type == MBEDTLS_MD_NONE || hmac == NULL || hmac_len == 0)
{
return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA;
}
ACCUMULATE_AND_CHECK(result, len,
mbedtls_asn1_write_octet_string(p, start, hmac, hmac_len)
);
ACCUMULATE_AND_CHECK(result, par_len,
mbedtls_asn1_write_null(p, start)
);
INVOKE_AND_CHECK(result,
mbedtls_oid_get_oid_by_md(hmac_type, &oid, &oid_len)
);
ACCUMULATE_AND_CHECK(result, len,
mbedtls_asn1_write_algorithm_identifier(p, start, oid, oid_len, par_len)
);
ACCUMULATE_AND_CHECK(result, len,
mbedtls_asn1_write_len(p, start, len)
);
ACCUMULATE_AND_CHECK(result, len,
mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
);
return (int)len;
}
int mbedtls_ecies_write_content_info(unsigned char **p, unsigned char *start,
mbedtls_cipher_type_t cipher_type, const unsigned char *iv, size_t iv_len,
size_t data_len)
{
int result = 0;
size_t len = data_len;
size_t par_len = 0;
const char *oid = NULL;
size_t oid_len = 0;
if (cipher_type == MBEDTLS_CIPHER_NONE || iv == NULL || iv_len == 0)
{
return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA;
}
ACCUMULATE_AND_CHECK(result, len,
mbedtls_asn1_write_len(p, start, data_len)
);
ACCUMULATE_AND_CHECK(result, len,
mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_OCTET_STRING)
);
ACCUMULATE_AND_CHECK(result, par_len,
mbedtls_asn1_write_octet_string(p, start, iv, iv_len)
);
INVOKE_AND_CHECK(result,
mbedtls_oid_get_oid_by_cipher_alg(cipher_type, &oid, &oid_len)
);
ACCUMULATE_AND_CHECK(result, len,
mbedtls_asn1_write_algorithm_identifier(p, start, oid, oid_len, par_len)
);
ACCUMULATE_AND_CHECK(result, len,
mbedtls_asn1_write_len(p, start, len)
);
ACCUMULATE_AND_CHECK(result, len,
mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
);
return (int)len;
}
#endif /* defined(MBEDTLS_ECIES_C) */