diff --git a/Configure b/Configure index 4d939424..2b35229b 100755 --- a/Configure +++ b/Configure @@ -311,7 +311,7 @@ $config{sdirs} = [ "buffer", "bio", "stack", "lhash", "rand", "err", "evp", "asn1", "pem", "x509", "x509v3", "conf", "txt_db", "pkcs7", "pkcs12", "comp", "ocsp", "ui", "cms", "ts", "srp", "cmac", "ct", "async", "kdf", - "sm3", "sms4", "kdf2", "ecies", "ffx" + "sm3", "sms4", "kdf2", "ecies", "ffx", "sm2" ]; # Known TLS and DTLS protocols diff --git a/crypto/ec/ec_err.c b/crypto/ec/ec_err.c index dcc90c42..e7d933bc 100644 --- a/crypto/ec/ec_err.c +++ b/crypto/ec/ec_err.c @@ -24,6 +24,7 @@ static ERR_STRING_DATA EC_str_functs[] = { {ERR_FUNC(EC_F_D2I_ECPARAMETERS), "d2i_ECParameters"}, {ERR_FUNC(EC_F_D2I_ECPKPARAMETERS), "d2i_ECPKParameters"}, {ERR_FUNC(EC_F_D2I_ECPRIVATEKEY), "d2i_ECPrivateKey"}, + {ERR_FUNC(EC_F_D2I_SM2_CIPHERTEXT_VALUE), "d2i_SM2_CIPHERTEXT_VALUE"}, {ERR_FUNC(EC_F_DO_EC_KEY_PRINT), "do_EC_KEY_print"}, {ERR_FUNC(EC_F_ECDH_CMS_DECRYPT), "ecdh_cms_decrypt"}, {ERR_FUNC(EC_F_ECDH_CMS_SET_SHARED_INFO), "ecdh_cms_set_shared_info"}, @@ -196,6 +197,7 @@ static ERR_STRING_DATA EC_str_functs[] = { {ERR_FUNC(EC_F_I2D_ECPARAMETERS), "i2d_ECParameters"}, {ERR_FUNC(EC_F_I2D_ECPKPARAMETERS), "i2d_ECPKParameters"}, {ERR_FUNC(EC_F_I2D_ECPRIVATEKEY), "i2d_ECPrivateKey"}, + {ERR_FUNC(EC_F_I2D_SM2_CIPHERTEXT_VALUE), "i2d_SM2_CIPHERTEXT_VALUE"}, {ERR_FUNC(EC_F_I2O_ECPUBLICKEY), "i2o_ECPublicKey"}, {ERR_FUNC(EC_F_NISTP224_PRE_COMP_NEW), "nistp224_pre_comp_new"}, {ERR_FUNC(EC_F_NISTP256_PRE_COMP_NEW), "nistp256_pre_comp_new"}, @@ -212,6 +214,37 @@ static ERR_STRING_DATA EC_str_functs[] = { {ERR_FUNC(EC_F_PKEY_EC_KEYGEN), "pkey_ec_keygen"}, {ERR_FUNC(EC_F_PKEY_EC_PARAMGEN), "pkey_ec_paramgen"}, {ERR_FUNC(EC_F_PKEY_EC_SIGN), "pkey_ec_sign"}, + {ERR_FUNC(EC_F_SM2_CIPHERTEXT_VALUE_DECODE), + "SM2_CIPHERTEXT_VALUE_decode"}, + {ERR_FUNC(EC_F_SM2_CIPHERTEXT_VALUE_ENCODE), + "SM2_CIPHERTEXT_VALUE_encode"}, + {ERR_FUNC(EC_F_SM2_CIPHERTEXT_VALUE_GET_ECIES_CIPHERTEXT_VALUE), + "SM2_CIPHERTEXT_VALUE_get_ECIES_CIPHERTEXT_VALUE"}, + {ERR_FUNC(EC_F_SM2_CIPHERTEXT_VALUE_NEW), "SM2_CIPHERTEXT_VALUE_new"}, + {ERR_FUNC(EC_F_SM2_CIPHERTEXT_VALUE_NEW_FROM_ECIES_CIPHERTEXT_VALUE), + "SM2_CIPHERTEXT_VALUE_new_from_ECIES_CIPHERTEXT_VALUE"}, + {ERR_FUNC(EC_F_SM2_CIPHERTEXT_VALUE_SET_ECIES_CIPHERTEXT_VALUE), + "SM2_CIPHERTEXT_VALUE_set_ECIES_CIPHERTEXT_VALUE"}, + {ERR_FUNC(EC_F_SM2_CIPHERTEXT_VALUE_SIZE), "SM2_CIPHERTEXT_VALUE_size"}, + {ERR_FUNC(EC_F_SM2_COMPUTE_ID_DIGEST), "SM2_compute_id_digest"}, + {ERR_FUNC(EC_F_SM2_COMPUTE_MESSAGE_DIGEST), "SM2_compute_message_digest"}, + {ERR_FUNC(EC_F_SM2_DECRYPT), "SM2_decrypt"}, + {ERR_FUNC(EC_F_SM2_DO_DECRYPT), "SM2_do_decrypt"}, + {ERR_FUNC(EC_F_SM2_DO_ENCRYPT), "SM2_do_encrypt"}, + {ERR_FUNC(EC_F_SM2_DO_SIGN), "sm2_do_sign"}, + {ERR_FUNC(EC_F_SM2_DO_VERIFY), "sm2_do_verify"}, + {ERR_FUNC(EC_F_SM2_ENCRYPT), "SM2_encrypt"}, + {ERR_FUNC(EC_F_SM2_ENC_PARAMS_DUP), "SM2_ENC_PARAMS_dup"}, + {ERR_FUNC(EC_F_SM2_ENC_PARAMS_INIT_WITH_RECOMMENDED), + "SM2_ENC_PARAMS_init_with_recommended"}, + {ERR_FUNC(EC_F_SM2_ENC_PARAMS_NEW), "SM2_ENC_PARAMS_new"}, + {ERR_FUNC(EC_F_SM2_ENC_PARAMS_SET_TYPE), "SM2_ENC_PARAMS_set_type"}, + {ERR_FUNC(EC_F_SM2_GET_PUBLIC_KEY_DATA), "SM2_get_public_key_data"}, + {ERR_FUNC(EC_F_SM2_KAP_COMPUTE_KEY), "SM2_KAP_compute_key"}, + {ERR_FUNC(EC_F_SM2_KAP_CTX_INIT), "SM2_KAP_CTX_init"}, + {ERR_FUNC(EC_F_SM2_KAP_FINAL_CHECK), "SM2_KAP_final_check"}, + {ERR_FUNC(EC_F_SM2_KAP_PREPARE), "SM2_KAP_prepare"}, + {ERR_FUNC(EC_F_SM2_SIGN_SETUP), "sm2_sign_setup"}, {0, NULL} }; @@ -220,6 +253,7 @@ static ERR_STRING_DATA EC_str_reasons[] = { {ERR_REASON(EC_R_BAD_SIGNATURE), "bad signature"}, {ERR_REASON(EC_R_BIGNUM_OUT_OF_RANGE), "bignum out of range"}, {ERR_REASON(EC_R_BUFFER_TOO_SMALL), "buffer too small"}, + {ERR_REASON(EC_R_CIPHERTEXT_ENCODE_FAILED), "ciphertext encode failed"}, {ERR_REASON(EC_R_CMAC_FINAL_FAILURE), "cmac final failure"}, {ERR_REASON(EC_R_CMAC_INIT_FAILURE), "cmac init failure"}, {ERR_REASON(EC_R_CMAC_UPDATE_FAILURE), "cmac update failure"}, @@ -241,8 +275,14 @@ static ERR_STRING_DATA EC_str_reasons[] = { {ERR_REASON(EC_R_EC_GROUP_NEW_BY_NAME_FAILURE), "ec group new by name failure"}, {ERR_REASON(EC_R_ENCRYPT_FAILED), "encrypt failed"}, + {ERR_REASON(EC_R_ERROR), "error"}, {ERR_REASON(EC_R_FIELD_TOO_LARGE), "field too large"}, {ERR_REASON(EC_R_GEN_MAC_FAILED), "gen mac failed"}, + {ERR_REASON(EC_R_GET_CIPHERTEXT_SIZE_FAILED), + "get ciphertext size failed"}, + {ERR_REASON(EC_R_GET_KDF_FAILED), "get kdf failed"}, + {ERR_REASON(EC_R_GET_PUBLIC_KEY_DATA_FAILURE), + "get public key data failure"}, {ERR_REASON(EC_R_GF2M_NOT_SUPPORTED), "gf2m not supported"}, {ERR_REASON(EC_R_GROUP2PKPARAMETERS_FAILURE), "group2pkparameters failure"}, @@ -250,26 +290,37 @@ static ERR_STRING_DATA EC_str_reasons[] = { {ERR_REASON(EC_R_I2D_ECPKPARAMETERS_FAILURE), "i2d ecpkparameters failure"}, {ERR_REASON(EC_R_INCOMPATIBLE_OBJECTS), "incompatible objects"}, + {ERR_REASON(EC_R_INNOR_ERROR), "innor error"}, {ERR_REASON(EC_R_INVALID_ARGUMENT), "invalid argument"}, {ERR_REASON(EC_R_INVALID_COMPRESSED_POINT), "invalid compressed point"}, {ERR_REASON(EC_R_INVALID_COMPRESSION_BIT), "invalid compression bit"}, {ERR_REASON(EC_R_INVALID_CURVE), "invalid curve"}, {ERR_REASON(EC_R_INVALID_DIGEST), "invalid digest"}, + {ERR_REASON(EC_R_INVALID_DIGEST_ALGOR), "invalid digest algor"}, {ERR_REASON(EC_R_INVALID_DIGEST_TYPE), "invalid digest type"}, {ERR_REASON(EC_R_INVALID_ECIES_CIPHERTEXT), "invalid ecies ciphertext"}, {ERR_REASON(EC_R_INVALID_ECIES_PARAMETERS), "invalid ecies parameters"}, + {ERR_REASON(EC_R_INVALID_EC_KEY), "invalid ec key"}, {ERR_REASON(EC_R_INVALID_ENCODING), "invalid encoding"}, {ERR_REASON(EC_R_INVALID_FIELD), "invalid field"}, {ERR_REASON(EC_R_INVALID_FORM), "invalid form"}, {ERR_REASON(EC_R_INVALID_GROUP_ORDER), "invalid group order"}, + {ERR_REASON(EC_R_INVALID_ID_LENGTH), "invalid id length"}, + {ERR_REASON(EC_R_INVALID_KDF_MD), "invalid kdf md"}, {ERR_REASON(EC_R_INVALID_KEY), "invalid key"}, {ERR_REASON(EC_R_INVALID_OUTPUT_LENGTH), "invalid output length"}, {ERR_REASON(EC_R_INVALID_PEER_KEY), "invalid peer key"}, {ERR_REASON(EC_R_INVALID_PENTANOMIAL_BASIS), "invalid pentanomial basis"}, {ERR_REASON(EC_R_INVALID_PRIVATE_KEY), "invalid private key"}, + {ERR_REASON(EC_R_INVALID_SM2_ID), "invalid sm2 id"}, + {ERR_REASON(EC_R_INVALID_SM2_KAP_CHECKSUM_LENGTH), + "invalid sm2 kap checksum length"}, + {ERR_REASON(EC_R_INVALID_SM2_KAP_CHECKSUM_VALUE), + "invalid sm2 kap checksum value"}, {ERR_REASON(EC_R_INVALID_TRINOMIAL_BASIS), "invalid trinomial basis"}, {ERR_REASON(EC_R_KDF_PARAMETER_ERROR), "kdf parameter error"}, {ERR_REASON(EC_R_KEYS_NOT_SET), "keys not set"}, + {ERR_REASON(EC_R_MALLOC_FAILED), "malloc failed"}, {ERR_REASON(EC_R_MISSING_PARAMETERS), "missing parameters"}, {ERR_REASON(EC_R_MISSING_PRIVATE_KEY), "missing private key"}, {ERR_REASON(EC_R_NEED_NEW_SETUP_VALUES), "need new setup values"}, @@ -278,18 +329,23 @@ static ERR_STRING_DATA EC_str_reasons[] = { {ERR_REASON(EC_R_NOT_INITIALIZED), "not initialized"}, {ERR_REASON(EC_R_NO_PARAMETERS_SET), "no parameters set"}, {ERR_REASON(EC_R_NO_PRIVATE_VALUE), "no private value"}, + {ERR_REASON(EC_R_NULL_ARGUMENT), "null argument"}, + {ERR_REASON(EC_R_OCT2POINT_FAILED), "oct2point failed"}, {ERR_REASON(EC_R_OPERATION_NOT_SUPPORTED), "operation not supported"}, {ERR_REASON(EC_R_PASSED_NULL_PARAMETER), "passed null parameter"}, {ERR_REASON(EC_R_PEER_KEY_ERROR), "peer key error"}, {ERR_REASON(EC_R_PKPARAMETERS2GROUP_FAILURE), "pkparameters2group failure"}, + {ERR_REASON(EC_R_POINT2OCT_FAILED), "point2oct failed"}, {ERR_REASON(EC_R_POINT_ARITHMETIC_FAILURE), "point arithmetic failure"}, {ERR_REASON(EC_R_POINT_AT_INFINITY), "point at infinity"}, {ERR_REASON(EC_R_POINT_IS_NOT_ON_CURVE), "point is not on curve"}, + {ERR_REASON(EC_R_POINT_NEW_FAILED), "point new failed"}, {ERR_REASON(EC_R_RANDOM_NUMBER_GENERATION_FAILED), "random number generation failed"}, {ERR_REASON(EC_R_SHARED_INFO_ERROR), "shared info error"}, {ERR_REASON(EC_R_SLOT_FULL), "slot full"}, + {ERR_REASON(EC_R_SM2_KAP_NOT_INITED), "sm2 kap not inited"}, {ERR_REASON(EC_R_UNDEFINED_GENERATOR), "undefined generator"}, {ERR_REASON(EC_R_UNDEFINED_ORDER), "undefined order"}, {ERR_REASON(EC_R_UNKNOWN_GROUP), "unknown group"}, diff --git a/crypto/sm2/build.info b/crypto/sm2/build.info new file mode 100644 index 00000000..0aaa629d --- /dev/null +++ b/crypto/sm2/build.info @@ -0,0 +1,3 @@ +LIBS=../../libcrypto +SOURCE[../../libcrypto]=sm2_asn1.c sm2_id.c sm2_sign.c sm2_enc.c sm2_kap.c \ + sm2_kmeth.c diff --git a/crypto/sm2/sm2_asn1.c b/crypto/sm2/sm2_asn1.c new file mode 100644 index 00000000..3192c7ac --- /dev/null +++ b/crypto/sm2/sm2_asn1.c @@ -0,0 +1,201 @@ +/* ==================================================================== + * Copyright (c) 2007 - 2016 The GmSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED 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 GmSSL PROJECT OR + * ITS CONTRIBUTORS 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. + * ==================================================================== + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +typedef struct SM2CiphertextValue_st { + ASN1_INTEGER *xCoordinate; + ASN1_INTEGER *yCoordinate; + ASN1_OCTET_STRING *hash; + ASN1_OCTET_STRING *ciphertext; +} SM2CiphertextValue; + +ASN1_SEQUENCE(SM2CiphertextValue) = { + ASN1_SIMPLE(SM2CiphertextValue, xCoordinate, ASN1_INTEGER), + ASN1_SIMPLE(SM2CiphertextValue, yCoordinate, ASN1_INTEGER), + ASN1_SIMPLE(SM2CiphertextValue, hash, ASN1_OCTET_STRING), + ASN1_SIMPLE(SM2CiphertextValue, ciphertext, ASN1_OCTET_STRING), +} ASN1_SEQUENCE_END(SM2CiphertextValue) +IMPLEMENT_ASN1_FUNCTIONS(SM2CiphertextValue) +IMPLEMENT_ASN1_DUP_FUNCTION(SM2CiphertextValue) + + +int i2d_SM2_CIPHERTEXT_VALUE(const EC_GROUP *group, const SM2_CIPHERTEXT_VALUE *c, + unsigned char **out) +{ + int ret = 0; + SM2CiphertextValue *asn1 = NULL; + BIGNUM *x = NULL; + BIGNUM *y = NULL; + BN_CTX *bn_ctx = NULL; + + asn1 = SM2CiphertextValue_new(); + x = BN_new(); + y = BN_new(); + bn_ctx = BN_CTX_new(); + if (!asn1 || !x || !y || !bn_ctx) { + ECerr(EC_F_I2D_SM2_CIPHERTEXT_VALUE, ERR_R_MALLOC_FAILURE); + goto end; + } + + if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) { + if (!EC_POINT_get_affine_coordinates_GFp(group, c->ephem_point, x, y, bn_ctx)) { + ECerr(EC_F_I2D_SM2_CIPHERTEXT_VALUE, ERR_R_EC_LIB); + goto end; + } + } else { + if (!EC_POINT_get_affine_coordinates_GF2m(group, c->ephem_point, x, y, bn_ctx)) { + ECerr(EC_F_I2D_SM2_CIPHERTEXT_VALUE, ERR_R_EC_LIB); + goto end; + } + } + + if (!BN_to_ASN1_INTEGER(x, asn1->xCoordinate)) { + ECerr(EC_F_I2D_SM2_CIPHERTEXT_VALUE, ERR_R_BN_LIB); + goto end; + } + if (!BN_to_ASN1_INTEGER(y, asn1->yCoordinate)) { + ECerr(EC_F_I2D_SM2_CIPHERTEXT_VALUE, ERR_R_BN_LIB); + goto end; + } + if (!ASN1_OCTET_STRING_set(asn1->hash, c->mactag, c->mactag_size)) { + ECerr(EC_F_I2D_SM2_CIPHERTEXT_VALUE, ERR_R_ASN1_LIB); + goto end; + } + if (!ASN1_OCTET_STRING_set(asn1->ciphertext, c->ciphertext, c->ciphertext_size)) { + ECerr(EC_F_I2D_SM2_CIPHERTEXT_VALUE, ERR_R_ASN1_LIB); + goto end; + } + + ret = 1; +end: + SM2CiphertextValue_free(asn1); + BN_free(x); + BN_free(y); + BN_CTX_free(bn_ctx); + return ret; +} + +SM2_CIPHERTEXT_VALUE *d2i_SM2_CIPHERTEXT_VALUE(const EC_GROUP *group, + SM2_CIPHERTEXT_VALUE **c, const unsigned char **in, long len) +{ + int e = 1; + SM2_CIPHERTEXT_VALUE *ret = NULL; + SM2CiphertextValue *asn1 = NULL; + BIGNUM *x = NULL; + BIGNUM *y = NULL; + BN_CTX *bn_ctx = NULL; + + if (!(asn1 = d2i_SM2CiphertextValue(NULL, in, len))) { + ECerr(EC_F_D2I_SM2_CIPHERTEXT_VALUE, ERR_R_MALLOC_FAILURE); + goto end; + } + if (!(x = ASN1_INTEGER_to_BN(asn1->xCoordinate, NULL))) { + ECerr(EC_F_D2I_SM2_CIPHERTEXT_VALUE, ERR_R_BN_LIB); + goto end; + } + if (!(y = ASN1_INTEGER_to_BN(asn1->yCoordinate, NULL))) { + ECerr(EC_F_D2I_SM2_CIPHERTEXT_VALUE, ERR_R_BN_LIB); + goto end; + } + + ret = SM2_CIPHERTEXT_VALUE_new(group); + bn_ctx = BN_CTX_new(); + if (!ret || !bn_ctx) { + ECerr(EC_F_D2I_SM2_CIPHERTEXT_VALUE, ERR_R_MALLOC_FAILURE); + goto end; + } + + /* (x, y) */ + if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) { + if (!EC_POINT_set_affine_coordinates_GFp(group, ret->ephem_point, x, y, bn_ctx)) { + ECerr(EC_F_D2I_SM2_CIPHERTEXT_VALUE, ERR_R_EC_LIB); + goto end; + } + } else { + if (!EC_POINT_set_affine_coordinates_GF2m(group, ret->ephem_point, x, y, bn_ctx)) { + ECerr(EC_F_D2I_SM2_CIPHERTEXT_VALUE, ERR_R_EC_LIB); + goto end; + } + } + + /* hash */ + ret->mactag_size = asn1->hash->length; + memcpy(ret->mactag, asn1->hash->data, asn1->hash->length); + + /* ciphertext */ + ret->ciphertext_size = asn1->ciphertext->length; + if (!(ret->ciphertext = OPENSSL_malloc(ret->ciphertext_size))) { + ECerr(EC_F_D2I_SM2_CIPHERTEXT_VALUE, ERR_R_MALLOC_FAILURE); + goto end; + } + memcpy(ret->ciphertext, asn1->ciphertext->data, asn1->ciphertext->length); + + e = 0; + +end: + SM2CiphertextValue_free(asn1); + BN_free(x); + BN_free(y); + BN_CTX_free(bn_ctx); + if (e && ret) { + SM2_CIPHERTEXT_VALUE_free(ret); + ret = NULL; + } + return ret; +} + diff --git a/crypto/sm2/sm2_enc.c b/crypto/sm2/sm2_enc.c new file mode 100644 index 00000000..b1584ed6 --- /dev/null +++ b/crypto/sm2/sm2_enc.c @@ -0,0 +1,745 @@ +/* + * Copyright (c) 2015 - 2016 The GmSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED 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 GmSSL PROJECT OR + * ITS CONTRIBUTORS 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. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include "internal/o_str.h" + +SM2_ENC_PARAMS *SM2_ENC_PARAMS_new(void) +{ + SM2_ENC_PARAMS *ret = NULL; + + if (!(ret = OPENSSL_zalloc(sizeof(*ret)))) { + ECerr(EC_F_SM2_ENC_PARAMS_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + + SM2_ENC_PARAMS_init_with_recommended(ret); + return ret; +} + +SM2_ENC_PARAMS *SM2_ENC_PARAMS_dup(const SM2_ENC_PARAMS *param) +{ + SM2_ENC_PARAMS *ret = NULL; + + if (!param) { + ECerr(EC_F_SM2_ENC_PARAMS_DUP, EC_R_NULL_ARGUMENT); + return NULL; + } + if (!(ret = OPENSSL_memdup(param, sizeof(*param)))) { + ECerr(EC_F_SM2_ENC_PARAMS_DUP, ERR_R_MALLOC_FAILURE); + return NULL; + } + + return ret; +} + +int SM2_ENC_PARAMS_init_with_recommended(SM2_ENC_PARAMS *params) +{ + if (!params) { + ECerr(EC_F_SM2_ENC_PARAMS_INIT_WITH_RECOMMENDED, + EC_R_NULL_ARGUMENT); + return 0; + } + params->kdf_md = EVP_sm3(); + params->mac_md = EVP_sm3(); + params->point_form = POINT_CONVERSION_UNCOMPRESSED; + return 1; +} + +void SM2_ENC_PARAMS_free(SM2_ENC_PARAMS *param) +{ + OPENSSL_free(param); +} + +int SM2_CIPHERTEXT_VALUE_size(const EC_GROUP *group, + const SM2_ENC_PARAMS *params, size_t mlen) +{ + int ret = 0; + EC_KEY *ec_key = NULL; + size_t len = 0; + + if (!(ec_key = EC_KEY_new())) { + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_SIZE, ERR_R_EC_LIB); + goto end; + } + if (!EC_KEY_set_group(ec_key, group)) { + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_SIZE, ERR_R_EC_LIB); + goto end; + } + if (!EC_KEY_generate_key(ec_key)) { + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_SIZE, ERR_R_EC_LIB); + goto end; + } + + len += EC_POINT_point2oct(group, EC_KEY_get0_public_key(ec_key), + params->point_form, NULL, 0, NULL); + len += mlen; + len += EVP_MD_size(params->mac_md); + + ret = (int)len; + +end: + EC_KEY_free(ec_key); + return ret; +} + +SM2_CIPHERTEXT_VALUE *SM2_CIPHERTEXT_VALUE_new(const EC_GROUP *group) +{ + SM2_CIPHERTEXT_VALUE *cv; + + if (!(cv = OPENSSL_malloc(sizeof(*cv)))) { + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_NEW, EC_R_MALLOC_FAILED); + return NULL; + } + + memset(cv, 0, sizeof(*cv)); + + if (!(cv->ephem_point = EC_POINT_new(group))) { + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_NEW, EC_R_POINT_NEW_FAILED); + OPENSSL_free(cv); + return NULL; + } + + return cv; +} + +void SM2_CIPHERTEXT_VALUE_free(SM2_CIPHERTEXT_VALUE *cv) +{ + if (cv->ephem_point) EC_POINT_free(cv->ephem_point); + if (cv->ciphertext) OPENSSL_free(cv->ciphertext); + memset(cv, 0, sizeof(*cv)); + OPENSSL_free(cv); +} + +int SM2_CIPHERTEXT_VALUE_encode(const SM2_CIPHERTEXT_VALUE *cv, + const EC_GROUP *ec_group, const SM2_ENC_PARAMS *params, + unsigned char *buf, size_t *buflen) +{ + int ret = 0; + BN_CTX *bn_ctx = BN_CTX_new(); + size_t ptlen, cvlen; + + OPENSSL_assert(cv); + OPENSSL_assert(ec_group); + OPENSSL_assert(buf); + OPENSSL_assert(cv->ephem_point); + + if (!bn_ctx) { + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_ENCODE, ERR_R_BN_LIB); + return 0; + } + + if (!(ptlen = EC_POINT_point2oct(ec_group, cv->ephem_point, + params->point_form, NULL, 0, bn_ctx))) { + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_ENCODE, EC_R_POINT2OCT_FAILED); + goto end; + } + cvlen = ptlen + cv->ciphertext_size + cv->mactag_size; + + if (!buf) { + *buflen = cvlen; + ret = 1; + goto end; + + } else if (*buflen < cvlen) { + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_ENCODE, EC_R_BUFFER_TOO_SMALL); + goto end; + } + + if (!(ptlen = EC_POINT_point2oct(ec_group, cv->ephem_point, + params->point_form, buf, *buflen, bn_ctx))) { + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_ENCODE, EC_R_POINT2OCT_FAILED); + goto end; + } + buf += ptlen; + memcpy(buf, cv->ciphertext, cv->ciphertext_size); + buf += cv->ciphertext_size; + if (cv->mactag_size > 0) { + memcpy(buf, cv->mactag, cv->mactag_size); + } + + *buflen = cvlen; + ret = 1; +end: + if (bn_ctx) BN_CTX_free(bn_ctx); + return ret; +} + +SM2_CIPHERTEXT_VALUE *SM2_CIPHERTEXT_VALUE_decode( + const EC_GROUP *ec_group, const SM2_ENC_PARAMS *params, + const unsigned char *buf, size_t buflen) +{ + int ok = 0; + SM2_CIPHERTEXT_VALUE *ret = NULL; + BN_CTX *bn_ctx = BN_CTX_new(); + int ptlen; + int fixlen; + + if (!bn_ctx) { + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_DECODE, ERR_R_BN_LIB); + return NULL; + } + + if (!(fixlen = SM2_CIPHERTEXT_VALUE_size(ec_group, params, 0))) { + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_DECODE, EC_R_GET_CIPHERTEXT_SIZE_FAILED); + goto end; + } + + if (buflen <= fixlen) { + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_DECODE, EC_R_BUFFER_TOO_SMALL); + goto end; + } + + if (!(ret = OPENSSL_malloc(sizeof(SM2_CIPHERTEXT_VALUE)))) { + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_DECODE, EC_R_MALLOC_FAILED); + goto end; + } + + ret->ephem_point = EC_POINT_new(ec_group); + ret->ciphertext_size = buflen - fixlen; + ret->ciphertext = OPENSSL_malloc(ret->ciphertext_size); + if (!ret->ephem_point || !ret->ciphertext) { + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_DECODE, EC_R_INNOR_ERROR); + goto end; + } + +#if 0 + //FIXME + ptlen = fixlen - SM2_ENC_PARAMS_mactag_size(params); +#endif + ptlen = fixlen; //FIXME + if (!EC_POINT_oct2point(ec_group, ret->ephem_point, buf, ptlen, bn_ctx)) { + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_DECODE, EC_R_OCT2POINT_FAILED); + goto end; + } + + memcpy(ret->ciphertext, buf + ptlen, ret->ciphertext_size); + //FIXME + //ret->mactag_size = SM2_ENC_PARAMS_mactag_size(params); + if (ret->mactag_size > 0) { + memcpy(ret->mactag, buf + buflen - ret->mactag_size, ret->mactag_size); + } + ok = 1; + +end: + if (!ok && ret) { + SM2_CIPHERTEXT_VALUE_free(ret); + ret = NULL; + } + if (bn_ctx) BN_CTX_free(bn_ctx); + + return ret; +} + +int SM2_CIPHERTEXT_VALUE_print(BIO *out, const EC_GROUP *ec_group, + const SM2_CIPHERTEXT_VALUE *cv, int indent, unsigned long flags) +{ + int ret = 0; + char *hex = NULL; + BN_CTX *ctx = BN_CTX_new(); + int i; + + if (!ctx) { + goto end; + } + + if (!(hex = EC_POINT_point2hex(ec_group, cv->ephem_point, + POINT_CONVERSION_UNCOMPRESSED, ctx))) { + goto end; + } + + BIO_printf(out, "SM2_CIPHERTEXT_VALUE.ephem_point: %s\n", hex); + BIO_printf(out, "SM2_CIPHERTEXT_VALUE.ciphertext : "); + for (i = 0; i < cv->ciphertext_size; i++) { + BIO_printf(out, "%02X", cv->ciphertext[i]); + } + BIO_printf(out, "\n"); + BIO_printf(out, "SM2_CIPHERTEXT_VALUE.mactag :"); + for (i = 0; i < cv->mactag_size; i++) { + BIO_printf(out, "%02X", cv->mactag[i]); + } + BIO_printf(out, "\n"); + + ret = 1; + +end: + OPENSSL_free(hex); + BN_CTX_free(ctx); + return 0; +} + +int SM2_encrypt(const SM2_ENC_PARAMS *params, + const unsigned char *in, size_t inlen, + unsigned char *out, size_t *outlen, + EC_KEY *ec_key) +{ + int ret = 0; + const EC_GROUP *ec_group = EC_KEY_get0_group(ec_key); + SM2_CIPHERTEXT_VALUE *cv = NULL; + int len; + + if (!(len = SM2_CIPHERTEXT_VALUE_size(ec_group, params, inlen))) { + ECerr(EC_F_SM2_ENCRYPT, EC_R_ERROR); + goto end; + } + + if (!out) { + *outlen = (size_t)len; + return 1; + + } else if (*outlen < (size_t)len) { + ECerr(EC_F_SM2_ENCRYPT, EC_R_BUFFER_TOO_SMALL); + return 0; + } + + if (!(cv = SM2_do_encrypt(params, in, inlen, ec_key))) { + ECerr(EC_F_SM2_ENCRYPT, EC_R_ENCRYPT_FAILED); + goto end; + } + + if (!SM2_CIPHERTEXT_VALUE_encode(cv, ec_group, params, out, outlen)) { + ECerr(EC_F_SM2_ENCRYPT, EC_R_CIPHERTEXT_ENCODE_FAILED); + goto end; + } + + ret = 1; +end: + if (cv) SM2_CIPHERTEXT_VALUE_free(cv); + return ret; +} + +SM2_CIPHERTEXT_VALUE *SM2_do_encrypt(const SM2_ENC_PARAMS *params, + const unsigned char *in, size_t inlen, + EC_KEY *ec_key) +{ + int ok = 0; + SM2_CIPHERTEXT_VALUE *cv = NULL; + const EC_GROUP *ec_group = EC_KEY_get0_group(ec_key); + const EC_POINT *pub_key = EC_KEY_get0_public_key(ec_key); + KDF_FUNC kdf = KDF_get_x9_63(params->kdf_md); + EC_POINT *point = NULL; + BIGNUM *n = NULL; + BIGNUM *h = NULL; + BIGNUM *k = NULL; + BN_CTX *bn_ctx = NULL; + EVP_MD_CTX *md_ctx = NULL; + unsigned char buf[(OPENSSL_ECC_MAX_FIELD_BITS + 7)/4 + 1]; + int nbytes; + unsigned char dgst[EVP_MAX_MD_SIZE]; + unsigned int dgstlen; + int mactag_size; + size_t len; + int i; + + if (!ec_group || !pub_key) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_INVALID_EC_KEY); + goto end; + } + if (!kdf) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_GET_KDF_FAILED); + goto end; + } + + /* init ciphertext_value */ + if (!(cv = OPENSSL_malloc(sizeof(SM2_CIPHERTEXT_VALUE)))) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_MALLOC_FAILED); + goto end; + } + memset(cv, 0, sizeof(*cv)); + cv->ephem_point = EC_POINT_new(ec_group); + cv->ciphertext = OPENSSL_malloc(inlen); + cv->ciphertext_size = inlen; + if (!cv->ephem_point || !cv->ciphertext) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_ERROR); + goto end; + } + + point = EC_POINT_new(ec_group); + n = BN_new(); + h = BN_new(); + k = BN_new(); + bn_ctx = BN_CTX_new(); + md_ctx = EVP_MD_CTX_create(); + if (!point || !n || !h || !k || !bn_ctx || !md_ctx) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_ERROR); + goto end; + } + + /* init ec domain parameters */ + if (!EC_GROUP_get_order(ec_group, n, bn_ctx)) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_ERROR); + goto end; + } + if (!EC_GROUP_get_cofactor(ec_group, h, bn_ctx)) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_ERROR); + goto end; + } + nbytes = (EC_GROUP_get_degree(ec_group) + 7) / 8; + + do + { + /* A1: rand k in [1, n-1] */ + do { + BN_rand_range(k, n); + } while (BN_is_zero(k)); + + + /* A2: C1 = [k]G = (x1, y1) */ + if (!EC_POINT_mul(ec_group, cv->ephem_point, k, NULL, NULL, bn_ctx)) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_ERROR); + goto end; + } + + /* A3: check [h]P_B != O */ + if (!EC_POINT_mul(ec_group, point, NULL, pub_key, h, bn_ctx)) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_ERROR); + goto end; + } + if (EC_POINT_is_at_infinity(ec_group, point)) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_ERROR); + goto end; + } + + /* A4: compute ECDH [k]P_B = (x2, y2) */ + if (!EC_POINT_mul(ec_group, point, NULL, pub_key, k, bn_ctx)) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_ERROR); + goto end; + } + if (!(len = EC_POINT_point2oct(ec_group, point, + POINT_CONVERSION_UNCOMPRESSED, buf, sizeof(buf), bn_ctx))) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_ERROR); + goto end; + } + OPENSSL_assert(len == nbytes * 2 + 1); + + /* A5: t = KDF(x2 || y2, klen) */ + kdf(buf + 1, len - 1, cv->ciphertext, &cv->ciphertext_size); + + for (i = 0; i < cv->ciphertext_size; i++) { + if (cv->ciphertext[i]) { + break; + } + } + if (i == cv->ciphertext_size) { + continue; + } + + break; + + } while (1); + + + /* A6: C2 = M xor t */ + for (i = 0; i < inlen; i++) { + cv->ciphertext[i] ^= in[i]; + } + + mactag_size = EVP_MD_size(params->mac_md); + if (mactag_size) { + + /* A7: C3 = Hash(x2 || M || y2) */ + if (!EVP_DigestInit_ex(md_ctx, params->mac_md, NULL)) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_ERROR); + goto end; + } + if (!EVP_DigestUpdate(md_ctx, buf + 1, nbytes)) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_ERROR); + goto end; + } + if (!EVP_DigestUpdate(md_ctx, in, inlen)) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_ERROR); + goto end; + } + if (!EVP_DigestUpdate(md_ctx, buf + 1 + nbytes, nbytes)) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_ERROR); + goto end; + } + if (!EVP_DigestFinal_ex(md_ctx, dgst, &dgstlen)) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_ERROR); + goto end; + } + + /* GmSSL specific: reduce mactag size */ + if (mactag_size > dgstlen) { + ECerr(EC_F_SM2_DO_ENCRYPT, EC_R_ERROR); + goto end; + } + + cv->mactag_size = mactag_size; + memcpy(cv->mactag, dgst, cv->mactag_size); + } + + ok = 1; + +end: + if (!ok && cv) { + SM2_CIPHERTEXT_VALUE_free(cv); + cv = NULL; + } + + if (point) EC_POINT_free(point); + if (n) BN_free(n); + if (h) BN_free(h); + if (k) BN_free(k); + if (bn_ctx) BN_CTX_free(bn_ctx); + if (md_ctx) EVP_MD_CTX_destroy(md_ctx); + + return cv; +} + +int SM2_decrypt(const SM2_ENC_PARAMS *params, + const unsigned char *in, size_t inlen, + unsigned char *out, size_t *outlen, + EC_KEY *ec_key) +{ + int ret = 0; + const EC_GROUP *ec_group = EC_KEY_get0_group(ec_key); + SM2_CIPHERTEXT_VALUE *cv = NULL; + int len; + + if (!(len = SM2_CIPHERTEXT_VALUE_size(ec_group, params, 0))) { + ECerr(EC_F_SM2_DECRYPT, EC_R_ERROR); + goto end; + } + if (inlen <= len) { + ECerr(EC_F_SM2_DECRYPT, EC_R_ERROR); + goto end; + } + + if (!out) { + *outlen = inlen - len; + return 1; + } else if (*outlen < inlen - len) { + ECerr(EC_F_SM2_DECRYPT, EC_R_ERROR); + return 0; + } + + if (!(cv = SM2_CIPHERTEXT_VALUE_decode(ec_group, params, in, inlen))) { + ECerr(EC_F_SM2_DECRYPT, EC_R_ERROR); + goto end; + } + if (!SM2_do_decrypt(params, cv, out, outlen, ec_key)) { + ECerr(EC_F_SM2_DECRYPT, EC_R_ERROR); + goto end; + } + + ret = 1; +end: + if (cv) SM2_CIPHERTEXT_VALUE_free(cv); + return ret; +} + +int SM2_do_decrypt(const SM2_ENC_PARAMS *params, + const SM2_CIPHERTEXT_VALUE *cv, + unsigned char *out, size_t *outlen, + EC_KEY *ec_key) +{ + int ret = 0; + const EC_GROUP *ec_group = EC_KEY_get0_group(ec_key); + const BIGNUM *pri_key = EC_KEY_get0_private_key(ec_key); + KDF_FUNC kdf = KDF_get_x9_63(params->kdf_md); + EC_POINT *point = NULL; + BIGNUM *n = NULL; + BIGNUM *h = NULL; + BN_CTX *bn_ctx = NULL; + EVP_MD_CTX *md_ctx = NULL; + unsigned char buf[(OPENSSL_ECC_MAX_FIELD_BITS + 7)/4 + 1]; + unsigned char mac[EVP_MAX_MD_SIZE]; + unsigned int maclen; + int mactag_size; + int nbytes; + size_t size; + int i; + + if (!ec_group || !pri_key) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + if (!kdf) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + + if (!out) { + *outlen = cv->ciphertext_size; + return 1; + } + if (*outlen < cv->ciphertext_size) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + + /* init vars */ + point = EC_POINT_new(ec_group); + n = BN_new(); + h = BN_new(); + bn_ctx = BN_CTX_new(); + md_ctx = EVP_MD_CTX_create(); + if (!point || !n || !h || !bn_ctx || !md_ctx) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + + /* init ec domain parameters */ + if (!EC_GROUP_get_order(ec_group, n, bn_ctx)) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + if (!EC_GROUP_get_cofactor(ec_group, h, bn_ctx)) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + nbytes = (EC_GROUP_get_degree(ec_group) + 7) / 8; + + /* B2: check [h]C1 != O */ + if (!EC_POINT_mul(ec_group, point, NULL, cv->ephem_point, h, bn_ctx)) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + if (EC_POINT_is_at_infinity(ec_group, point)) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + + /* B3: compute ECDH [d]C1 = (x2, y2) */ + if (!EC_POINT_mul(ec_group, point, NULL, cv->ephem_point, pri_key, bn_ctx)) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + if (!(size = EC_POINT_point2oct(ec_group, point, + POINT_CONVERSION_UNCOMPRESSED, buf, sizeof(buf), bn_ctx))) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + OPENSSL_assert(size == 1 + nbytes * 2); + + /* B4: compute t = KDF(x2 || y2, clen) */ + + *outlen = cv->ciphertext_size; //FIXME: duplicated code + kdf(buf + 1, size - 1, out, outlen); + + + /* B5: compute M = C2 xor t */ + for (i = 0; i < cv->ciphertext_size; i++) { + out[i] ^= cv->ciphertext[i]; + } + *outlen = cv->ciphertext_size; + + mactag_size = EVP_MD_size(params->mac_md); + if (mactag_size) { + + /* B6: check Hash(x2 || M || y2) == C3 */ + if (!EVP_DigestInit_ex(md_ctx, params->mac_md, NULL)) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + if (!EVP_DigestUpdate(md_ctx, buf + 1, nbytes)) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + if (!EVP_DigestUpdate(md_ctx, out, *outlen)) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + if (!EVP_DigestUpdate(md_ctx, buf + 1 + nbytes, nbytes)) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + if (!EVP_DigestFinal_ex(md_ctx, mac, &maclen)) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + + /* GmSSL specific */ + if (mactag_size > maclen) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + if (cv->mactag_size != mactag_size || + OPENSSL_memcmp(mac, cv->mactag, cv->mactag_size)) { + ECerr(EC_F_SM2_DO_DECRYPT, EC_R_ERROR); + goto end; + } + } + + ret = 1; +end: + EC_POINT_free(point); + BN_free(n); + BN_free(h); + BN_CTX_free(bn_ctx); + EVP_MD_CTX_destroy(md_ctx); + + return ret; +} + +int SM2_encrypt_with_recommended(const unsigned char *in, size_t inlen, + unsigned char *out, size_t *outlen, EC_KEY *ec_key) +{ + SM2_ENC_PARAMS params; + SM2_ENC_PARAMS_init_with_recommended(¶ms); + return SM2_encrypt(¶ms, in, inlen, out, outlen, ec_key); +} + +int SM2_decrypt_with_recommended(const unsigned char *in, size_t inlen, + unsigned char *out, size_t *outlen, + EC_KEY *ec_key) +{ + SM2_ENC_PARAMS params; + SM2_ENC_PARAMS_init_with_recommended(¶ms); + return SM2_decrypt(¶ms, in, inlen, out, outlen, ec_key); +} + diff --git a/crypto/sm2/sm2_id.c b/crypto/sm2/sm2_id.c new file mode 100644 index 00000000..8fdd0701 --- /dev/null +++ b/crypto/sm2/sm2_id.c @@ -0,0 +1,343 @@ +/* ==================================================================== + * Copyright (c) 2015 - 2016 The GmSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED 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 GmSSL PROJECT OR + * ITS CONTRIBUTORS 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. + * ==================================================================== + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EC_MAX_NBYTES ((OPENSSL_ECC_MAX_FIELD_BITS + 7)/8) + + +int SM2_get_public_key_data(EC_KEY *ec_key, unsigned char *out, size_t *outlen) +{ + int ret = 0; + const EC_GROUP *group; + BN_CTX *bn_ctx = NULL; + BIGNUM *p = NULL; + BIGNUM *x = NULL; + BIGNUM *y = NULL; + int nbytes; + size_t len; + + if (!ec_key || !outlen) { + ECerr(EC_F_SM2_GET_PUBLIC_KEY_DATA, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if (!(group = EC_KEY_get0_group(ec_key))) { + ECerr(EC_F_SM2_GET_PUBLIC_KEY_DATA, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + /* degree is the bit length of field element, not the order of subgroup */ + nbytes = (EC_GROUP_get_degree(group) + 7)/8; + len = nbytes * 6; + + if (!out) { + *outlen = len; + return 1; + } + if (*outlen < len) { + ECerr(EC_F_SM2_GET_PUBLIC_KEY_DATA, EC_R_BUFFER_TOO_SMALL); + return 0; + } + + memset(out, 0, len); + + p = BN_new(); + x = BN_new(); + y = BN_new(); + bn_ctx = BN_CTX_new(); + if (!bn_ctx || !p || !x || !y) { + ECerr(EC_F_SM2_GET_PUBLIC_KEY_DATA, ERR_R_MALLOC_FAILURE); + goto end; + } + + /* get curve coefficients */ + if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) { + if (!EC_GROUP_get_curve_GFp(group, p, x, y, bn_ctx)) { + ECerr(EC_F_SM2_GET_PUBLIC_KEY_DATA, ERR_R_EC_LIB); + goto end; + } + } else { + if (!EC_GROUP_get_curve_GF2m(group, p, x, y, bn_ctx)) { + ECerr(EC_F_SM2_GET_PUBLIC_KEY_DATA, ERR_R_EC_LIB); + goto end; + } + } + + BN_bn2bin(x, out + nbytes - BN_num_bytes(x)); + out += nbytes; + + BN_bn2bin(y, out + nbytes - BN_num_bytes(y)); + out += nbytes; + + /* get curve generator coordinates */ + if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) { + if (!EC_POINT_get_affine_coordinates_GFp(group, + EC_GROUP_get0_generator(group), x, y, bn_ctx)) { + ECerr(EC_F_SM2_GET_PUBLIC_KEY_DATA, ERR_R_EC_LIB); + goto end; + } + } else { + if (!EC_POINT_get_affine_coordinates_GF2m(group, + EC_GROUP_get0_generator(group), x, y, bn_ctx)) { + ECerr(EC_F_SM2_GET_PUBLIC_KEY_DATA, ERR_R_EC_LIB); + goto end; + } + } + + if (!BN_bn2bin(x, out + nbytes - BN_num_bytes(x))) { + ECerr(EC_F_SM2_GET_PUBLIC_KEY_DATA, ERR_R_BN_LIB); + goto end; + } + out += nbytes; + + if (!BN_bn2bin(y, out + nbytes - BN_num_bytes(y))) { + ECerr(EC_F_SM2_GET_PUBLIC_KEY_DATA, ERR_R_BN_LIB); + goto end; + } + out += nbytes; + + + /* get pub_key coorindates */ + if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) { + if (!EC_POINT_get_affine_coordinates_GFp(group, + EC_KEY_get0_public_key(ec_key), x, y, bn_ctx)) { + ECerr(EC_F_SM2_GET_PUBLIC_KEY_DATA, ERR_R_EC_LIB); + goto end; + } + } else { + if (!EC_POINT_get_affine_coordinates_GF2m(group, + EC_KEY_get0_public_key(ec_key), x, y, bn_ctx)) { + ECerr(EC_F_SM2_GET_PUBLIC_KEY_DATA, ERR_R_EC_LIB); + goto end; + } + } + + if (!BN_bn2bin(x, out + nbytes - BN_num_bytes(x))) { + ECerr(EC_F_SM2_GET_PUBLIC_KEY_DATA, ERR_R_BN_LIB); + goto end; + } + out += nbytes; + + if (!BN_bn2bin(y, out + nbytes - BN_num_bytes(y))) { + ECerr(EC_F_SM2_GET_PUBLIC_KEY_DATA, ERR_R_BN_LIB); + goto end; + } + + *outlen = len; + ret = 1; + +end: + BN_free(p); + BN_free(x); + BN_free(y); + BN_CTX_free(bn_ctx); + return ret; +} + +int SM2_compute_id_digest(const EVP_MD *md, const char *id, size_t idlen, + unsigned char *out, size_t *outlen, EC_KEY *ec_key) +{ + int ret = 0; + EVP_MD_CTX *md_ctx = NULL; + unsigned char idbits[2]; + unsigned char buf[SM2_MAX_PKEY_DATA_LENGTH]; + unsigned int len; + size_t size; + + if (!md || !id || idlen <= 0 || !outlen || !ec_key) { + ECerr(EC_F_SM2_COMPUTE_ID_DIGEST, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + /* + * check compatibility with the GM/T 0003.2-2012 standard + * digest length must be 256-bit/32-byte + * id length should be less than SM2_MAX_ID_LENGTH + */ + if (EVP_MD_size(md) != SM2_ID_DIGEST_LENGTH) { + ECerr(EC_F_SM2_COMPUTE_ID_DIGEST, EC_R_INVALID_DIGEST_ALGOR); + return 0; + } + if (strlen(id) != idlen) { + ECerr(EC_F_SM2_COMPUTE_ID_DIGEST, EC_R_INVALID_SM2_ID); + return 0; + } + if (idlen > SM2_MAX_ID_LENGTH || idlen <= 0) { + ECerr(EC_F_SM2_COMPUTE_ID_DIGEST, EC_R_INVALID_ID_LENGTH); + return 0; + } + + if (!out) { + *outlen = EVP_MD_size(md); + return 1; + } + if (*outlen < EVP_MD_size(md)) { + ECerr(EC_F_SM2_COMPUTE_ID_DIGEST, EC_R_BUFFER_TOO_SMALL); + return 0; + } + + /* prepare */ + if (!(md_ctx = EVP_MD_CTX_new())) { + ECerr(EC_F_SM2_COMPUTE_ID_DIGEST, ERR_R_MALLOC_FAILURE); + return 0; + } + + /* get public key data from ec_key */ + size = sizeof(buf); + if (!SM2_get_public_key_data(ec_key, buf, &size)) { + ECerr(EC_F_SM2_COMPUTE_ID_DIGEST, EC_R_GET_PUBLIC_KEY_DATA_FAILURE); + goto end; + } + + /* 2-byte id length in bits */ + idbits[0] = ((idlen * 8) >> 8) % 256; + idbits[1] = (idlen * 8) % 256; + + /* compute digest of (idbits, id, pkeydata) */ + if (!EVP_DigestInit_ex(md_ctx, md, NULL)) { + ECerr(EC_F_SM2_COMPUTE_ID_DIGEST, ERR_R_EVP_LIB); + goto end; + } + if (!EVP_DigestUpdate(md_ctx, idbits, sizeof(idbits))) { + ECerr(EC_F_SM2_COMPUTE_ID_DIGEST, ERR_R_EVP_LIB); + goto end; + } + if (!EVP_DigestUpdate(md_ctx, id, idlen)) { + ECerr(EC_F_SM2_COMPUTE_ID_DIGEST, ERR_R_EVP_LIB); + goto end; + } + if (!EVP_DigestUpdate(md_ctx, buf, size)) { + ECerr(EC_F_SM2_COMPUTE_ID_DIGEST, ERR_R_EVP_LIB); + goto end; + } + len = EVP_MD_size(md); + if (!EVP_DigestFinal_ex(md_ctx, out, &len)) { + ECerr(EC_F_SM2_COMPUTE_ID_DIGEST, ERR_R_EVP_LIB); + goto end; + } + + *outlen = len; + ret = 1; + +end: + EVP_MD_CTX_free(md_ctx); + return ret; +} + +/* + * Generate GM/T 0003.2-2012 message digest for SM2 signature scheme. + * Return dgst = msg_md( id_md(id, ec_key) || msg ) + */ +int SM2_compute_message_digest(const EVP_MD *id_md, const EVP_MD *msg_md, + const unsigned char *msg, size_t msglen, const char *id, size_t idlen, + unsigned char *out, size_t *outlen, + EC_KEY *ec_key) +{ + int ret = 0; + EVP_MD_CTX *md_ctx; + unsigned char buf[EVP_MAX_MD_SIZE]; + size_t len; + + if (!id_md || !msg_md || !msg || msglen <= 0 || !id || idlen <= 0 || !ec_key) { + ECerr(EC_F_SM2_COMPUTE_MESSAGE_DIGEST, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (!(md_ctx = EVP_MD_CTX_new())) { + ECerr(EC_F_SM2_COMPUTE_MESSAGE_DIGEST, ERR_R_MALLOC_FAILURE); + return 0; + } + + len = sizeof(buf); + if (!SM2_compute_id_digest(id_md, id, idlen, buf, &len, ec_key)) { + ECerr(EC_F_SM2_COMPUTE_MESSAGE_DIGEST, ERR_R_EC_LIB); + goto end; + } + + if (!EVP_DigestInit_ex(md_ctx, msg_md, NULL)) { + ECerr(EC_F_SM2_COMPUTE_MESSAGE_DIGEST, ERR_R_EVP_LIB); + goto end; + } + if (!EVP_DigestUpdate(md_ctx, buf, len)) { + ECerr(EC_F_SM2_COMPUTE_MESSAGE_DIGEST, ERR_R_EVP_LIB); + goto end; + } + printf("zid(%d)=", len); for (int i=0; i +#include +#include +#include + +int SM2_KAP_CTX_init(SM2_KAP_CTX *ctx, + EC_KEY *ec_key, const char *id, size_t idlen, + EC_KEY *remote_pubkey, const char *rid, size_t ridlen, + int is_initiator, int do_checksum) +{ + int ret = 0; + int w; + + if (!ctx || !ec_key || !remote_pubkey) { + ECerr(EC_F_SM2_KAP_CTX_INIT, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + memset(ctx, 0, sizeof(*ctx)); + + ctx->id_dgst_md = EVP_sm3(); + ctx->kdf_md = EVP_sm3(); + ctx->checksum_md = EVP_sm3(); + ctx->point_form = SM2_DEFAULT_POINT_CONVERSION_FORM; + + if (!(ctx->kdf = KDF_get_x9_63(ctx->kdf_md))) { + ECerr(EC_F_SM2_KAP_CTX_INIT, EC_R_INVALID_KDF_MD); + goto end; + } + + ctx->is_initiator = is_initiator; + ctx->do_checksum = do_checksum; + + if (EC_GROUP_cmp(EC_KEY_get0_group(ec_key), + EC_KEY_get0_group(remote_pubkey), NULL) != 0) { + ECerr(EC_F_SM2_KAP_CTX_INIT, 0); + goto end; + } + + if (!SM2_compute_id_digest(ctx->id_dgst_md, id, idlen, + ctx->id_dgst, &ctx->id_dgstlen, ec_key)) { + ECerr(EC_F_SM2_KAP_CTX_INIT, 0); + goto end; + } + + if (!(ctx->ec_key = EC_KEY_dup(ec_key))) { + ECerr(EC_F_SM2_KAP_CTX_INIT, ERR_R_EC_LIB); + goto end; + } + + if (!SM2_compute_id_digest(ctx->id_dgst_md, rid, ridlen, + ctx->remote_id_dgst, &ctx->remote_id_dgstlen, remote_pubkey)) { + ECerr(EC_F_SM2_KAP_CTX_INIT, 0); + goto end; + } + + if (!(ctx->remote_pubkey = EC_KEY_dup(remote_pubkey))) { + ECerr(EC_F_SM2_KAP_CTX_INIT, 0); + goto end; + } + + ctx->group = EC_KEY_get0_group(ec_key); + ctx->bn_ctx = BN_CTX_new(); + ctx->order = BN_new(); + ctx->two_pow_w = BN_new(); + ctx->t = BN_new(); + + if (!ctx->bn_ctx || !ctx->order || !ctx->two_pow_w || !ctx->t) { + ECerr(EC_F_SM2_KAP_CTX_INIT, ERR_R_BN_LIB); + goto end; + } + + if (!EC_GROUP_get_order(EC_KEY_get0_group(ec_key), ctx->order, ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_CTX_INIT, ERR_R_EC_LIB); + goto end; + } + + w = (BN_num_bits(ctx->order) + 1)/2 - 1; + + if (!BN_one(ctx->two_pow_w)) { + ECerr(EC_F_SM2_KAP_CTX_INIT, ERR_R_BN_LIB); + goto end; + } + + if (!BN_lshift(ctx->two_pow_w, ctx->two_pow_w, w)) { + ECerr(EC_F_SM2_KAP_CTX_INIT, ERR_R_BN_LIB); + goto end; + } + + if (!(ctx->point = EC_POINT_new(ctx->group))) { + ECerr(EC_F_SM2_KAP_CTX_INIT, ERR_R_EC_LIB); + goto end; + } + + ret = 1; + +end: + if (!ret) SM2_KAP_CTX_cleanup(ctx); + return ret; +} + +void SM2_KAP_CTX_cleanup(SM2_KAP_CTX *ctx) +{ + if (ctx) { + EC_KEY_free(ctx->ec_key); + EC_KEY_free(ctx->remote_pubkey); + BN_CTX_free(ctx->bn_ctx); + BN_free(ctx->two_pow_w); + BN_free(ctx->order); + EC_POINT_free(ctx->point); + BN_free(ctx->t); + memset(ctx, 0, sizeof(*ctx)); + } +} + +/* FIXME: ephem_point_len should be both input and output */ +int SM2_KAP_prepare(SM2_KAP_CTX *ctx, unsigned char *ephem_point, + size_t *ephem_point_len) +{ + int ret = 0; + const BIGNUM *prikey; + BIGNUM *h = NULL; + BIGNUM *r = NULL; + BIGNUM *x = NULL; + + if (!(prikey = EC_KEY_get0_private_key(ctx->ec_key))) { + ECerr(EC_F_SM2_KAP_PREPARE, EC_R_SM2_KAP_NOT_INITED); + return 0; + } + + h = BN_new(); + r = BN_new(); + x = BN_new(); + + if (!h || !r || !x) { + ECerr(EC_F_SM2_KAP_PREPARE, 0); + goto end; + } + + /* + * r = rand(1, n) + * R = rG = (x, y) + */ + + do { + if (!BN_rand_range(r, ctx->order)) { + ECerr(EC_F_SM2_KAP_PREPARE, EC_R_RANDOM_NUMBER_GENERATION_FAILED); + goto end; + } + + } while (BN_is_zero(r)); + + + if (!EC_POINT_mul(ctx->group, ctx->point, r, NULL, NULL, ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_PREPARE, ERR_R_EC_LIB); + goto end; + } + + + if (EC_METHOD_get_field_type(EC_GROUP_method_of(ctx->group)) == NID_X9_62_prime_field) { + if (!EC_POINT_get_affine_coordinates_GFp(ctx->group, ctx->point, x, NULL, ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_PREPARE, ERR_R_EC_LIB); + goto end; + } + } else { + if (!EC_POINT_get_affine_coordinates_GF2m(ctx->group, ctx->point, x, NULL, ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_PREPARE, ERR_R_EC_LIB); + goto end; + } + } + + /* + * w = ceil(keybits / 2) - 1 + * x = 2^w + (x and (2^w - 1)) = 2^w + (x mod 2^w) + * t = (d + x * r) mod n + * t = (h * t) mod n + */ + + if (!ctx->t) { + ECerr(EC_F_SM2_KAP_PREPARE, EC_R_SM2_KAP_NOT_INITED); + goto end; + } + + if (!BN_nnmod(x, x, ctx->two_pow_w, ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_PREPARE, ERR_R_BN_LIB); + goto end; + } + + if (!BN_add(x, x, ctx->two_pow_w)) { + ECerr(EC_F_SM2_KAP_PREPARE, ERR_R_BN_LIB); + goto end; + } + + if (!BN_mod_mul(ctx->t, x, r, ctx->order, ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_PREPARE, ERR_R_BN_LIB); + goto end; + } + + if (!BN_mod_add(ctx->t, ctx->t, prikey, ctx->order, ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_PREPARE, ERR_R_BN_LIB); + goto end; + } + + if (!EC_GROUP_get_cofactor(ctx->group, h, ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_PREPARE, ERR_R_EC_LIB); + goto end; + } + + if (!BN_mul(ctx->t, ctx->t, h, ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_PREPARE, ERR_R_BN_LIB); + goto end; + } + + /* encode R = (x, y) for output and local buffer */ + + // FIXME: ret is size_t and ret is the output length + ret = EC_POINT_point2oct(ctx->group, ctx->point, ctx->point_form, + ephem_point, *ephem_point_len, ctx->bn_ctx); + + memcpy(ctx->pt_buf, ephem_point, ret); + *ephem_point_len = ret; + ret = 1; + +end: + if (h) BN_free(h); + if (r) BN_free(r); + if (x) BN_free(x); + + return ret; +} + +int SM2_KAP_compute_key(SM2_KAP_CTX *ctx, const unsigned char *remote_point, + size_t remote_point_len, unsigned char *key, size_t keylen, + unsigned char *checksum, size_t *checksumlen) +{ + int ret = 0; + + EVP_MD_CTX *md_ctx = NULL; + BIGNUM *x = NULL; + unsigned char share_pt_buf[1 + (OPENSSL_ECC_MAX_FIELD_BITS+7)/4 + EVP_MAX_MD_SIZE * 2 + 100]; + unsigned char remote_pt_buf[1 + (OPENSSL_ECC_MAX_FIELD_BITS+7)/4 + 111]; + unsigned char dgst[EVP_MAX_MD_SIZE]; + unsigned int dgstlen; + unsigned int len, bnlen; + size_t klen = keylen; + + md_ctx = EVP_MD_CTX_new(); + x = BN_new(); + if (!md_ctx || !x) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, 0); + goto end; + } + + /* + * decode point R = (x, y), encode (x, y) + * x = 2^w + (x and (2^w - 1)) = 2^w + (x mod 2^w), w = ceil(keybits / 2) - 1 + * U = ht * (P + x * R) + * check U != O + */ + + if (!EC_POINT_oct2point(ctx->group, ctx->point, + remote_point, remote_point_len, ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, 0); + goto end; + } + + if (!(len = EC_POINT_point2oct(ctx->group, ctx->point, POINT_CONVERSION_UNCOMPRESSED, + remote_pt_buf, sizeof(remote_pt_buf), ctx->bn_ctx))) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, 0); + goto end; + } + + if (EC_METHOD_get_field_type(EC_GROUP_method_of(ctx->group)) == NID_X9_62_prime_field) { + if (!EC_POINT_get_affine_coordinates_GFp(ctx->group, ctx->point, x, NULL, ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EC_LIB); + goto end; + } + } else { + if (!EC_POINT_get_affine_coordinates_GF2m(ctx->group, ctx->point, x, NULL, ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EC_LIB); + goto end; + } + } + + /* x = 2^w + (x and (2^w - 1)) = 2^w + (x mod 2^w) */ + + if (!BN_nnmod(x, x, ctx->two_pow_w, ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_BN_LIB); + goto end; + } + + if (!BN_add(x, x, ctx->two_pow_w)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_BN_LIB); + goto end; + } + + /* + if (!BN_mod_mul(x, x, ctx->t, ctx->order, ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_BN_LIB); + goto end; + } + */ + + /* U = ht * (P + x * R), check U != O */ + + if (!EC_POINT_mul(ctx->group, ctx->point, NULL, ctx->point, x, ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EC_LIB); + goto end; + } + + if (!EC_POINT_add(ctx->group, ctx->point, ctx->point, + EC_KEY_get0_public_key(ctx->remote_pubkey), ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EC_LIB); + goto end; + } + + if (!EC_POINT_mul(ctx->group, ctx->point, NULL, ctx->point, ctx->t, ctx->bn_ctx)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EC_LIB); + goto end; + } + + if (EC_POINT_is_at_infinity(ctx->group, ctx->point)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, 0); + goto end; + } + + /* encode U, append with ZA, ZB */ + + if (!(len = EC_POINT_point2oct(ctx->group, ctx->point, POINT_CONVERSION_UNCOMPRESSED, + share_pt_buf, sizeof(share_pt_buf), ctx->bn_ctx))) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, 0); + goto end; + } + + if (ctx->is_initiator) { + memcpy(share_pt_buf + len, ctx->id_dgst, ctx->id_dgstlen); + len += ctx->id_dgstlen; + memcpy(share_pt_buf + len, ctx->remote_id_dgst, ctx->remote_id_dgstlen); + len += ctx->remote_id_dgstlen; + } else { + memcpy(share_pt_buf + len, ctx->remote_id_dgst, ctx->remote_id_dgstlen); + len += ctx->remote_id_dgstlen; + memcpy(share_pt_buf + len, ctx->id_dgst, ctx->id_dgstlen); + len += ctx->id_dgstlen; + } + + /* key = KDF(xu, yu, ZA, ZB) */ + + + if (!ctx->kdf(share_pt_buf + 1, len - 1, key, &klen)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, 0); + goto end; + } + + if (ctx->do_checksum) { + + /* generate checksum S1 or SB start with 0x02 + * S1 = SB = Hash(0x02, yu, Hash(xu, ZA, ZB, x1, y1, x2, y2)) + */ + if (!EVP_DigestInit_ex(md_ctx, ctx->checksum_md, NULL)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + + bnlen = BN_num_bytes(ctx->order); + + if (!EVP_DigestUpdate(md_ctx, share_pt_buf + 1, bnlen)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + + if (ctx->is_initiator) { + + /* update ZA,ZB,x1,y1,x2,y2 */ + if (!EVP_DigestUpdate(md_ctx, ctx->id_dgst, ctx->id_dgstlen)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + if (!EVP_DigestUpdate(md_ctx, ctx->remote_id_dgst, ctx->remote_id_dgstlen)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + if (!EVP_DigestUpdate(md_ctx, ctx->pt_buf + 1, bnlen * 2)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + if (!EVP_DigestUpdate(md_ctx, remote_pt_buf + 1, bnlen * 2)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + + } else { + + if (!EVP_DigestUpdate(md_ctx, ctx->remote_id_dgst, ctx->remote_id_dgstlen)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + if (!EVP_DigestUpdate(md_ctx, ctx->id_dgst, ctx->id_dgstlen)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + if (!EVP_DigestUpdate(md_ctx, remote_pt_buf + 1, bnlen * 2)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + if (!EVP_DigestUpdate(md_ctx, ctx->pt_buf + 1, bnlen * 2)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + } + + if (!EVP_DigestFinal_ex(md_ctx, dgst, &dgstlen)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + /* now dgst == H(xu,ZA,ZB,x1,y1,x2,y2) + */ + + /* S1 = SB = Hash(0x02, yu, dgst) */ + + if (!EVP_DigestInit_ex(md_ctx, ctx->checksum_md, NULL)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + + if (!EVP_DigestUpdate(md_ctx, "\x02", 1)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + + if (!EVP_DigestUpdate(md_ctx, share_pt_buf + 1 + bnlen, bnlen)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + + if (!EVP_DigestUpdate(md_ctx, dgst, dgstlen)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + + /* output S1 to local buffer or SB to output */ + if (ctx->is_initiator) { + if (!EVP_DigestFinal_ex(md_ctx, ctx->checksum, &len)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + + } else { + if (!EVP_DigestFinal_ex(md_ctx, checksum, &len)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + *checksumlen = len; + } + + /* generate checksum SA or S2 start with 0x03 + * SA = S2 = Hash(0x03, yu, dgst) + */ + + if (!EVP_DigestInit_ex(md_ctx, ctx->checksum_md, NULL)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + + if (!EVP_DigestUpdate(md_ctx, "\x03", 1)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + + if (!EVP_DigestUpdate(md_ctx, share_pt_buf + 1 + bnlen, bnlen)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + + if (!EVP_DigestUpdate(md_ctx, dgst, dgstlen)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + + if (ctx->is_initiator) { + if (!EVP_DigestFinal_ex(md_ctx, checksum, &len)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + *checksumlen = len; + + } else { + if (!EVP_DigestFinal_ex(md_ctx, ctx->checksum, &len)) { + ECerr(EC_F_SM2_KAP_COMPUTE_KEY, ERR_R_EVP_LIB); + goto end; + } + } + + + } + + ret = 1; + +end: + EVP_MD_CTX_free(md_ctx); + BN_free(x); + return ret; +} + +int SM2_KAP_final_check(SM2_KAP_CTX *ctx, const unsigned char *checksum, + size_t checksumlen) +{ + if (ctx->do_checksum) { + if (checksumlen != EVP_MD_size(ctx->checksum_md)) { + ECerr(EC_F_SM2_KAP_FINAL_CHECK, EC_R_INVALID_SM2_KAP_CHECKSUM_LENGTH); + return 0; + } + if (memcmp(ctx->checksum, checksum, checksumlen)) { + ECerr(EC_F_SM2_KAP_FINAL_CHECK, EC_R_INVALID_SM2_KAP_CHECKSUM_VALUE); + return 0; + } + } + + return 1; +} + +int SM2_compute_key(void *out, size_t outlen, + const EC_POINT *pub_key, EC_KEY *ecdh, + const EC_POINT *pub_key2, EC_KEY *ec_key2, + const char *id1, const char *id2, int is_ini) +{ + return 0; +} + + diff --git a/crypto/sm2/sm2_kmeth.c b/crypto/sm2/sm2_kmeth.c new file mode 100644 index 00000000..a54d98f2 --- /dev/null +++ b/crypto/sm2/sm2_kmeth.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2016 The GmSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED 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 GmSSL PROJECT OR + * ITS CONTRIBUTORS 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. + */ + +#include +#include +#include +#include +#include +#include +#include "../ec/ec_lcl.h" + +#define SM2_KMETH_FLAGS 0 + +int SM2_ENC_PARAMS_set_type(SM2_ENC_PARAMS *params, int type) +{ + // FIXME: + ECerr(EC_F_SM2_ENC_PARAMS_SET_TYPE, ERR_R_EVP_LIB); + return 0; +} + +SM2_CIPHERTEXT_VALUE *SM2_CIPHERTEXT_VALUE_new_from_ECIES_CIPHERTEXT_VALUE( + const ECIES_CIPHERTEXT_VALUE *in) +{ + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_NEW_FROM_ECIES_CIPHERTEXT_VALUE, + ERR_R_EC_LIB); + return NULL; +} + +int SM2_CIPHERTEXT_VALUE_set_ECIES_CIPHERTEXT_VALUE(SM2_CIPHERTEXT_VALUE *sm2, + const ECIES_CIPHERTEXT_VALUE *in) +{ + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_SET_ECIES_CIPHERTEXT_VALUE, + ERR_R_EC_LIB); + return 0; +} + +int SM2_CIPHERTEXT_VALUE_get_ECIES_CIPHERTEXT_VALUE( + const SM2_CIPHERTEXT_VALUE *sm2, ECIES_CIPHERTEXT_VALUE *out) +{ + ECerr(EC_F_SM2_CIPHERTEXT_VALUE_GET_ECIES_CIPHERTEXT_VALUE, + ERR_R_EC_LIB); + return 0; +} + +static int sm2_compute_key(unsigned char **Pout, size_t *poutlen, + const EC_POINT *pub_key, const EC_KEY *ec_key) +{ + return 0; +} + +static int sm2_encrypt(int type, const unsigned char *in, size_t inlen, + unsigned char *out, size_t *outlen, EC_KEY *ec_key) +{ + SM2_ENC_PARAMS param; + if (!SM2_ENC_PARAMS_set_type(¶m, type)) { + return 0; + } + return SM2_encrypt(¶m, in, inlen, out, outlen, ec_key); +} + +ECIES_CIPHERTEXT_VALUE *sm2_do_encrypt(int type, const unsigned char *in, + size_t inlen, EC_KEY *ec_key) +{ + ECIES_CIPHERTEXT_VALUE *ret = NULL; + ECIES_CIPHERTEXT_VALUE *ecies = NULL; + SM2_CIPHERTEXT_VALUE *sm2 = NULL; + SM2_ENC_PARAMS param; + + if (!(ecies = ECIES_CIPHERTEXT_VALUE_new())) { + goto end; + } + if (!SM2_ENC_PARAMS_set_type(¶m, type)) { + goto end; + } + if (!(sm2 = SM2_do_encrypt(¶m, in, inlen, ec_key))) { + goto end; + } + if (!SM2_CIPHERTEXT_VALUE_get_ECIES_CIPHERTEXT_VALUE(sm2, ecies)) { + goto end; + } + + ret = ecies; + ecies = NULL; + +end: + ECIES_CIPHERTEXT_VALUE_free(ecies); + SM2_CIPHERTEXT_VALUE_free(sm2); + return ret; +} + +int sm2_decrypt(int type, const unsigned char *in, size_t inlen, + unsigned char *out, size_t *outlen, EC_KEY *ec_key) +{ + SM2_ENC_PARAMS param; + if (!SM2_ENC_PARAMS_set_type(¶m, type)) { + return 0; + } + return SM2_decrypt(¶m, in, inlen, out, outlen, ec_key); +} + +int sm2_do_decrypt(int type, const ECIES_CIPHERTEXT_VALUE *in, + unsigned char *out, size_t *outlen, EC_KEY *ec_key) +{ + int ret = 0; + SM2_CIPHERTEXT_VALUE *sm2 = NULL; + SM2_ENC_PARAMS param; + + if (!SM2_ENC_PARAMS_set_type(¶m, type)) { + goto end; + } + // we might require type/param + if (!(sm2 = SM2_CIPHERTEXT_VALUE_new_from_ECIES_CIPHERTEXT_VALUE(in))) { + goto end; + } + if (!SM2_do_decrypt(¶m, sm2, out, outlen, ec_key)) { + goto end; + } + + ret = 1; +end: + SM2_CIPHERTEXT_VALUE_free(sm2); + return ret; +} + +static const EC_KEY_METHOD gmssl_ec_key_method = { + "GmSSL EC_KEY method", + 0, + 0,0,0,0,0,0, + ossl_ec_key_gen, + sm2_compute_key, + SM2_sign, + SM2_sign_setup, + SM2_do_sign, + SM2_verify, + SM2_do_verify, + sm2_encrypt, + sm2_do_encrypt, + sm2_decrypt, + sm2_do_decrypt, +}; + +const EC_KEY_METHOD *EC_KEY_GmSSL(void) +{ + return &gmssl_ec_key_method; +} + diff --git a/crypto/sm2/sm2_sign.c b/crypto/sm2/sm2_sign.c new file mode 100644 index 00000000..db50f025 --- /dev/null +++ b/crypto/sm2/sm2_sign.c @@ -0,0 +1,526 @@ +/* ==================================================================== + * Copyright (c) 2015 - 2016 The GmSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED 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 GmSSL PROJECT OR + * ITS CONTRIBUTORS 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. + * ==================================================================== + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../ec/ec_lcl.h" + + +static int sm2_sign_setup(EC_KEY *ec_key, BN_CTX *ctx_in, BIGNUM **kp, BIGNUM **xp) +{ + int ret = 0; + const EC_GROUP *ec_group; + BN_CTX *ctx = NULL; + BIGNUM *k = NULL; + BIGNUM *x = NULL; + BIGNUM *order = NULL; + EC_POINT *point = NULL; + + if (ec_key == NULL || (ec_group = EC_KEY_get0_group(ec_key)) == NULL) { + ECerr(EC_F_SM2_SIGN_SETUP, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (ctx_in == NULL) { + if ((ctx = BN_CTX_new()) == NULL) { + ECerr(EC_F_SM2_SIGN_SETUP,ERR_R_MALLOC_FAILURE); + return 0; + } + } + else { + ctx = ctx_in; + } + + k = BN_new(); + x = BN_new(); + order = BN_new(); + if (!k || !x || !order) { + ECerr(EC_F_SM2_SIGN_SETUP, ERR_R_MALLOC_FAILURE); + goto end; + } + + if (!EC_GROUP_get_order(ec_group, order, ctx)) { + ECerr(EC_F_SM2_SIGN_SETUP, ERR_R_EC_LIB); + goto end; + } + + if ((point = EC_POINT_new(ec_group)) == NULL) { + ECerr(EC_F_SM2_SIGN_SETUP, ERR_R_EC_LIB); + goto end; + } + + do { + /* get random k */ + do { + if (!BN_rand_range(k, order)) { + ECerr(EC_F_SM2_SIGN_SETUP, + EC_R_RANDOM_NUMBER_GENERATION_FAILED); + goto end; + } + + } while (BN_is_zero(k)); + + /* compute r the x-coordinate of generator * k */ + if (!EC_POINT_mul(ec_group, point, k, NULL, NULL, ctx)) { + ECerr(EC_F_SM2_SIGN_SETUP, ERR_R_EC_LIB); + goto end; + } + + if (EC_METHOD_get_field_type(EC_GROUP_method_of(ec_group)) == NID_X9_62_prime_field) { + if (!EC_POINT_get_affine_coordinates_GFp(ec_group, point, x, NULL, ctx)) { + ECerr(EC_F_SM2_SIGN_SETUP,ERR_R_EC_LIB); + goto end; + } + } else /* NID_X9_62_characteristic_two_field */ { + if (!EC_POINT_get_affine_coordinates_GF2m(ec_group, point, x, NULL, ctx)) { + ECerr(EC_F_SM2_SIGN_SETUP,ERR_R_EC_LIB); + goto end; + } + } + + if (!BN_nnmod(x, x, order, ctx)) { + ECerr(EC_F_SM2_SIGN_SETUP, ERR_R_BN_LIB); + goto end; + } + + } while (BN_is_zero(x)); + + /* clear old values if necessary */ + BN_clear_free(*kp); + BN_clear_free(*xp); + + /* save the pre-computed values */ + *kp = k; + *xp = x; + ret = 1; + +end: + if (!ret) { + BN_clear_free(k); + BN_clear_free(x); + } + if (!ctx_in) { + BN_CTX_free(ctx); + } + BN_free(order); + EC_POINT_free(point); + + return(ret); +} + +static ECDSA_SIG *sm2_do_sign(const unsigned char *dgst, int dgstlen, + const BIGNUM *in_k, const BIGNUM *in_x, EC_KEY *ec_key) +{ + int ok = 0; + ECDSA_SIG *ret = NULL; + const EC_GROUP *ec_group; + const BIGNUM *priv_key; + const BIGNUM *ck; + BIGNUM *k = NULL; + BN_CTX *ctx = NULL; + BIGNUM *order = NULL; + BIGNUM *e = NULL; + BIGNUM *bn = NULL; + int i; + + ec_group = EC_KEY_get0_group(ec_key); + priv_key = EC_KEY_get0_private_key(ec_key); + if (!ec_group || !priv_key) { + ECerr(EC_F_SM2_DO_SIGN, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + if (!(ret = ECDSA_SIG_new())) { + ECerr(EC_F_SM2_DO_SIGN, ERR_R_MALLOC_FAILURE); + return NULL; + } + ret->r = BN_new(); + ret->s = BN_new(); + ctx = BN_CTX_new(); + order = BN_new(); + e = BN_new(); + bn = BN_new(); + if (!ret->r || !ret->s || !ctx || !order || !e || !bn) { + ECerr(EC_F_SM2_DO_SIGN, ERR_R_MALLOC_FAILURE); + goto end; + } + if (!EC_GROUP_get_order(ec_group, order, ctx)) { + ECerr(EC_F_SM2_DO_SIGN, ERR_R_EC_LIB); + goto end; + } + + /* convert dgst to e */ + i = BN_num_bits(order); +#if 0 + if (8 * dgstlen > i) { + dgstlen = (i + 7)/8; + } +#endif + if (!BN_bin2bn(dgst, dgstlen, e)) { + ECerr(EC_F_SM2_DO_SIGN, ERR_R_BN_LIB); + goto end; + } + +#if 0 + if ((8 * dgstlen > i) && !BN_rshift(e, e, 8 - (i & 0x7))) { + ECerr(EC_F_SM2_DO_SIGN, ERR_R_BN_LIB); + goto end; + } +#endif + + fprintf(stderr, " --- %s %d\n", __func__, __LINE__); + + do { + /* use or compute k and (kG).x */ + if (!in_k || !in_x) { + if (!sm2_sign_setup(ec_key, ctx, &k, &ret->r)) { + ECerr(EC_F_SM2_DO_SIGN,ERR_R_ECDSA_LIB); + goto end; + } + ck = k; + } else { + ck = in_k; + if (!BN_copy(ret->r, in_x)) { + ECerr(EC_F_SM2_DO_SIGN, ERR_R_MALLOC_FAILURE); + goto end; + } + } + fprintf(stderr, " --- %s %d\n", __func__, __LINE__); + + + /* r = e + x (mod n) */ + if (!BN_mod_add(ret->r, ret->r, e, order, ctx)) { + ECerr(EC_F_SM2_DO_SIGN, ERR_R_BN_LIB); + goto end; + } + + fprintf(stderr, " --- %s %d\n", __func__, __LINE__); + + if (!BN_mod_add(bn, ret->r, ck, order, ctx)) { + ECerr(EC_F_SM2_DO_SIGN, ERR_R_BN_LIB); + goto end; + } + fprintf(stderr, " --- %s %d\n", __func__, __LINE__); + + /* check r != 0 && r + k != n */ + if (BN_is_zero(ret->r) || BN_is_zero(bn)) { + if (in_k && in_x) { + ECerr(EC_F_SM2_DO_SIGN, EC_R_NEED_NEW_SETUP_VALUES); + goto end; + } else + continue; + } + + fprintf(stderr, " --- %s %d\n", __func__, __LINE__); + /* s = ((1 + d)^-1 * (k - rd)) mod n */ + if (!BN_one(bn)) { + ECerr(EC_F_SM2_DO_SIGN, ERR_R_BN_LIB); + goto end; + } + if (ret->s == NULL) { + fprintf(stderr, " --- %s %d\n", __func__, __LINE__); + } + + fprintf(stderr, " --- %s %d\n", __func__, __LINE__); + if (!BN_mod_add(ret->s, priv_key, bn, order, ctx)) { + ECerr(EC_F_SM2_DO_SIGN, ERR_R_BN_LIB); + goto end; + } + fprintf(stderr, " --- %s %d\n", __func__, __LINE__); + if (!BN_mod_inverse(ret->s, ret->s, order, ctx)) { + ECerr(EC_F_SM2_DO_SIGN, ERR_R_BN_LIB); + goto end; + } + + fprintf(stderr, " --- %s %d\n", __func__, __LINE__); + if (!BN_mod_mul(bn, ret->r, priv_key, order, ctx)) { + ECerr(EC_F_SM2_DO_SIGN, ERR_R_BN_LIB); + goto end; + } + if (!BN_mod_sub(bn, ck, bn, order, ctx)) { + ECerr(EC_F_SM2_DO_SIGN, ERR_R_BN_LIB); + goto end; + } + if (!BN_mod_mul(ret->s, ret->s, bn, order, ctx)) { + ECerr(EC_F_SM2_DO_SIGN, ERR_R_BN_LIB); + goto end; + } + + /* check s != 0 */ + if (BN_is_zero(ret->s)) { + if (in_k && in_x) { + ECerr(EC_F_SM2_DO_SIGN, EC_R_NEED_NEW_SETUP_VALUES); + goto end; + } + } else { + break; + } + + } while (1); + + ok = 1; + +end: + if (!ok) { + ECDSA_SIG_free(ret); + ret = NULL; + } + BN_free(k); + BN_CTX_free(ctx); + BN_free(order); + BN_free(e); + BN_free(bn); + + return ret; +} + +int sm2_do_verify(const unsigned char *dgst, int dgstlen, + const ECDSA_SIG *sig, EC_KEY *ec_key) +{ + int ret = -1; + const EC_GROUP *ec_group; + const EC_POINT *pub_key; + EC_POINT *point = NULL; + BN_CTX *ctx = NULL; + BIGNUM *order = NULL; + BIGNUM *e = NULL; + BIGNUM *t = NULL; + int i; + + if (!sig || !ec_key || + !(ec_group = EC_KEY_get0_group(ec_key)) || + !(pub_key = EC_KEY_get0_public_key(ec_key))) { + + ECerr(EC_F_SM2_DO_VERIFY, EC_R_MISSING_PARAMETERS); + return -1; + } + + ctx = BN_CTX_new(); + order = BN_new(); + e = BN_new(); + t = BN_new(); + if (!ctx || !order || !e || !t) { + ECerr(EC_F_SM2_DO_VERIFY, ERR_R_MALLOC_FAILURE); + goto end; + } + if (!EC_GROUP_get_order(ec_group, order, ctx)) { + ECerr(EC_F_SM2_DO_VERIFY, ERR_R_EC_LIB); + goto end; + } + + /* check r, s in [1, n-1] and r + s != 0 (mod n) */ + if (BN_is_zero(sig->r) || + BN_is_negative(sig->r) || + BN_ucmp(sig->r, order) >= 0 || + BN_is_zero(sig->s) || + BN_is_negative(sig->s) || + BN_ucmp(sig->s, order) >= 0) { + + ECerr(EC_F_SM2_DO_VERIFY, EC_R_BAD_SIGNATURE); + ret = 0; + goto end; + } + + /* check t = r + s != 0 */ + if (!BN_mod_add(t, sig->r, sig->s, order, ctx)) { + ECerr(EC_F_SM2_DO_VERIFY, ERR_R_BN_LIB); + goto end; + } + if (BN_is_zero(t)) { + ret = 0; + goto end; + } + + /* convert digest to e */ + i = BN_num_bits(order); +#if 0 + if (8 * dgstlen > i) { + dgstlen = (i + 7)/8; + } +#endif + if (!BN_bin2bn(dgst, dgstlen, e)) { + ECerr(EC_F_SM2_DO_VERIFY, ERR_R_BN_LIB); + goto end; + } +#if 0 + if ((8 * dgstlen > i) && !BN_rshift(e, e, 8 - (i & 0x7))) { + ECerr(EC_F_SM2_DO_VERIFY, ERR_R_BN_LIB); + goto end; + } +#endif + + /* compute (x, y) = sG + tP, P is pub_key */ + if (!(point = EC_POINT_new(ec_group))) { + ECerr(EC_F_SM2_DO_VERIFY, ERR_R_MALLOC_FAILURE); + goto end; + } + if (!EC_POINT_mul(ec_group, point, sig->s, pub_key, t, ctx)) { + ECerr(EC_F_SM2_DO_VERIFY, ERR_R_EC_LIB); + goto end; + } + if (EC_METHOD_get_field_type(EC_GROUP_method_of(ec_group)) == NID_X9_62_prime_field) { + if (!EC_POINT_get_affine_coordinates_GFp(ec_group, point, t, NULL, ctx)) { + ECerr(EC_F_SM2_DO_VERIFY, ERR_R_EC_LIB); + goto end; + } + } else /* NID_X9_62_characteristic_two_field */ { + if (!EC_POINT_get_affine_coordinates_GF2m(ec_group, point, t, NULL, ctx)) { + ECerr(EC_F_SM2_DO_VERIFY, ERR_R_EC_LIB); + goto end; + } + } + if (!BN_nnmod(t, t, order, ctx)) { + ECerr(EC_F_SM2_DO_VERIFY, ERR_R_BN_LIB); + goto end; + } + + /* check (sG + tP).x + e == sig.r */ + if (!BN_mod_add(t, t, e, order, ctx)) { + ECerr(EC_F_SM2_DO_VERIFY, ERR_R_BN_LIB); + goto end; + } + if (BN_ucmp(t, sig->r) == 0) { + ret = 1; + } else { + ret = 0; + } + +end: + EC_POINT_free(point); + BN_free(order); + BN_free(e); + BN_free(t); + BN_CTX_free(ctx); + return ret; +} + +int SM2_sign_setup(EC_KEY *ec_key, BN_CTX *ctx_in, BIGNUM **kp, BIGNUM **xp) +{ + return sm2_sign_setup(ec_key, ctx_in, kp, xp); +} + +ECDSA_SIG *SM2_do_sign_ex(const unsigned char *dgst, int dgstlen, + const BIGNUM *kp, const BIGNUM *xp, EC_KEY *ec_key) +{ + return sm2_do_sign(dgst, dgstlen, kp, xp, ec_key); +} + +ECDSA_SIG *SM2_do_sign(const unsigned char *dgst, int dgstlen, EC_KEY *ec_key) +{ + return SM2_do_sign_ex(dgst, dgstlen, NULL, NULL, ec_key); +} + +int SM2_do_verify(const unsigned char *dgst, int dgstlen, + const ECDSA_SIG *sig, EC_KEY *ec_key) +{ + return sm2_do_verify(dgst, dgstlen, sig, ec_key); +} + +int SM2_sign_ex(int type, const unsigned char *dgst, int dgstlen, + unsigned char *sig, unsigned int *siglen, + const BIGNUM *k, const BIGNUM *x, EC_KEY *ec_key) +{ + ECDSA_SIG *s; + + RAND_seed(dgst, dgstlen); + + if (!(s = SM2_do_sign_ex(dgst, dgstlen, k, x, ec_key))) { + *siglen = 0; + return 0; + } + + *siglen = i2d_ECDSA_SIG(s, &sig); + ECDSA_SIG_free(s); + + return 1; +} + +int SM2_sign(int type, const unsigned char *dgst, int dgstlen, + unsigned char *sig, unsigned int *siglen, EC_KEY *ec_key) +{ + return SM2_sign_ex(type, dgst, dgstlen, sig, siglen, NULL, NULL, ec_key); +} + +int SM2_verify(int type, const unsigned char *dgst, int dgstlen, + const unsigned char *sig, int siglen, EC_KEY *ec_key) +{ + ECDSA_SIG *s; + const unsigned char *p = sig; + unsigned char *der = NULL; + int derlen = -1; + int ret = -1; + + if (!(s = ECDSA_SIG_new())) { + return ret; + } + if (!d2i_ECDSA_SIG(&s, &p, siglen)) { + goto err; + } + derlen = i2d_ECDSA_SIG(s, &der); + if (derlen != siglen || memcmp(sig, der, derlen)) { + goto err; + } + + ret = SM2_do_verify(dgst, dgstlen, s, ec_key); + +err: + if (derlen > 0) { + OPENSSL_cleanse(der, derlen); + OPENSSL_free(der); + } + + ECDSA_SIG_free(s); + return ret; +} diff --git a/include/openssl/ec.h b/include/openssl/ec.h index 0bcf3f11..3d124dd0 100644 --- a/include/openssl/ec.h +++ b/include/openssl/ec.h @@ -1372,6 +1372,7 @@ int ERR_load_EC_strings(void); # define EC_F_D2I_ECPARAMETERS 144 # define EC_F_D2I_ECPKPARAMETERS 145 # define EC_F_D2I_ECPRIVATEKEY 146 +# define EC_F_D2I_SM2_CIPHERTEXT_VALUE 280 # define EC_F_DO_EC_KEY_PRINT 221 # define EC_F_ECDH_CMS_DECRYPT 238 # define EC_F_ECDH_CMS_SET_SHARED_INFO 239 @@ -1506,6 +1507,7 @@ int ERR_load_EC_strings(void); # define EC_F_I2D_ECPARAMETERS 190 # define EC_F_I2D_ECPKPARAMETERS 191 # define EC_F_I2D_ECPRIVATEKEY 192 +# define EC_F_I2D_SM2_CIPHERTEXT_VALUE 281 # define EC_F_I2O_ECPUBLICKEY 151 # define EC_F_NISTP224_PRE_COMP_NEW 227 # define EC_F_NISTP256_PRE_COMP_NEW 236 @@ -1522,12 +1524,38 @@ int ERR_load_EC_strings(void); # define EC_F_PKEY_EC_KEYGEN 199 # define EC_F_PKEY_EC_PARAMGEN 219 # define EC_F_PKEY_EC_SIGN 218 +# define EC_F_SM2_CIPHERTEXT_VALUE_DECODE 282 +# define EC_F_SM2_CIPHERTEXT_VALUE_ENCODE 283 +# define EC_F_SM2_CIPHERTEXT_VALUE_GET_ECIES_CIPHERTEXT_VALUE 284 +# define EC_F_SM2_CIPHERTEXT_VALUE_NEW 285 +# define EC_F_SM2_CIPHERTEXT_VALUE_NEW_FROM_ECIES_CIPHERTEXT_VALUE 286 +# define EC_F_SM2_CIPHERTEXT_VALUE_SET_ECIES_CIPHERTEXT_VALUE 287 +# define EC_F_SM2_CIPHERTEXT_VALUE_SIZE 288 +# define EC_F_SM2_COMPUTE_ID_DIGEST 289 +# define EC_F_SM2_COMPUTE_MESSAGE_DIGEST 290 +# define EC_F_SM2_DECRYPT 291 +# define EC_F_SM2_DO_DECRYPT 292 +# define EC_F_SM2_DO_ENCRYPT 293 +# define EC_F_SM2_DO_SIGN 294 +# define EC_F_SM2_DO_VERIFY 295 +# define EC_F_SM2_ENCRYPT 296 +# define EC_F_SM2_ENC_PARAMS_DUP 297 +# define EC_F_SM2_ENC_PARAMS_INIT_WITH_RECOMMENDED 298 +# define EC_F_SM2_ENC_PARAMS_NEW 299 +# define EC_F_SM2_ENC_PARAMS_SET_TYPE 300 +# define EC_F_SM2_GET_PUBLIC_KEY_DATA 301 +# define EC_F_SM2_KAP_COMPUTE_KEY 302 +# define EC_F_SM2_KAP_CTX_INIT 303 +# define EC_F_SM2_KAP_FINAL_CHECK 304 +# define EC_F_SM2_KAP_PREPARE 305 +# define EC_F_SM2_SIGN_SETUP 306 /* Reason codes. */ # define EC_R_ASN1_ERROR 115 # define EC_R_BAD_SIGNATURE 156 # define EC_R_BIGNUM_OUT_OF_RANGE 144 # define EC_R_BUFFER_TOO_SMALL 100 +# define EC_R_CIPHERTEXT_ENCODE_FAILED 173 # define EC_R_CMAC_FINAL_FAILURE 136 # define EC_R_CMAC_INIT_FAILURE 153 # define EC_R_CMAC_UPDATE_FAILURE 162 @@ -1544,33 +1572,46 @@ int ERR_load_EC_strings(void); # define EC_R_ECIES_VERIFY_MAC_FAILURE 167 # define EC_R_EC_GROUP_NEW_BY_NAME_FAILURE 119 # define EC_R_ENCRYPT_FAILED 168 +# define EC_R_ERROR 174 # define EC_R_FIELD_TOO_LARGE 143 # define EC_R_GEN_MAC_FAILED 169 +# define EC_R_GET_CIPHERTEXT_SIZE_FAILED 175 +# define EC_R_GET_KDF_FAILED 176 +# define EC_R_GET_PUBLIC_KEY_DATA_FAILURE 177 # define EC_R_GF2M_NOT_SUPPORTED 147 # define EC_R_GROUP2PKPARAMETERS_FAILURE 120 # define EC_R_HMAC_FAILURE 170 # define EC_R_I2D_ECPKPARAMETERS_FAILURE 121 # define EC_R_INCOMPATIBLE_OBJECTS 101 +# define EC_R_INNOR_ERROR 178 # define EC_R_INVALID_ARGUMENT 112 # define EC_R_INVALID_COMPRESSED_POINT 110 # define EC_R_INVALID_COMPRESSION_BIT 109 # define EC_R_INVALID_CURVE 141 # define EC_R_INVALID_DIGEST 151 +# define EC_R_INVALID_DIGEST_ALGOR 179 # define EC_R_INVALID_DIGEST_TYPE 138 # define EC_R_INVALID_ECIES_CIPHERTEXT 171 # define EC_R_INVALID_ECIES_PARAMETERS 172 +# define EC_R_INVALID_EC_KEY 180 # define EC_R_INVALID_ENCODING 102 # define EC_R_INVALID_FIELD 103 # define EC_R_INVALID_FORM 104 # define EC_R_INVALID_GROUP_ORDER 122 +# define EC_R_INVALID_ID_LENGTH 181 +# define EC_R_INVALID_KDF_MD 182 # define EC_R_INVALID_KEY 116 # define EC_R_INVALID_OUTPUT_LENGTH 161 # define EC_R_INVALID_PEER_KEY 133 # define EC_R_INVALID_PENTANOMIAL_BASIS 132 # define EC_R_INVALID_PRIVATE_KEY 123 +# define EC_R_INVALID_SM2_ID 183 +# define EC_R_INVALID_SM2_KAP_CHECKSUM_LENGTH 184 +# define EC_R_INVALID_SM2_KAP_CHECKSUM_VALUE 185 # define EC_R_INVALID_TRINOMIAL_BASIS 137 # define EC_R_KDF_PARAMETER_ERROR 148 # define EC_R_KEYS_NOT_SET 140 +# define EC_R_MALLOC_FAILED 186 # define EC_R_MISSING_PARAMETERS 124 # define EC_R_MISSING_PRIVATE_KEY 125 # define EC_R_NEED_NEW_SETUP_VALUES 157 @@ -1579,16 +1620,21 @@ int ERR_load_EC_strings(void); # define EC_R_NOT_INITIALIZED 111 # define EC_R_NO_PARAMETERS_SET 139 # define EC_R_NO_PRIVATE_VALUE 154 +# define EC_R_NULL_ARGUMENT 187 +# define EC_R_OCT2POINT_FAILED 188 # define EC_R_OPERATION_NOT_SUPPORTED 152 # define EC_R_PASSED_NULL_PARAMETER 134 # define EC_R_PEER_KEY_ERROR 149 # define EC_R_PKPARAMETERS2GROUP_FAILURE 127 +# define EC_R_POINT2OCT_FAILED 189 # define EC_R_POINT_ARITHMETIC_FAILURE 155 # define EC_R_POINT_AT_INFINITY 106 # define EC_R_POINT_IS_NOT_ON_CURVE 107 +# define EC_R_POINT_NEW_FAILED 190 # define EC_R_RANDOM_NUMBER_GENERATION_FAILED 158 # define EC_R_SHARED_INFO_ERROR 150 # define EC_R_SLOT_FULL 108 +# define EC_R_SM2_KAP_NOT_INITED 191 # define EC_R_UNDEFINED_GENERATOR 113 # define EC_R_UNDEFINED_ORDER 128 # define EC_R_UNKNOWN_GROUP 129 diff --git a/include/openssl/sm2.h b/include/openssl/sm2.h new file mode 100755 index 00000000..fcd28c72 --- /dev/null +++ b/include/openssl/sm2.h @@ -0,0 +1,226 @@ +/* ==================================================================== + * Copyright (c) 2015 - 2016 The GmSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED 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 GmSSL PROJECT OR + * ITS CONTRIBUTORS 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. + * ==================================================================== + */ + +#ifndef HEADER_SM2_H +#define HEADER_SM2_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define SM2_MAX_ID_BITS 65535 +#define SM2_MAX_ID_LENGTH (SM2_MAX_ID_BITS/8) + +#define SM2_DEFAULT_ID_GMT09 "1234567812345678" +#define SM2_DEFAULT_ID_GMSSL "anonym@gmssl.org" +#define SM2_DEFAULT_ID SM2_DEFAULT_ID_GMSSL +#define SM2_DEFAULT_ID_LENGTH (sizeof(SM2_DEFAULT_ID) - 1) +#define SM2_DEFAULT_ID_BITS (SM2_DEFAULT_ID_LENGTH * 8) +#define SM2_ID_DIGEST_LENGTH SM3_DIGEST_LENGTH + +#define SM2_DEFAULT_POINT_CONVERSION_FORM POINT_CONVERSION_UNCOMPRESSED + +#define SM2_MAX_PKEY_DATA_LENGTH ((EC_MAX_NBYTES + 1) * 6) + + + +int SM2_get_public_key_data(EC_KEY *ec_key, unsigned char *out, size_t *outlen); + +int SM2_compute_id_digest(const EVP_MD *md, const char *id, size_t idlen, + unsigned char *out, size_t *outlen, EC_KEY *ec_key); + +/* + * Generate GM/T 0003.2-2012 message digest for SM2 signature scheme. + * Return dgst = msg_md( id_md(id, ec_key) || msg ) + */ +int SM2_compute_message_digest(const EVP_MD *id_md, const EVP_MD *msg_md, + const unsigned char *msg, size_t msglen, const char *id, size_t idlen, + unsigned char *out, size_t *outlen, + EC_KEY *ec_key); + + +typedef struct sm2_enc_params_st { + const EVP_MD *kdf_md; + const EVP_MD *mac_md; + point_conversion_form_t point_form; +} SM2_ENC_PARAMS; + + +/* SM2_ENC_PARAMS_dup() is used by ec_pmeth.c, + * so the SM2_ENC_PARAMS_new() and SM2_ENC_PARAMS_free() is also provided + */ +SM2_ENC_PARAMS *SM2_ENC_PARAMS_new(void); +SM2_ENC_PARAMS *SM2_ENC_PARAMS_dup(const SM2_ENC_PARAMS *param); +void SM2_ENC_PARAMS_free(SM2_ENC_PARAMS *param); + +int SM2_ENC_PARAMS_init_with_recommended(SM2_ENC_PARAMS *param); + + +typedef struct sm2_ciphertext_value_st { + EC_POINT *ephem_point; + unsigned char *ciphertext; + size_t ciphertext_size; + unsigned char mactag[EVP_MAX_MD_SIZE]; + unsigned int mactag_size; +} SM2_CIPHERTEXT_VALUE; + +int SM2_CIPHERTEXT_VALUE_size(const EC_GROUP *ec_group, + const SM2_ENC_PARAMS *params, size_t mlen); + +SM2_CIPHERTEXT_VALUE *SM2_CIPHERTEXT_VALUE_new(const EC_GROUP *group); +void SM2_CIPHERTEXT_VALUE_free(SM2_CIPHERTEXT_VALUE *cv); +int SM2_CIPHERTEXT_VALUE_encode(const SM2_CIPHERTEXT_VALUE *cv, + const EC_GROUP *ec_group, const SM2_ENC_PARAMS *params, + unsigned char *buf, size_t *buflen); +SM2_CIPHERTEXT_VALUE *SM2_CIPHERTEXT_VALUE_decode(const EC_GROUP *ec_group, + const SM2_ENC_PARAMS *params, const unsigned char *buf, size_t buflen); + +int i2d_SM2_CIPHERTEXT_VALUE(const EC_GROUP *group, + const SM2_CIPHERTEXT_VALUE *c, unsigned char **out); +SM2_CIPHERTEXT_VALUE *d2i_SM2_CIPHERTEXT_VALUE(const EC_GROUP *group, + SM2_CIPHERTEXT_VALUE **c, const unsigned char **in, long len); + +int SM2_CIPHERTEXT_VALUE_print(BIO *out, const EC_GROUP *ec_group, + const SM2_CIPHERTEXT_VALUE *cv, int indent, unsigned long flags); + +SM2_CIPHERTEXT_VALUE *SM2_do_encrypt(const SM2_ENC_PARAMS *params, + const unsigned char *in, size_t inlen, EC_KEY *ec_key); +int SM2_do_decrypt(const SM2_ENC_PARAMS *params, + const SM2_CIPHERTEXT_VALUE *in, unsigned char *out, size_t *outlen, + EC_KEY *ec_key); +int SM2_encrypt(const SM2_ENC_PARAMS *params, + const unsigned char *in, size_t inlen, + unsigned char *out, size_t *outlen, + EC_KEY *ec_key); +int SM2_decrypt(const SM2_ENC_PARAMS *params, + const unsigned char *in, size_t inlen, + unsigned char *out, size_t *outlen, + EC_KEY *ec_key); + + +int SM2_encrypt_with_recommended(const unsigned char *in, size_t inlen, + unsigned char *out, size_t *outlen, EC_KEY *ec_key); +int SM2_decrypt_with_recommended(const unsigned char *in, size_t inlen, + unsigned char *out, size_t *outlen, EC_KEY *ec_key); + + +int SM2_sign_setup(EC_KEY *ec_key, BN_CTX *ctx, BIGNUM **a, BIGNUM **b); +ECDSA_SIG *SM2_do_sign_ex(const unsigned char *dgst, int dgstlen, + const BIGNUM *a, const BIGNUM *b, EC_KEY *ec_key); +ECDSA_SIG *SM2_do_sign(const unsigned char *dgst, int dgst_len, + EC_KEY *ec_key); +int SM2_do_verify(const unsigned char *dgst, int dgstlen, + const ECDSA_SIG *sig, EC_KEY *ec_key); +int SM2_sign_ex(int type, const unsigned char *dgst, int dgstlen, + unsigned char *sig, unsigned int *siglen, + const BIGNUM *k, const BIGNUM *x, EC_KEY *ec_key); +int SM2_sign(int type, const unsigned char *dgst, int dgstlen, + unsigned char *sig, unsigned int *siglen, EC_KEY *eckey); +int SM2_verify(int type, const unsigned char *dgst, int dgstlen, + const unsigned char *sig, int siglen, EC_KEY *ec_key); + + +typedef struct sm2_kap_ctx_st { + + const EVP_MD *id_dgst_md; + const EVP_MD *kdf_md; + const EVP_MD *checksum_md; + point_conversion_form_t point_form; + KDF_FUNC kdf; + + int is_initiator; + int do_checksum; + + EC_KEY *ec_key; + unsigned char id_dgst[EVP_MAX_MD_SIZE]; + unsigned int id_dgstlen; + + EC_KEY *remote_pubkey; + unsigned char remote_id_dgst[EVP_MAX_MD_SIZE]; + unsigned int remote_id_dgstlen; + + const EC_GROUP *group; + BN_CTX *bn_ctx; + BIGNUM *order; + BIGNUM *two_pow_w; + + BIGNUM *t; + EC_POINT *point; + unsigned char pt_buf[1 + (OPENSSL_ECC_MAX_FIELD_BITS+7)/4]; + unsigned char checksum[EVP_MAX_MD_SIZE]; +} SM2_KAP_CTX; + +int SM2_KAP_CTX_init(SM2_KAP_CTX *ctx, + EC_KEY *ec_key, const char *id, size_t idlen, + EC_KEY *remote_pubkey, const char *rid, size_t ridlen, + int is_initiator, int do_checksum); +int SM2_KAP_prepare(SM2_KAP_CTX *ctx, unsigned char *ephem_point, + size_t *ephem_point_len); +int SM2_KAP_compute_key(SM2_KAP_CTX *ctx, const unsigned char *remote_ephem_point, + size_t remote_ephem_point_len, unsigned char *key, size_t keylen, + unsigned char *checksum, size_t *checksumlen); +int SM2_KAP_final_check(SM2_KAP_CTX *ctx, const unsigned char *checksum, + size_t checksumlen); +void SM2_KAP_CTX_cleanup(SM2_KAP_CTX *ctx); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/test/recipes/15-test_sm2.t b/test/recipes/15-test_sm2.t new file mode 100644 index 00000000..31be5b88 --- /dev/null +++ b/test/recipes/15-test_sm2.t @@ -0,0 +1,13 @@ +#! /usr/bin/env perl +# Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + + +use OpenSSL::Test::Simple; + +simple_test("test_sm2", "sm2test", "sm2"); +#simple_test("test_sm2evp", "sm2evptest", "sm2"); diff --git a/test/sm2evptest.c b/test/sm2evptest.c new file mode 100644 index 00000000..9803ba4b --- /dev/null +++ b/test/sm2evptest.c @@ -0,0 +1,1336 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2016 The GmSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED 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 GmSSL PROJECT OR + * ITS CONTRIBUTORS 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. + * ==================================================================== + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +RAND_METHOD fake_rand; +const RAND_METHOD *old_rand; + +static const char rnd_seed[] = + "string to make the random number generator think it has entropy"; +static const char *rnd_number = NULL; + +int fbytes(unsigned char *buf, int num) +{ + int ret = 0; + BIGNUM *bn = NULL; + + if (!BN_hex2bn(&bn, rnd_number)) { + goto end; + } + if (BN_num_bytes(bn) > num) { + goto end; + } + memset(buf, 0, num); + if (!BN_bn2bin(bn, buf + num - BN_num_bytes(bn))) { + goto end; + } + ret = 1; +end: + BN_free(bn); + return ret; +} + +int change_rand(const char *hex) +{ + if (!(old_rand = RAND_get_rand_method())) { + return 0; + } + + fake_rand.seed = old_rand->seed; + fake_rand.cleanup = old_rand->cleanup; + fake_rand.add = old_rand->add; + fake_rand.status = old_rand->status; + fake_rand.bytes = fbytes; + fake_rand.pseudorand = old_rand->bytes; + + if (!RAND_set_rand_method(&fake_rand)) { + return 0; + } + + rnd_number = hex; + return 1; +} + +int restore_rand(void) +{ + rnd_number = NULL; + if (!RAND_set_rand_method(old_rand)) + return 0; + else return 1; +} + +int hexequbin(const char *hex, const unsigned char *bin, size_t binlen) +{ + int ret = 0; + char *buf = NULL; + int i = 0; + size_t buflen = binlen * 2 + 1; + + + if (binlen * 2 != strlen(hex)) { + return 0; + } + if (!(buf = malloc(binlen * 2 + 1))) { + return 0; + } + for (i = 0; i < binlen; i++) { + sprintf(buf + i*2, "%02X", bin[i]); + } + buf[buflen - 1] = 0; + + if (memcmp(hex, buf, binlen * 2) == 0) { + ret = 1; + } + + free(buf); + return ret; +} + +EC_GROUP *new_ec_group(int is_prime_field, + const char *p_hex, const char *a_hex, const char *b_hex, + const char *x_hex, const char *y_hex, const char *n_hex, const char *h_hex) +{ + int ok = 0; + EC_GROUP *group = NULL; + BN_CTX *ctx = NULL; + BIGNUM *p = NULL; + BIGNUM *a = NULL; + BIGNUM *b = NULL; + BIGNUM *x = NULL; + BIGNUM *y = NULL; + BIGNUM *n = NULL; + BIGNUM *h = NULL; + EC_POINT *G = NULL; + point_conversion_form_t form = SM2_DEFAULT_POINT_CONVERSION_FORM; + int flag = 0; + + if (!(ctx = BN_CTX_new())) { + goto err; + } + + if (!BN_hex2bn(&p, p_hex) || + !BN_hex2bn(&a, a_hex) || + !BN_hex2bn(&b, b_hex) || + !BN_hex2bn(&x, x_hex) || + !BN_hex2bn(&y, y_hex) || + !BN_hex2bn(&n, n_hex) || + !BN_hex2bn(&h, h_hex)) { + goto err; + } + + if (is_prime_field) { + if (!(group = EC_GROUP_new_curve_GFp(p, a, b, ctx))) { + goto err; + } + if (!(G = EC_POINT_new(group))) { + goto err; + } + if (!EC_POINT_set_affine_coordinates_GFp(group, G, x, y, ctx)) { + goto err; + } + } else { + if (!(group = EC_GROUP_new_curve_GF2m(p, a, b, ctx))) { + goto err; + } + if (!(G = EC_POINT_new(group))) { + goto err; + } + if (!EC_POINT_set_affine_coordinates_GF2m(group, G, x, y, ctx)) { + goto err; + } + } + + if (!EC_GROUP_set_generator(group, G, n, h)) { + goto err; + } + + EC_GROUP_set_asn1_flag(group, flag); + EC_GROUP_set_point_conversion_form(group, form); + + ok = 1; +err: + BN_CTX_free(ctx); + BN_free(p); + BN_free(a); + BN_free(b); + BN_free(x); + BN_free(y); + BN_free(n); + BN_free(h); + EC_POINT_free(G); + if (!ok && group) { + ERR_print_errors_fp(stderr); + EC_GROUP_free(group); + group = NULL; + } + + return group; +} + +EC_KEY *new_ec_key(const EC_GROUP *group, + const char *sk, const char *xP, const char *yP, + const char *id, const EVP_MD *id_md) +{ + int ok = 0; + EC_KEY *ec_key = NULL; + BIGNUM *d = NULL; + BIGNUM *x = NULL; + BIGNUM *y = NULL; + + OPENSSL_assert(group); + OPENSSL_assert(xP); + OPENSSL_assert(yP); + + if (!(ec_key = EC_KEY_new())) { + goto end; + } + if (!EC_KEY_set_group(ec_key, group)) { + goto end; + } + + if (sk) { + if (!BN_hex2bn(&d, sk)) { + goto end; + } + if (!EC_KEY_set_private_key(ec_key, d)) { + goto end; + } + } + + if (xP && yP) { + if (!BN_hex2bn(&x, xP)) { + goto end; + } + if (!BN_hex2bn(&y, yP)) { + goto end; + } + if (!EC_KEY_set_public_key_affine_coordinates(ec_key, x, y)) { + goto end; + } + } + + if (id) { + if (!SM2_set_id(ec_key, id, id_md)) { + goto end; + } + } + + ok = 1; +end: + if (d) BN_free(d); + if (x) BN_free(x); + if (y) BN_free(y); + if (!ok && ec_key) { + ERR_print_errors_fp(stderr); + EC_KEY_free(ec_key); + ec_key = NULL; + } + return ec_key; +} + +int test_sm2_sign(const EC_GROUP *group, + const char *sk, const char *xP, const char *yP, + const char *id, const char *Z, + const char *M, const char *e, + const char *k, const char *r, const char *s) +{ + int ret = 0; + const EVP_MD *id_md = EVP_sm3(); + const EVP_MD *msg_md = EVP_sm3(); + int type = NID_undef; + unsigned char dgst[EVP_MAX_MD_SIZE]; + size_t dgstlen; + unsigned char sig[256]; + unsigned int siglen; + const unsigned char *p; + EC_KEY *ec_key = NULL; + EC_KEY *pubkey = NULL; + ECDSA_SIG *sm2sig = NULL; + BIGNUM *rr = NULL; + BIGNUM *ss = NULL; + + change_rand(k); + + if (!(ec_key = new_ec_key(group, sk, xP, yP, id, id_md))) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + + dgstlen = sizeof(dgst); + if (!SM2_get_id_digest(ec_key, dgst, &dgstlen)) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + if (!hexequbin(Z, dgst, dgstlen)) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + dgstlen = sizeof(dgst); + if (!SM2_compute_message_digest(dgst, &dgstlen, + id_md, id, ec_key, msg_md, M, strlen(M))) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + if (!hexequbin(e, dgst, dgstlen)) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + + /* sign */ + if (!SM2_sign(type, dgst, dgstlen, sig, &siglen, ec_key)) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + + p = sig; + if (!(sm2sig = d2i_ECDSA_SIG(NULL, &p, siglen))) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + if (!BN_hex2bn(&rr, r) || !BN_hex2bn(&ss, s)) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + + if (BN_cmp(sm2sig->r, rr) || BN_cmp(sm2sig->s, ss)) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + + /* verify */ + if (!(pubkey = new_ec_key(group, NULL, xP, yP, id, id_md))) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + if (SM2_verify(type, dgst, dgstlen, sig, siglen, pubkey) != SM2_VERIFY_SUCCESS) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + + ret = 1; +err: + restore_rand(); + if (ec_key) EC_KEY_free(ec_key); + if (pubkey) EC_KEY_free(pubkey); + if (sm2sig) ECDSA_SIG_free(sm2sig); + if (rr) BN_free(rr); + if (ss) BN_free(ss); + return ret; +} + +int test_sm2_enc(const EC_GROUP *group, + const char *d, const char *xP, const char *yP, + const char *M, + const char *k, const char *C) +{ + int ret = 0; + EC_KEY *ec_key = NULL; + const EVP_MD *kdf_md = EVP_sm3(); + const EVP_MD *mac_md = EVP_sm3(); + point_conversion_form_t point_form = POINT_CONVERSION_UNCOMPRESSED; + unsigned char msg[128]; + unsigned char buf[sizeof(msg) + 128]; + size_t msglen, buflen; + + change_rand(k); + + if (!(ec_key = new_ec_key(group, NULL, xP, yP, NULL, NULL))) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + buflen = sizeof(buf); + if (!SM2_encrypt_with_recommended(buf, &buflen, + (const unsigned char *)M, strlen(M), ec_key)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + + if (!hexequbin(C, buf, buflen)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + printf("shit\n"); + goto end; + } + EC_KEY_free(ec_key); + + if (!(ec_key = new_ec_key(group, d, xP, yP, NULL, NULL))) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + if (!SM2_decrypt_with_recommended(msg, &msglen, buf, buflen, ec_key)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + if (msglen != strlen(M) || memcmp(msg, M, strlen(M))) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + ret = 1; + +end: + ERR_print_errors_fp(stderr); + restore_rand(); + EC_KEY_free(ec_key); + return ret; +} + +int test_sm2_kap(const EC_GROUP *group, + const char *A, const char *dA, const char *xA, const char *yA, const char *ZA, + const char *B, const char *dB, const char *xB, const char *yB, const char *ZB, + const char *rA, const char *rB, const char *KAB, const char *S1, const char *S2) +{ + int ret = 0; + const EVP_MD *id_md = EVP_sm3(); + EC_KEY *eckeyA = NULL; + EC_KEY *eckeyB = NULL; + EC_KEY *pubkeyA = NULL; + EC_KEY *pubkeyB = NULL; + SM2_KAP_CTX ctxA; + SM2_KAP_CTX ctxB; + unsigned char za[EVP_MAX_MD_SIZE]; + unsigned char zb[EVP_MAX_MD_SIZE]; + size_t zalen, zblen; + unsigned char RA[256]; + unsigned char RB[256]; + size_t RAlen = sizeof(RA); + size_t RBlen = sizeof(RB); + unsigned char kab[64]; + unsigned char kba[64]; + size_t kablen = strlen(KAB)/2; + size_t kbalen = strlen(KAB)/2; + unsigned char s1[64]; + unsigned char s2[64]; + size_t s1len, s2len; + + memset(&ctxA, 0, sizeof(ctxA)); + memset(&ctxB, 0, sizeof(ctxB)); + + + eckeyA = new_ec_key(group, dA, xA, yA, A, id_md); + eckeyB = new_ec_key(group, dB, xB, yB, B, id_md); + pubkeyA = new_ec_key(group, NULL, xA, yA, A, id_md); + pubkeyB = new_ec_key(group, NULL, xB, yB, B, id_md); + if (!eckeyA || !eckeyB || !pubkeyA || !pubkeyB) { + goto end; + } + + zalen = sizeof(za); + if (!SM2_get_id_digest(eckeyA, za, &zalen)) { + goto end; + } + zblen = sizeof(zb); + if (!SM2_get_id_digest(eckeyB, zb, &zblen)) { + goto end; + } + + if (!hexequbin(ZA, za, zalen)) { + fprintf(stderr, "error (%s %d): ZA != value in test vector !!!\n", __FILE__, __LINE__); + goto end; + } + + if (!hexequbin(ZB, zb, zblen)) { + goto end; + } + + if (!SM2_KAP_CTX_init(&ctxA, eckeyA, pubkeyB, 1, 1)) { + goto end; + } + if (!SM2_KAP_CTX_init(&ctxB, eckeyB, pubkeyA, 0, 1)) { + goto end; + } + + change_rand(rA); + if (!SM2_KAP_prepare(&ctxA, RA, &RAlen)) { + goto end; + } + restore_rand(); + + change_rand(rB); + if (!SM2_KAP_prepare(&ctxB, RB, &RBlen)) { + goto end; + } + restore_rand(); + + + if (!SM2_KAP_compute_key(&ctxA, RB, RBlen, kab, kablen, s1, &s1len)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + + if (!SM2_KAP_compute_key(&ctxB, RA, RAlen, kba, kbalen, s2, &s2len)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!SM2_KAP_final_check(&ctxA, s2, s2len)) { + goto end; + } + if (!SM2_KAP_final_check(&ctxB, s1, s1len)) { + goto end; + } + + ret = 1; + +end: + EC_KEY_free(eckeyA); + EC_KEY_free(eckeyB); + EC_KEY_free(pubkeyA); + EC_KEY_free(pubkeyB); + SM2_KAP_CTX_cleanup(&ctxA); + SM2_KAP_CTX_cleanup(&ctxB); + return ret; +} + +int test_sm2_test_vector() +{ + int ret = 0; + EC_GROUP *sm2p192test = NULL; + EC_GROUP *sm2p256test = NULL; + EC_GROUP *sm2b193test = NULL; + EC_GROUP *sm2b257test = NULL; + + sm2p192test = new_ec_group(1, + "BDB6F4FE3E8B1D9E0DA8C0D46F4C318CEFE4AFE3B6B8551F", + "BB8E5E8FBC115E139FE6A814FE48AAA6F0ADA1AA5DF91985", + "1854BEBDC31B21B7AEFC80AB0ECD10D5B1B3308E6DBF11C1", + "4AD5F7048DE709AD51236DE65E4D4B482C836DC6E4106640", + "02BB3A02D4AAADACAE24817A4CA3A1B014B5270432DB27D2", + "BDB6F4FE3E8B1D9E0DA8C0D40FC962195DFAE76F56564677", + "1"); + + sm2p256test = new_ec_group(1, + "8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", + "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", + "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", + "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", + "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", + "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", + "1"); + + sm2b193test = new_ec_group(0, + "2000000000000000000000000000000000000000000008001", + "0", + "002FE22037B624DBEBC4C618E13FD998B1A18E1EE0D05C46FB", + "00D78D47E85C93644071BC1C212CF994E4D21293AAD8060A84", + "00615B9E98A31B7B2FDDEEECB76B5D875586293725F9D2FC0C", + "80000000000000000000000043E9885C46BF45D8C5EBF3A1", + "1"); + + sm2b257test = new_ec_group(0, + "20000000000000000000000000000000000000000000000000000000000001001", + "0", + "00E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B", + "00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD", + "013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E", + "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC972CF7E6B6F900945B3C6A0CF6161D", + "4"); + + if (!sm2p192test || !sm2p256test || !sm2b193test || !sm2b257test) { + goto end; + } + + if (!test_sm2_sign( + sm2p256test, + "128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263", + "0AE4C7798AA0F119471BEE11825BE46202BB79E2A5844495E97C04FF4DF2548A", + "7C0240F88F1CD4E16352A73C17B7F16F07353E53A176D684A9FE0C6BB798E857", + "ALICE123@YAHOO.COM", + "F4A38489E32B45B6F876E3AC2168CA392362DC8F23459C1D1146FC3DBFB7BC9A", + "message digest", + "B524F552CD82B8B028476E005C377FB19A87E6FC682D48BB5D42E3D9B9EFFE76", + "6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F", + "40F1EC59F793D9F49E09DCEF49130D4194F79FB1EED2CAA55BACDB49C4E755D1", + "6FC6DAC32C5D5CF10C77DFB20F7C2EB667A457872FB09EC56327A67EC7DEEBE7")) { + printf("sm2 sign p256 failed\n"); + goto end; + } else { + printf("sm2 sign p256 passed\n"); + } + + + if (!test_sm2_sign( + sm2b257test, + "771EF3DBFF5F1CDC32B9C572930476191998B2BF7CB981D7F5B39202645F0931", + "0165961645281A8626607B917F657D7E9382F1EA5CD931F40F6627F357542653B2", + "01686522130D590FB8DE635D8FCA715CC6BF3D05BEF3F75DA5D543454448166612", + "ALICE123@YAHOO.COM", + "26352AF82EC19F207BBC6F9474E11E90CE0F7DDACE03B27F801817E897A81FD5", + "message digest", + "AD673CBDA311417129A9EAA5F9AB1AA1633AD47718A84DFD46C17C6FA0AA3B12", + "36CD79FC8E24B7357A8A7B4A46D454C397703D6498158C605399B341ADA186D6", + "6D3FBA26EAB2A1054F5D198332E335817C8AC453ED26D3391CD4439D825BF25B", + "3124C5688D95F0A10252A9BED033BEC84439DA384621B6D6FAD77F94B74A9556")) { + printf("sm2 sign b257 failed\n"); + goto end; + } else { + printf("sm2 sign b257 passed\n"); + } + + if (!test_sm2_enc( + sm2p256test, + "1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0", + "435B39CCA8F3B508C1488AFC67BE491A0F7BA07E581A0E4849A5CF70628A7E0A", + "75DDBA78F15FEECB4C7895E2C1CDF5FE01DEBB2CDBADF45399CCF77BBA076A42", + "encryption standard", + "4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F", + "04" + "245C26FB68B1DDDDB12C4B6BF9F2B6D5FE60A383B0D18D1C4144ABF17F6252E7" + "76CB9264C2A7E88E52B19903FDC47378F605E36811F5C07423A24B84400F01B8" + "650053A89B41C418B0C3AAD00D886C00286467" + "9C3D7360C30156FAB7C80A0276712DA9D8094A634B766D3A285E07480653426D")) { + printf("sm2 enc p256 failed\n"); + goto end; + } else { + printf("sm2 enc p256 passed\n"); + } + + if (!test_sm2_enc( + sm2b257test, + "56A270D17377AA9A367CFA82E46FA5267713A9B91101D0777B07FCE018C757EB", + "00A67941E6DE8A61805F7BCFF0985BB3BED986F1C297E4D8880D82B821C624EE57", + "0193ED5A6707B5908781B860841085F52EEFA7FE329A5C811843533A874D027271", + "encryption standard", + "6D3B497153E3E92524E5C122682DBDC8705062E20B917A5F8FCDB8EE4C66663D", + "04" + "019D236DDB305009AD52C51BB932709BD534D476FBB7B0DF9542A8A4D890A3F2E1" + "00B23B938DC0A94D1DF8F42CF45D2D6601BF638C3D7DE75A29F02AFB7E45E91771" + "FD55AC6213C2A8A040E4CAB5B26A9CFCDA7373" + "73A48625D3758FA37B3EAB80E9CFCABA665E3199EA15A1FA8189D96F579125E4")) { + printf("sm2 enc b257 failed\n"); + goto end; + } else { + printf("sm2 enc b257 passed\n"); + } + + if (!test_sm2_kap( + sm2p256test, + "ALICE123@YAHOO.COM", + "6FCBA2EF9AE0AB902BC3BDE3FF915D44BA4CC78F88E2F8E7F8996D3B8CCEEDEE", + "3099093BF3C137D8FCBBCDF4A2AE50F3B0F216C3122D79425FE03A45DBFE1655", + "3DF79E8DAC1CF0ECBAA2F2B49D51A4B387F2EFAF482339086A27A8E05BAED98B", + "E4D1D0C3CA4C7F11BC8FF8CB3F4C02A78F108FA098E51A668487240F75E20F31", + "BILL456@YAHOO.COM", + "5E35D7D3F3C54DBAC72E61819E730B019A84208CA3A35E4C2E353DFCCB2A3B53", + "245493D446C38D8CC0F118374690E7DF633A8A4BFB3329B5ECE604B2B4F37F43", + "53C0869F4B9E17773DE68FEC45E14904E0DEA45BF6CECF9918C85EA047C60A4C", + "6B4B6D0E276691BD4A11BF72F4FB501AE309FDACB72FA6CC336E6656119ABD67", + "83A2C9C8B96E5AF70BD480B472409A9A327257F1EBB73F5B073354B248668563", + "33FE21940342161C55619C4A0C060293D543C80AF19748CE176D83477DE71C80", + "55B0AC62A6B927BA23703832C853DED4", + "284C8F198F141B502E81250F1581C7E9EEB4CA6990F9E02DF388B45471F5BC5C", + "23444DAF8ED7534366CB901C84B3BDBB63504F4065C1116C91A4C00697E6CF7A")) { + printf("sm2 kap p256 failed\n"); + goto end; + } else { + printf("sm2 kap p256 passed\n"); + } + +#if 0 + /* ZA will not pass! */ + if (!test_sm2_kap( + sm2b257test, + "ALICE123@YAHOO.COM", + "4813903D254F2C20A94BC5704238496954BB5279F861952EF2C5298E84D2CEAA", + "008E3BDB2E11F9193388F1F901CCC857BF49CFC065FB38B9069CAAE6D5AFC3592F", + "004555122AAC0075F42E0A8BBD2C0665C789120DF19D77B4E3EE4712F598040415", + "ECF0080215977B2E5D6D61B98A99442F03E8803DC39E349F8DCA5621A9ACDF2B", + "BILL456@YAHOO.COM", + "08F41BAE0922F47C212803FE681AD52B9BF28A35E1CD0EC273A2CF813E8FD1DC", + "0034297DD83AB14D5B393B6712F32B2F2E938D4690B095424B89DA880C52D4A7D9", + "0199BBF11AC95A0EA34BBD00CA50B93EC24ACB68335D20BA5DCFE3B33BDBD2B62D", + "557BAD30 E183559A EEC3B2256E1C7C11F870D22B165D015ACF9465B09B87B527", + "54A3D6673FF3A6BD6B02EBB164C2A3AF6D4A4906229D9BFCE68CC366A2E64BA4", + "1F21933387BEF781D0A8F7FD708C5AE0A56EE3F423DBC2FE5BDF6F068C53F7AD", + "4E587E5C66634F22D973A7D98BF8BE23", + "4EB47D28AD3906D6244D01E0F6AEC73B0B51DE1574C13798184E4833DBAE295A", + "588AA67064F24DC27CCAA1FAB7E27DFF811D500AD7EF2FB8F69DDF48CC0FECB7")) { + printf("sm2 kap b257 failed\n"); + goto end; + } else { + printf("sm2 kap b257 passed\n"); + } +#endif + + ret = 1; + +end: + EC_GROUP_free(sm2p192test); + EC_GROUP_free(sm2p256test); + EC_GROUP_free(sm2b193test); + EC_GROUP_free(sm2b257test); + + return ret; +} + + +EVP_PKEY *genpkey(int curve_nid, BIO *out, int verbose) +{ + int ok = 0; + EVP_PKEY *ret = NULL; + EVP_PKEY_CTX *pkctx = NULL; + + if (!(pkctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_PKEY_keygen_init(pkctx)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pkctx, curve_nid)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_PKEY_keygen(pkctx, &ret)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (verbose > 1) { + EVP_PKEY_print_private(out, ret, 4, NULL); + BIO_printf(out, "\n"); + } + + ok = 1; +end: + if (!ok && ret) { + EVP_PKEY_free(ret); + ret = NULL; + } + EVP_PKEY_CTX_free(pkctx); + return ret; +} + +int test_evp_pkey_sign(EVP_PKEY *pkey, int do_sm2, int verbose) +{ + int ret = 0; + EVP_PKEY_CTX *pkctx = NULL; + int type = do_sm2 ? NID_sm_scheme : NID_secg_scheme; + unsigned char dgst[EVP_MAX_MD_SIZE] = "hello world"; + size_t dgstlen; + unsigned char sig[256]; + size_t siglen; + + + if (!(pkctx = EVP_PKEY_CTX_new(pkey, NULL))) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + /* EVP_PKEY_sign() */ + + if (!EVP_PKEY_sign_init(pkctx)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_PKEY_CTX_set_ec_scheme(pkctx, type)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + dgstlen = 32; + memset(sig, 0, sizeof(sig)); + siglen = sizeof(sig); + if (!EVP_PKEY_sign(pkctx, sig, &siglen, dgst, dgstlen)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (verbose > 1) { + size_t i; + printf("signature (%zu bytes) = ", siglen); + for (i = 0; i < siglen; i++) { + printf("%02X", sig[i]); + } + printf("\n"); + } + + if (!EVP_PKEY_verify_init(pkctx)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_PKEY_CTX_set_ec_scheme(pkctx, type)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (EVP_PKEY_verify(pkctx, sig, siglen, dgst, dgstlen) != SM2_VERIFY_SUCCESS) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (verbose) { + printf("%s(%s) passed\n", __FUNCTION__, OBJ_nid2sn(type)); + } + + ret = 1; +end: + EVP_PKEY_CTX_free(pkctx); + return ret; +} + +int test_evp_pkey_encrypt(EVP_PKEY *pkey, int do_sm2, int verbose) +{ + int ret = 0; + EVP_PKEY_CTX *pkctx = NULL; + int type = do_sm2 ? NID_sm_scheme : NID_secg_scheme; + unsigned char msg[] = "hello world this is the message"; + size_t msglen = sizeof(msg); + unsigned char cbuf[512]; + size_t cbuflen = sizeof(cbuf); + unsigned char mbuf[512]; + size_t mbuflen = sizeof(mbuf); + int len; + unsigned int ulen; + + if (!(pkctx = EVP_PKEY_CTX_new(pkey, NULL))) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + /* EVP_PKEY_encrypt() */ + + if (!EVP_PKEY_encrypt_init(pkctx)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_PKEY_CTX_set_ec_scheme(pkctx, type)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + cbuflen = sizeof(cbuf); + if (!EVP_PKEY_encrypt(pkctx, cbuf, &cbuflen, msg, msglen)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (verbose > 1) { + size_t i; + printf("ciphertext (%zu bytes) = ", cbuflen); + for (i = 0; i < cbuflen; i++) { + printf("%02X", cbuf[i]); + } + printf("\n"); + } + + if (!EVP_PKEY_decrypt_init(pkctx)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_PKEY_CTX_set_ec_scheme(pkctx, type)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + memset(mbuf, 0, sizeof(mbuf)); + mbuflen = sizeof(mbuf); + if (!EVP_PKEY_decrypt(pkctx, mbuf, &mbuflen, cbuf, cbuflen)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (verbose > 1) { + printf("original message = %s\n", msg); + printf("decrypted message = %s\n", mbuf); + } + + if (verbose) { + printf("%s(%s) passed\n", __FUNCTION__, OBJ_nid2sn(type)); + } + + ret = 1; +end: + EVP_PKEY_CTX_free(pkctx); + return ret; +} + +int test_evp_pkey_encrypt_old(EVP_PKEY *pkey, int verbose) +{ + int ret = 0; + unsigned char msg[] = "hello world this is the message"; + size_t msglen = sizeof(msg); + unsigned char cbuf[512]; + size_t cbuflen = sizeof(cbuf); + unsigned char mbuf[512]; + size_t mbuflen = sizeof(mbuf); + + int len; + + if ((len = EVP_PKEY_encrypt_old(cbuf, msg, (int)msglen, pkey)) <= 0) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (verbose > 1) { + int i; + printf("ciphertext (%d bytes) = ", len); + for (i = 0; i < len; i++) { + printf("%02X", cbuf[i]); + } + printf("\n"); + } + + memset(mbuf, 0, sizeof(mbuf)); + if ((len = EVP_PKEY_decrypt_old(mbuf, cbuf, len, pkey)) <= 0) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (verbose > 1) { + printf("original message = %s\n", msg); + printf("decrypted message = %s\n", mbuf); + } + + if (verbose) { + printf("%s() passed!\n", __FUNCTION__); + } + + ret = 1; +end: + return ret; +} + +int test_evp_sign(EVP_PKEY *pkey, const EVP_MD *md, int verbose) +{ + int ret = 0; + EVP_MD_CTX *mdctx = NULL; + unsigned char msg[] = "hello world this is the message"; + size_t msglen = sizeof(msg); + unsigned char sig[256]; + unsigned int siglen = (unsigned int)sizeof(sig); + unsigned int i; + + if (!(mdctx = EVP_MD_CTX_create())) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_SignInit_ex(mdctx, md, NULL)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_SignUpdate(mdctx, msg, msglen)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_SignFinal(mdctx, sig, &siglen, pkey)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (verbose > 1) { + size_t i; + printf("signature (%u bytes) = ", siglen); + for (i = 0; i < siglen; i++) { + printf("%02X", sig[i]); + } + printf("\n"); + } + + if (!EVP_VerifyInit_ex(mdctx, md, NULL)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_VerifyUpdate(mdctx, msg, msglen)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (EVP_VerifyFinal(mdctx, sig, siglen, pkey) != SM2_VERIFY_SUCCESS) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (verbose) { + printf("%s() passed\n", __FUNCTION__); + } + + ret = 1; + +end: + EVP_MD_CTX_destroy(mdctx); + return ret; +} + +int test_evp_digestsign(EVP_PKEY *pkey, int do_sm2, const EVP_MD *md, int verbose) +{ + int ret = 0; + EVP_MD_CTX *mdctx = NULL; + EVP_PKEY_CTX *pkctx; + int type = do_sm2 ? NID_sm_scheme : NID_secg_scheme; + unsigned char msg[] = "hello world this is the message"; + size_t msglen = sizeof(msg); + unsigned char sig[256]; + size_t siglen = (unsigned int)sizeof(sig); + + if (!(mdctx = EVP_MD_CTX_create())) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + pkctx = NULL; + if (!EVP_DigestSignInit(mdctx, &pkctx, md, NULL, pkey)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_PKEY_CTX_set_ec_scheme(pkctx, type)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_DigestSignUpdate(mdctx, msg, msglen)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + siglen = sizeof(sig); + if (!EVP_DigestSignFinal(mdctx, sig, &siglen)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + pkctx = NULL; + if (!EVP_DigestVerifyInit(mdctx, &pkctx, md, NULL, pkey)) { + ERR_print_errors_fp(stderr); + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_PKEY_CTX_set_ec_scheme(pkctx, type)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_DigestVerifyUpdate(mdctx, msg, msglen)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_DigestVerifyFinal(mdctx, sig, siglen)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (verbose) { + printf("%s() passed\n", __FUNCTION__); + } + + ret = 1; +end: + EVP_MD_CTX_destroy(mdctx); + return ret; +} + +#define NUM_PKEYS 3 +#define MAX_PKEY_SIZE 1024 + +int test_evp_seal(int curve_id, const EVP_CIPHER *cipher, BIO *out, int verbose) +{ + int ret = 0; + EVP_PKEY *pkey[NUM_PKEYS] = {0}; + EVP_CIPHER_CTX *cctx = NULL; + unsigned char iv[16]; + unsigned char *ek[NUM_PKEYS] = {0}; + int ekl[NUM_PKEYS]; + unsigned char msg1[] = "Hello "; + unsigned char msg2[] = "World!"; + unsigned char cbuf[256]; + unsigned char mbuf[256]; + unsigned char *p; + int len, clen, mlen, i; + + + for (i = 0; i < NUM_PKEYS; i++) { + if (!(pkey[i] = genpkey(curve_id, out, verbose))) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + ekl[i] = MAX_PKEY_SIZE; + ek[i] = OPENSSL_malloc(ekl[i]); + } + RAND_bytes(iv, sizeof(iv)); + + if (!(cctx = EVP_CIPHER_CTX_new())) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if ((i = EVP_SealInit(cctx, cipher, ek, ekl, iv, pkey, NUM_PKEYS)) != NUM_PKEYS) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (verbose > 1) { + for (i = 0; i < NUM_PKEYS; i++) { + int j; + BIO_printf(out, "ek[%d] (%d-byte) = ", i, ekl[i]); + for (j = 0; j < ekl[i]; j++) { + BIO_printf(out, "%02X", ek[i][j]); + } + BIO_printf(out, "\n"); + } + } + + p = cbuf; + len = sizeof(cbuf); + if (!EVP_SealUpdate(cctx, p, &len, msg1, sizeof(msg1)-1)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + p += len; + + len = sizeof(cbuf) - (p - cbuf); + if (!EVP_SealUpdate(cctx, p, &len, msg2, sizeof(msg2)-1)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + p += len; + + len = sizeof(cbuf) - (p - cbuf); + if (!EVP_SealFinal(cctx, p, &len)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + p += len; + + clen = p - cbuf; + + if (verbose > 1) { + BIO_printf(out, "ciphertext (%d-byte) = ", clen); + for (i = 0; i < clen; i++) { + BIO_printf(out, "%02X", cbuf[i]); + } + BIO_printf(out, "\n"); + } + + if (!EVP_OpenInit(cctx, cipher, ek[1], ekl[1], iv, pkey[1])) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + memset(mbuf, 0, sizeof(mbuf)); + p = mbuf; + len = sizeof(mbuf); + + if (!EVP_OpenUpdate(cctx, p, &len, cbuf, clen)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + p += len; + len = sizeof(mbuf) - len; + + if (!EVP_OpenFinal(cctx, p, &len)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + p += len; + + mlen = p - mbuf; + + if (verbose > 1) { + BIO_printf(out, "message = %s%s\n", (char *)msg1, (char *)msg2); + BIO_printf(out, "message = %s\n", (char *)mbuf); + } + + if (verbose) { + BIO_printf(out, "%s() passed!\n", __FUNCTION__); + } + + ret = 1; + +end: + EVP_CIPHER_CTX_free(cctx); + for (i = 0; i < NUM_PKEYS; i++) { + EVP_PKEY_free(pkey[i]); + OPENSSL_free(ek[i]); + } + return ret; +} + +int test_sm2_evp(int verbose) +{ + int ret = 0; + EVP_PKEY *pkey = NULL; + BIO *out = NULL; + int curve_id = NID_sm2p256v1; + const EVP_MD *md = EVP_sm3(); + const EVP_CIPHER *cipher = EVP_sms4_cbc(); + + ERR_load_crypto_strings(); + + out = BIO_new_fp(stderr, BIO_NOCLOSE); + + if (!(pkey = genpkey(curve_id, out, verbose))) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + /* test sm2sign */ + if (!test_evp_pkey_sign(pkey, 1, verbose)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + /* test ecdsa */ + if (!test_evp_pkey_sign(pkey, 0, verbose)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + /* test sm2encrypt */ + if (!test_evp_pkey_encrypt(pkey, 1, verbose)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + /* test ecies */ + if (!test_evp_pkey_encrypt(pkey, 0, verbose)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + /* test ec default encrypt */ + if (!test_evp_pkey_encrypt_old(pkey, verbose)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + /* test ec default sign */ + if (!test_evp_sign(pkey, md, verbose)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + /* test seal/open */ + if (!test_evp_seal(curve_id, cipher, out, verbose)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + ret = 1; + +end: + if (ret != 1) { + ERR_print_errors_fp(stderr); + } + EVP_PKEY_free(pkey); + return ret; +} + +int main(int argc, char **argv) +{ + int ret = -1; + BIO *out = NULL; + + out = BIO_new_fp(stdout, BIO_NOCLOSE); + + /* + if (!((getenv("OPENSSL_DEBUG_MEMORY") != NULL) && + (0 == strcmp(getenv("OPENSSL_DEBUG_MEMORY"), "off")))) { + CRYPTO_malloc_debug_init(); + CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL); + } else { + CRYPTO_set_mem_debug_functions(0, 0, 0, 0, 0); + } + CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); + */ + + ERR_load_crypto_strings(); + RAND_seed(rnd_seed, sizeof(rnd_seed)); + + + if (!test_sm2_test_vector()) { + goto err; + } + + if (!test_sm2_evp(1)) { + goto err; + } + + ret =0; +err: + if (ret) + BIO_printf(out, "\nSM2 test failed\n"); + else BIO_printf(out, "\nSM2 test passed\n"); + + if (ret) + ERR_print_errors(out); + + //CRYPTO_cleanup_all_ex_data(); + //ERR_remove_thread_state(NULL); + //ERR_free_strings(); + //CRYPTO_mem_leaks(out); + //BIO_free(out); + + return ret; +} + diff --git a/test/sm2test.c b/test/sm2test.c new file mode 100644 index 00000000..14c2aba7 --- /dev/null +++ b/test/sm2test.c @@ -0,0 +1,846 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2016 The GmSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED 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 GmSSL PROJECT OR + * ITS CONTRIBUTORS 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. + * ==================================================================== + */ + +#include +#include +#include +#include "../e_os.h" + +#ifdef OPENSSL_NO_SM2 +int main(int argc, char **argv) +{ + printf("NO SM2 support\n"); + return 0; +} +#else +# include +# include +# include +# include +# include +# include + +RAND_METHOD fake_rand; +const RAND_METHOD *old_rand; + +static const char rnd_seed[] = + "string to make the random number generator think it has entropy"; +static const char *rnd_number = NULL; + +int fbytes(unsigned char *buf, int num) +{ + int ret = 0; + BIGNUM *bn = NULL; + + if (!BN_hex2bn(&bn, rnd_number)) { + goto end; + } + if (BN_num_bytes(bn) > num) { + goto end; + } + memset(buf, 0, num); + if (!BN_bn2bin(bn, buf + num - BN_num_bytes(bn))) { + goto end; + } + ret = 1; +end: + BN_free(bn); + return ret; +} + +int change_rand(const char *hex) +{ + if (!(old_rand = RAND_get_rand_method())) { + return 0; + } + + fake_rand.seed = old_rand->seed; + fake_rand.cleanup = old_rand->cleanup; + fake_rand.add = old_rand->add; + fake_rand.status = old_rand->status; + fake_rand.bytes = fbytes; + fake_rand.pseudorand = old_rand->bytes; + + if (!RAND_set_rand_method(&fake_rand)) { + return 0; + } + + rnd_number = hex; + return 1; +} + +int restore_rand(void) +{ + rnd_number = NULL; + if (!RAND_set_rand_method(old_rand)) + return 0; + else return 1; +} + +int hexequbin(const char *hex, const unsigned char *bin, size_t binlen) +{ + int ret = 0; + char *buf = NULL; + int i = 0; + size_t buflen = binlen * 2 + 1; + + + if (binlen * 2 != strlen(hex)) { + return 0; + } + if (!(buf = malloc(binlen * 2 + 1))) { + return 0; + } + for (i = 0; i < binlen; i++) { + sprintf(buf + i*2, "%02X", bin[i]); + } + buf[buflen - 1] = 0; + + if (memcmp(hex, buf, binlen * 2) == 0) { + ret = 1; + } + + free(buf); + return ret; +} + +EC_GROUP *new_ec_group(int is_prime_field, + const char *p_hex, const char *a_hex, const char *b_hex, + const char *x_hex, const char *y_hex, const char *n_hex, const char *h_hex) +{ + int ok = 0; + EC_GROUP *group = NULL; + BN_CTX *ctx = NULL; + BIGNUM *p = NULL; + BIGNUM *a = NULL; + BIGNUM *b = NULL; + BIGNUM *x = NULL; + BIGNUM *y = NULL; + BIGNUM *n = NULL; + BIGNUM *h = NULL; + EC_POINT *G = NULL; + point_conversion_form_t form = SM2_DEFAULT_POINT_CONVERSION_FORM; + int flag = 0; + + if (!(ctx = BN_CTX_new())) { + goto err; + } + + if (!BN_hex2bn(&p, p_hex) || + !BN_hex2bn(&a, a_hex) || + !BN_hex2bn(&b, b_hex) || + !BN_hex2bn(&x, x_hex) || + !BN_hex2bn(&y, y_hex) || + !BN_hex2bn(&n, n_hex) || + !BN_hex2bn(&h, h_hex)) { + goto err; + } + + if (is_prime_field) { + if (!(group = EC_GROUP_new_curve_GFp(p, a, b, ctx))) { + goto err; + } + if (!(G = EC_POINT_new(group))) { + goto err; + } + if (!EC_POINT_set_affine_coordinates_GFp(group, G, x, y, ctx)) { + goto err; + } + } else { + if (!(group = EC_GROUP_new_curve_GF2m(p, a, b, ctx))) { + goto err; + } + if (!(G = EC_POINT_new(group))) { + goto err; + } + if (!EC_POINT_set_affine_coordinates_GF2m(group, G, x, y, ctx)) { + goto err; + } + } + + if (!EC_GROUP_set_generator(group, G, n, h)) { + goto err; + } + + EC_GROUP_set_asn1_flag(group, flag); + EC_GROUP_set_point_conversion_form(group, form); + + ok = 1; +err: + BN_CTX_free(ctx); + BN_free(p); + BN_free(a); + BN_free(b); + BN_free(x); + BN_free(y); + BN_free(n); + BN_free(h); + EC_POINT_free(G); + if (!ok && group) { + ERR_print_errors_fp(stderr); + EC_GROUP_free(group); + group = NULL; + } + + return group; +} + +EC_KEY *new_ec_key(const EC_GROUP *group, + const char *sk, const char *xP, const char *yP, + const char *id, const EVP_MD *id_md) +{ + int ok = 0; + EC_KEY *ec_key = NULL; + BIGNUM *d = NULL; + BIGNUM *x = NULL; + BIGNUM *y = NULL; + + OPENSSL_assert(group); + OPENSSL_assert(xP); + OPENSSL_assert(yP); + + if (!(ec_key = EC_KEY_new())) { + goto end; + } + if (!EC_KEY_set_group(ec_key, group)) { + goto end; + } + + if (sk) { + if (!BN_hex2bn(&d, sk)) { + goto end; + } + if (!EC_KEY_set_private_key(ec_key, d)) { + goto end; + } + } + + if (xP && yP) { + if (!BN_hex2bn(&x, xP)) { + goto end; + } + if (!BN_hex2bn(&y, yP)) { + goto end; + } + if (!EC_KEY_set_public_key_affine_coordinates(ec_key, x, y)) { + goto end; + } + } + + /* + if (id) { + if (!SM2_set_id(ec_key, id, id_md)) { + goto end; + } + } + */ + + ok = 1; +end: + if (d) BN_free(d); + if (x) BN_free(x); + if (y) BN_free(y); + if (!ok && ec_key) { + ERR_print_errors_fp(stderr); + EC_KEY_free(ec_key); + ec_key = NULL; + } + return ec_key; +} + +int test_sm2_sign(const EC_GROUP *group, + const char *sk, const char *xP, const char *yP, + const char *id, const char *Z, + const char *M, const char *e, + const char *k, const char *r, const char *s) +{ + int ret = 0; + const EVP_MD *id_md = EVP_sm3(); + const EVP_MD *msg_md = EVP_sm3(); + int type = NID_undef; + unsigned char dgst[EVP_MAX_MD_SIZE]; + size_t dgstlen; + unsigned char sig[256]; + unsigned int siglen; + const unsigned char *p; + EC_KEY *ec_key = NULL; + EC_KEY *pubkey = NULL; + ECDSA_SIG *sm2sig = NULL; + BIGNUM *rr = NULL; + BIGNUM *ss = NULL; + const BIGNUM *sig_r; + const BIGNUM *sig_s; + + change_rand(k); + + if (!(ec_key = new_ec_key(group, sk, xP, yP, id, id_md))) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + EC_KEY_print_fp(stdout, ec_key, 4); + + + dgstlen = sizeof(dgst); + if (!SM2_compute_id_digest(id_md, id, strlen(id), dgst, &dgstlen, ec_key)) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + printf("id=%s\n", id); + printf("zid(xx):"); for (int j = 0; j < dgstlen; j++) { printf("%02x", dgst[j]); } printf("\n"); + if (!hexequbin(Z, dgst, dgstlen)) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + + dgstlen = sizeof(dgst); + if (!SM2_compute_message_digest(id_md, msg_md, + (const unsigned char *)M, strlen(M), id, strlen(id), + dgst, &dgstlen, ec_key)) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + if (!hexequbin(e, dgst, dgstlen)) { + int i; + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + + printf("%s\n", e); + printf(" my: "); for (i = 0; i < dgstlen; i++) { printf("%02x", dgst[i]); } printf("\n"); + + goto err; + } + + + /* sign */ + siglen = sizeof(sig); + if (!SM2_sign(type, dgst, dgstlen, sig, &siglen, ec_key)) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + + p = sig; + if (!(sm2sig = d2i_ECDSA_SIG(NULL, &p, siglen))) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + if (!BN_hex2bn(&rr, r) || !BN_hex2bn(&ss, s)) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + + ECDSA_SIG_get0(sm2sig, &sig_r, &sig_s); + + if (BN_cmp(sig_r, rr) || BN_cmp(sig_s, ss)) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + + + /* verify */ + if (!(pubkey = new_ec_key(group, NULL, xP, yP, id, id_md))) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + fprintf(stderr, " -> %d\n", __LINE__); + if (1 != SM2_verify(type, dgst, dgstlen, sig, siglen, pubkey)) { + fprintf(stderr, "error: %s %d\n", __FUNCTION__, __LINE__); + goto err; + } + + ret = 1; +err: + restore_rand(); + if (ec_key) EC_KEY_free(ec_key); + if (pubkey) EC_KEY_free(pubkey); + if (sm2sig) ECDSA_SIG_free(sm2sig); + if (rr) BN_free(rr); + if (ss) BN_free(ss); + return ret; +} + +int test_sm2_enc(const EC_GROUP *group, + const char *d, const char *xP, const char *yP, + const char *M, + const char *k, const char *C) +{ + int ret = 0; + EC_KEY *ec_key = NULL; + const EVP_MD *kdf_md = EVP_sm3(); + const EVP_MD *mac_md = EVP_sm3(); + point_conversion_form_t point_form = POINT_CONVERSION_UNCOMPRESSED; + unsigned char msg[128]; + unsigned char buf[sizeof(msg) + 128]; + size_t msglen, buflen; + + change_rand(k); + + if (!(ec_key = new_ec_key(group, NULL, xP, yP, NULL, NULL))) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + buflen = sizeof(buf); + if (!SM2_encrypt_with_recommended( + (const unsigned char *)M, strlen(M), + buf, &buflen, + ec_key)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + + if (!hexequbin(C, buf, buflen)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + printf("shit\n"); + goto end; + } + EC_KEY_free(ec_key); + + if (!(ec_key = new_ec_key(group, d, xP, yP, NULL, NULL))) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + if (!SM2_decrypt_with_recommended( + buf, buflen, + msg, &msglen, + ec_key)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + if (msglen != strlen(M) || memcmp(msg, M, strlen(M))) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + ret = 1; + +end: + ERR_print_errors_fp(stderr); + restore_rand(); + EC_KEY_free(ec_key); + return ret; +} + +int test_sm2_kap(const EC_GROUP *group, + const char *A, const char *dA, const char *xA, const char *yA, const char *ZA, + const char *B, const char *dB, const char *xB, const char *yB, const char *ZB, + const char *rA, const char *rB, const char *KAB, const char *S1, const char *S2) +{ + int ret = 0; + const EVP_MD *id_md = EVP_sm3(); + EC_KEY *eckeyA = NULL; + EC_KEY *eckeyB = NULL; + EC_KEY *pubkeyA = NULL; + EC_KEY *pubkeyB = NULL; + SM2_KAP_CTX ctxA; + SM2_KAP_CTX ctxB; + unsigned char za[EVP_MAX_MD_SIZE]; + unsigned char zb[EVP_MAX_MD_SIZE]; + size_t zalen, zblen; + unsigned char RA[256]; + unsigned char RB[256]; + size_t RAlen = sizeof(RA); + size_t RBlen = sizeof(RB); + unsigned char kab[64]; + unsigned char kba[64]; + size_t kablen = strlen(KAB)/2; + size_t kbalen = strlen(KAB)/2; + unsigned char s1[64]; + unsigned char s2[64]; + size_t s1len, s2len; + + memset(&ctxA, 0, sizeof(ctxA)); + memset(&ctxB, 0, sizeof(ctxB)); + + + eckeyA = new_ec_key(group, dA, xA, yA, A, id_md); + eckeyB = new_ec_key(group, dB, xB, yB, B, id_md); + pubkeyA = new_ec_key(group, NULL, xA, yA, A, id_md); + pubkeyB = new_ec_key(group, NULL, xB, yB, B, id_md); + if (!eckeyA || !eckeyB || !pubkeyA || !pubkeyB) { + goto end; + } + + /* + zalen = sizeof(za); + if (!SM2_get_id_digest(eckeyA, za, &zalen)) { + goto end; + } + zblen = sizeof(zb); + if (!SM2_get_id_digest(eckeyB, zb, &zblen)) { + goto end; + } + */ + + if (!hexequbin(ZA, za, zalen)) { + fprintf(stderr, "error (%s %d): ZA != value in test vector !!!\n", __FILE__, __LINE__); + goto end; + } + + if (!hexequbin(ZB, zb, zblen)) { + goto end; + } + + if (!SM2_KAP_CTX_init(&ctxA, eckeyA, ZA, strlen(ZA), pubkeyB, ZB, strlen(ZB), 1, 1)) { + goto end; + } + if (!SM2_KAP_CTX_init(&ctxB, eckeyB, ZB, strlen(ZB), pubkeyA, ZA, strlen(ZA), 0, 1)) { + goto end; + } + + change_rand(rA); + if (!SM2_KAP_prepare(&ctxA, RA, &RAlen)) { + goto end; + } + restore_rand(); + + change_rand(rB); + if (!SM2_KAP_prepare(&ctxB, RB, &RBlen)) { + goto end; + } + restore_rand(); + + + if (!SM2_KAP_compute_key(&ctxA, RB, RBlen, kab, kablen, s1, &s1len)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + + if (!SM2_KAP_compute_key(&ctxB, RA, RAlen, kba, kbalen, s2, &s2len)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!SM2_KAP_final_check(&ctxA, s2, s2len)) { + goto end; + } + if (!SM2_KAP_final_check(&ctxB, s1, s1len)) { + goto end; + } + + ret = 1; + +end: + EC_KEY_free(eckeyA); + EC_KEY_free(eckeyB); + EC_KEY_free(pubkeyA); + EC_KEY_free(pubkeyB); + SM2_KAP_CTX_cleanup(&ctxA); + SM2_KAP_CTX_cleanup(&ctxB); + return ret; +} + +int test_sm2_test_vector() +{ + int ret = 0; + EC_GROUP *sm2p192test = NULL; + EC_GROUP *sm2p256test = NULL; + EC_GROUP *sm2b193test = NULL; + EC_GROUP *sm2b257test = NULL; + + sm2p192test = new_ec_group(1, + "BDB6F4FE3E8B1D9E0DA8C0D46F4C318CEFE4AFE3B6B8551F", + "BB8E5E8FBC115E139FE6A814FE48AAA6F0ADA1AA5DF91985", + "1854BEBDC31B21B7AEFC80AB0ECD10D5B1B3308E6DBF11C1", + "4AD5F7048DE709AD51236DE65E4D4B482C836DC6E4106640", + "02BB3A02D4AAADACAE24817A4CA3A1B014B5270432DB27D2", + "BDB6F4FE3E8B1D9E0DA8C0D40FC962195DFAE76F56564677", + "1"); + + sm2p256test = new_ec_group(1, + "8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", + "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", + "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", + "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", + "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", + "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", + "1"); + + sm2b193test = new_ec_group(0, + "2000000000000000000000000000000000000000000008001", + "0", + "002FE22037B624DBEBC4C618E13FD998B1A18E1EE0D05C46FB", + "00D78D47E85C93644071BC1C212CF994E4D21293AAD8060A84", + "00615B9E98A31B7B2FDDEEECB76B5D875586293725F9D2FC0C", + "80000000000000000000000043E9885C46BF45D8C5EBF3A1", + "1"); + + sm2b257test = new_ec_group(0, + "20000000000000000000000000000000000000000000000000000000000001001", + "0", + "00E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B", + "00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD", + "013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E", + "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC972CF7E6B6F900945B3C6A0CF6161D", + "4"); + + if (!sm2p192test || !sm2p256test || !sm2b193test || !sm2b257test) { + goto end; + } + + if (!test_sm2_sign( + sm2p256test, + "128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263", + "0AE4C7798AA0F119471BEE11825BE46202BB79E2A5844495E97C04FF4DF2548A", + "7C0240F88F1CD4E16352A73C17B7F16F07353E53A176D684A9FE0C6BB798E857", + "ALICE123@YAHOO.COM", + "F4A38489E32B45B6F876E3AC2168CA392362DC8F23459C1D1146FC3DBFB7BC9A", + "message digest", + "B524F552CD82B8B028476E005C377FB19A87E6FC682D48BB5D42E3D9B9EFFE76", + "6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F", + "40F1EC59F793D9F49E09DCEF49130D4194F79FB1EED2CAA55BACDB49C4E755D1", + "6FC6DAC32C5D5CF10C77DFB20F7C2EB667A457872FB09EC56327A67EC7DEEBE7")) { + printf("sm2 sign p256 failed\n"); + goto end; + } else { + printf("sm2 sign p256 passed\n"); + } + + + if (!test_sm2_sign( + sm2b257test, + "771EF3DBFF5F1CDC32B9C572930476191998B2BF7CB981D7F5B39202645F0931", + "0165961645281A8626607B917F657D7E9382F1EA5CD931F40F6627F357542653B2", + "01686522130D590FB8DE635D8FCA715CC6BF3D05BEF3F75DA5D543454448166612", + "ALICE123@YAHOO.COM", + "26352AF82EC19F207BBC6F9474E11E90CE0F7DDACE03B27F801817E897A81FD5", + "message digest", + "AD673CBDA311417129A9EAA5F9AB1AA1633AD47718A84DFD46C17C6FA0AA3B12", + "36CD79FC8E24B7357A8A7B4A46D454C397703D6498158C605399B341ADA186D6", + "6D3FBA26EAB2A1054F5D198332E335817C8AC453ED26D3391CD4439D825BF25B", + "3124C5688D95F0A10252A9BED033BEC84439DA384621B6D6FAD77F94B74A9556")) { + printf("sm2 sign b257 failed\n"); + goto end; + } else { + printf("sm2 sign b257 passed\n"); + } + + if (!test_sm2_enc( + sm2p256test, + "1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0", + "435B39CCA8F3B508C1488AFC67BE491A0F7BA07E581A0E4849A5CF70628A7E0A", + "75DDBA78F15FEECB4C7895E2C1CDF5FE01DEBB2CDBADF45399CCF77BBA076A42", + "encryption standard", + "4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F", + "04" + "245C26FB68B1DDDDB12C4B6BF9F2B6D5FE60A383B0D18D1C4144ABF17F6252E7" + "76CB9264C2A7E88E52B19903FDC47378F605E36811F5C07423A24B84400F01B8" + "650053A89B41C418B0C3AAD00D886C00286467" + "9C3D7360C30156FAB7C80A0276712DA9D8094A634B766D3A285E07480653426D")) { + printf("sm2 enc p256 failed\n"); + goto end; + } else { + printf("sm2 enc p256 passed\n"); + } + + if (!test_sm2_enc( + sm2b257test, + "56A270D17377AA9A367CFA82E46FA5267713A9B91101D0777B07FCE018C757EB", + "00A67941E6DE8A61805F7BCFF0985BB3BED986F1C297E4D8880D82B821C624EE57", + "0193ED5A6707B5908781B860841085F52EEFA7FE329A5C811843533A874D027271", + "encryption standard", + "6D3B497153E3E92524E5C122682DBDC8705062E20B917A5F8FCDB8EE4C66663D", + "04" + "019D236DDB305009AD52C51BB932709BD534D476FBB7B0DF9542A8A4D890A3F2E1" + "00B23B938DC0A94D1DF8F42CF45D2D6601BF638C3D7DE75A29F02AFB7E45E91771" + "FD55AC6213C2A8A040E4CAB5B26A9CFCDA7373" + "73A48625D3758FA37B3EAB80E9CFCABA665E3199EA15A1FA8189D96F579125E4")) { + printf("sm2 enc b257 failed\n"); + goto end; + } else { + printf("sm2 enc b257 passed\n"); + } + + if (!test_sm2_kap( + sm2p256test, + "ALICE123@YAHOO.COM", + "6FCBA2EF9AE0AB902BC3BDE3FF915D44BA4CC78F88E2F8E7F8996D3B8CCEEDEE", + "3099093BF3C137D8FCBBCDF4A2AE50F3B0F216C3122D79425FE03A45DBFE1655", + "3DF79E8DAC1CF0ECBAA2F2B49D51A4B387F2EFAF482339086A27A8E05BAED98B", + "E4D1D0C3CA4C7F11BC8FF8CB3F4C02A78F108FA098E51A668487240F75E20F31", + "BILL456@YAHOO.COM", + "5E35D7D3F3C54DBAC72E61819E730B019A84208CA3A35E4C2E353DFCCB2A3B53", + "245493D446C38D8CC0F118374690E7DF633A8A4BFB3329B5ECE604B2B4F37F43", + "53C0869F4B9E17773DE68FEC45E14904E0DEA45BF6CECF9918C85EA047C60A4C", + "6B4B6D0E276691BD4A11BF72F4FB501AE309FDACB72FA6CC336E6656119ABD67", + "83A2C9C8B96E5AF70BD480B472409A9A327257F1EBB73F5B073354B248668563", + "33FE21940342161C55619C4A0C060293D543C80AF19748CE176D83477DE71C80", + "55B0AC62A6B927BA23703832C853DED4", + "284C8F198F141B502E81250F1581C7E9EEB4CA6990F9E02DF388B45471F5BC5C", + "23444DAF8ED7534366CB901C84B3BDBB63504F4065C1116C91A4C00697E6CF7A")) { + printf("sm2 kap p256 failed\n"); + goto end; + } else { + printf("sm2 kap p256 passed\n"); + } + +#if 0 + /* ZA will not pass! */ + if (!test_sm2_kap( + sm2b257test, + "ALICE123@YAHOO.COM", + "4813903D254F2C20A94BC5704238496954BB5279F861952EF2C5298E84D2CEAA", + "008E3BDB2E11F9193388F1F901CCC857BF49CFC065FB38B9069CAAE6D5AFC3592F", + "004555122AAC0075F42E0A8BBD2C0665C789120DF19D77B4E3EE4712F598040415", + "ECF0080215977B2E5D6D61B98A99442F03E8803DC39E349F8DCA5621A9ACDF2B", + "BILL456@YAHOO.COM", + "08F41BAE0922F47C212803FE681AD52B9BF28A35E1CD0EC273A2CF813E8FD1DC", + "0034297DD83AB14D5B393B6712F32B2F2E938D4690B095424B89DA880C52D4A7D9", + "0199BBF11AC95A0EA34BBD00CA50B93EC24ACB68335D20BA5DCFE3B33BDBD2B62D", + "557BAD30 E183559A EEC3B2256E1C7C11F870D22B165D015ACF9465B09B87B527", + "54A3D6673FF3A6BD6B02EBB164C2A3AF6D4A4906229D9BFCE68CC366A2E64BA4", + "1F21933387BEF781D0A8F7FD708C5AE0A56EE3F423DBC2FE5BDF6F068C53F7AD", + "4E587E5C66634F22D973A7D98BF8BE23", + "4EB47D28AD3906D6244D01E0F6AEC73B0B51DE1574C13798184E4833DBAE295A", + "588AA67064F24DC27CCAA1FAB7E27DFF811D500AD7EF2FB8F69DDF48CC0FECB7")) { + printf("sm2 kap b257 failed\n"); + goto end; + } else { + printf("sm2 kap b257 passed\n"); + } +#endif + + ret = 1; + +end: + EC_GROUP_free(sm2p192test); + EC_GROUP_free(sm2p256test); + EC_GROUP_free(sm2b193test); + EC_GROUP_free(sm2b257test); + + return ret; +} + + +EVP_PKEY *genpkey(int curve_nid, BIO *out, int verbose) +{ + int ok = 0; + EVP_PKEY *ret = NULL; + EVP_PKEY_CTX *pkctx = NULL; + + if (!(pkctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_PKEY_keygen_init(pkctx)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pkctx, curve_nid)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (!EVP_PKEY_keygen(pkctx, &ret)) { + fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__); + goto end; + } + + if (verbose > 1) { + EVP_PKEY_print_private(out, ret, 4, NULL); + BIO_printf(out, "\n"); + } + + ok = 1; +end: + if (!ok && ret) { + EVP_PKEY_free(ret); + ret = NULL; + } + EVP_PKEY_CTX_free(pkctx); + return ret; +} + +int main(int argc, char **argv) +{ + int ret = -1; + BIO *out = NULL; + + out = BIO_new_fp(stdout, BIO_NOCLOSE); + + /* + if (!((getenv("OPENSSL_DEBUG_MEMORY") != NULL) && + (0 == strcmp(getenv("OPENSSL_DEBUG_MEMORY"), "off")))) { + CRYPTO_malloc_debug_init(); + CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL); + } else { + CRYPTO_set_mem_debug_functions(0, 0, 0, 0, 0); + } + CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); + */ + + ERR_load_crypto_strings(); + RAND_seed(rnd_seed, sizeof(rnd_seed)); + + + if (!test_sm2_test_vector()) { + goto err; + } + + + ret =0; +err: + if (ret) + BIO_printf(out, "\nSM2 test failed\n"); + else BIO_printf(out, "\nSM2 test passed\n"); + + if (ret) + ERR_print_errors(out); + + //CRYPTO_cleanup_all_ex_data(); + //ERR_remove_thread_state(NULL); + //ERR_free_strings(); + //CRYPTO_mem_leaks(out); + //BIO_free(out); + + return ret; +} +#endif diff --git a/test/sm3test.c b/test/sm3test.c index 81f1ee6d..0cd146df 100644 --- a/test/sm3test.c +++ b/test/sm3test.c @@ -221,7 +221,7 @@ int main(int argc, char **argv) p = pt(dgst); if (memcmp(dgstbuf, dgst, dgstlen) != 0) { printf("error calculating SM3 on %s\n", testhex[i]); - printf("got %s instead of %s\n", p, testhex[i]); + printf("got %s instead of %s\n", p, dgsthex[i]); } else { printf("test %d ok\n", i+1); } diff --git a/util/shlib_wrap.sh b/util/shlib_wrap.sh deleted file mode 100755 index 811a08d6..00000000 --- a/util/shlib_wrap.sh +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/sh - -[ $# -ne 0 ] || set -x # debug mode without arguments:-) - -THERE="`echo $0 | sed -e 's|[^/]*$||' 2>/dev/null`.." -[ -d "${THERE}" ] || exec "$@" # should never happen... - -# Alternative to this is to parse ${THERE}/Makefile... -LIBCRYPTOSO="${THERE}/libcrypto.so" -if [ -f "$LIBCRYPTOSO" ]; then - while [ -h "$LIBCRYPTOSO" ]; do - LIBCRYPTOSO="${THERE}/`ls -l "$LIBCRYPTOSO" | sed -e 's|.*\-> ||'`" - done - SOSUFFIX=`echo ${LIBCRYPTOSO} | sed -e 's|.*\.so||' 2>/dev/null` - LIBSSLSO="${THERE}/libssl.so${SOSUFFIX}" -fi - -SYSNAME=`(uname -s) 2>/dev/null`; -case "$SYSNAME" in -SunOS|IRIX*) - # SunOS and IRIX run-time linkers evaluate alternative - # variables depending on target ABI... - rld_var=LD_LIBRARY_PATH - case "`(/usr/bin/file "$LIBCRYPTOSO") 2>/dev/null`" in - *ELF\ 64*SPARC*|*ELF\ 64*AMD64*) - [ -n "$LD_LIBRARY_PATH_64" ] && rld_var=LD_LIBRARY_PATH_64 - LD_PRELOAD_64="$LIBCRYPTOSO $LIBSSLSO"; export LD_PRELOAD_64 - preload_var=LD_PRELOAD_64 - ;; - *ELF\ 32*SPARC*|*ELF\ 32*80386*) - # We only need to change LD_PRELOAD_32 and LD_LIBRARY_PATH_32 - # on a multi-arch system. Otherwise, trust the fallbacks. - if [ -f /lib/64/ld.so.1 ]; then - [ -n "$LD_LIBRARY_PATH_32" ] && rld_var=LD_LIBRARY_PATH_32 - LD_PRELOAD_32="$LIBCRYPTOSO $LIBSSLSO"; export LD_PRELOAD_32 - preload_var=LD_PRELOAD_32 - fi - ;; - # Why are newly built .so's preloaded anyway? Because run-time - # .so lookup path embedded into application takes precedence - # over LD_LIBRARY_PATH and as result application ends up linking - # to previously installed .so's. On IRIX instead of preloading - # newly built .so's we trick run-time linker to fail to find - # the installed .so by setting _RLD_ROOT variable. - *ELF\ 32*MIPS*) - #_RLD_LIST="$LIBCRYPTOSO:$LIBSSLSO:DEFAULT"; export _RLD_LIST - _RLD_ROOT=/no/such/dir; export _RLD_ROOT - eval $rld_var=\"/usr/lib'${'$rld_var':+:$'$rld_var'}'\" - preload_var=_RLD_LIST - ;; - *ELF\ N32*MIPS*) - [ -n "$LD_LIBRARYN32_PATH" ] && rld_var=LD_LIBRARYN32_PATH - #_RLDN32_LIST="$LIBCRYPTOSO:$LIBSSLSO:DEFAULT"; export _RLDN32_LIST - _RLDN32_ROOT=/no/such/dir; export _RLDN32_ROOT - eval $rld_var=\"/usr/lib32'${'$rld_var':+:$'$rld_var'}'\" - preload_var=_RLDN32_LIST - ;; - *ELF\ 64*MIPS*) - [ -n "$LD_LIBRARY64_PATH" ] && rld_var=LD_LIBRARY64_PATH - #_RLD64_LIST="$LIBCRYPTOSO:$LIBSSLSO:DEFAULT"; export _RLD64_LIST - _RLD64_ROOT=/no/such/dir; export _RLD64_ROOT - eval $rld_var=\"/usr/lib64'${'$rld_var':+:$'$rld_var'}'\" - preload_var=_RLD64_LIST - ;; - esac - eval $rld_var=\"${THERE}'${'$rld_var':+:$'$rld_var'}'\"; export $rld_var - unset rld_var - ;; -*) LD_LIBRARY_PATH="${THERE}:$LD_LIBRARY_PATH" # Linux, ELF HP-UX - DYLD_LIBRARY_PATH="${THERE}:$DYLD_LIBRARY_PATH" # MacOS X - SHLIB_PATH="${THERE}:$SHLIB_PATH" # legacy HP-UX - LIBPATH="${THERE}:$LIBPATH" # AIX, OS/2 - export LD_LIBRARY_PATH DYLD_LIBRARY_PATH SHLIB_PATH LIBPATH - # Even though $PATH is adjusted [for Windows sake], it doesn't - # necessarily does the trick. Trouble is that with introduction - # of SafeDllSearchMode in XP/2003 it's more appropriate to copy - # .DLLs in vicinity of executable, which is done elsewhere... - if [ "$OSTYPE" != msdosdjgpp ]; then - PATH="${THERE}:$PATH"; export PATH - fi - ;; -esac - - - -cmd="$1"; [ -x "$cmd" ] || cmd="$cmd${EXE_EXT}" -shift -if [ $# -eq 0 ]; then - exec "$cmd" # old sh, such as Tru64 4.x, fails to expand empty "$@" -else - exec "$cmd" "$@" -fi