mirror of
https://github.com/guanzhi/GmSSL.git
synced 2026-05-07 00:46:17 +08:00
921 lines
24 KiB
C
921 lines
24 KiB
C
/* ====================================================================
|
|
* 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 <stdio.h>
|
|
#include <openssl/ec.h>
|
|
#include <openssl/sm2.h>
|
|
#include <openssl/gmapi.h>
|
|
#include <openssl/gmsdf.h>
|
|
#include "sdf_lcl.h"
|
|
|
|
/*
|
|
* For all the ECC signing/verification, the to be signed data `pucData`
|
|
* should be the digest of the message, instead of the original message. If
|
|
* the application requires a GM standard signature with the hashed identity
|
|
* `Z`, then `SDF_HashInit` must be called with the `pucPublicKey` and
|
|
* `pucID` provided.
|
|
*/
|
|
|
|
/*
|
|
* some of these functions require an `uiAlgID` to specify the algorithm.
|
|
* Currently only `SGD_SM2_1` and `SGD_SM2_3` should be used. Maybe for some
|
|
* implementations might also support international algorithms such as ECDSA
|
|
* and ECIES.
|
|
*/
|
|
/*
|
|
* there are limits on the max size of input plaintext, for SM2 encryptions,
|
|
* the length will be equal to the `ECCref_MAX_CIPHER_LEN`
|
|
*/
|
|
/*
|
|
* Symmetric Encryption:
|
|
* `SDF_Encrypt`
|
|
* `SDF_Decrypt`
|
|
*
|
|
* we will not provide two-step operations for SDF API which means the
|
|
* caller can not assign the `pucEnData` to be NULL hoping that the API will
|
|
* return the proper out length through `*puiEncDataLength`. The reason is
|
|
* that the maximum output length can be easily estimated in almost all the
|
|
* APIs of SDF. So when `pucEncData` is NULL or `*puiEncDataLength` is not
|
|
* large enough, the API will just return with an error.
|
|
*
|
|
* The implementation will not carefully to estimate the output length, so
|
|
* always prepare the max output buffer. For exmaple, prepare at least two
|
|
* extra blocks for symmetric encryption, prepare max digest length of known
|
|
* hash functions as the MAC buffer size.
|
|
*
|
|
* Note: the GM/T 0018-2012 standard requires the implementation MUST NOT do
|
|
* any padding operatons, and the input data length should be multiple block
|
|
* length. Thus these two functions can be used for modes such as CBC, the
|
|
* caller can use a function more than once and do the padding himself.
|
|
*/
|
|
|
|
|
|
|
|
int SDF_GenerateKeyPair_ECC(
|
|
void *hSessionHandle,
|
|
unsigned int uiAlgID,
|
|
unsigned int uiKeyBits,
|
|
ECCrefPublicKey *pucPublicKey,
|
|
ECCrefPrivateKey *pucPrivateKey)
|
|
{
|
|
int ret = SDR_UNKNOWERR;
|
|
EC_KEY *ec_key = NULL;
|
|
|
|
/* check arguments */
|
|
if (!hSessionHandle || !pucPublicKey || !pucPrivateKey) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYPAIR_ECC,
|
|
ERR_R_PASSED_NULL_PARAMETER);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
if (uiAlgID != SGD_SM2 && uiAlgID != SGD_SM2_1 &&
|
|
uiAlgID != SGD_SM2_2 && uiAlgID != SGD_SM2_3) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYPAIR_ECC,
|
|
SDF_R_INVALID_ALGOR);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
if (uiKeyBits != 256) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYPAIR_ECC,
|
|
SDF_R_INVALID_KEY_LENGTH);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
|
|
/* generate */
|
|
if(!(ec_key = EC_KEY_new_by_curve_name(NID_sm2p256v1))) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYPAIR_ECC, ERR_R_EC_LIB);
|
|
goto end;
|
|
}
|
|
|
|
/* convert */
|
|
if (!EC_KEY_get_ECCrefPublicKey(ec_key, pucPublicKey)) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYPAIR_ECC,
|
|
SDF_R_GET_PUBLIC_KEY_FAILED);
|
|
goto end;
|
|
}
|
|
if (!EC_KEY_get_ECCrefPrivateKey(ec_key, pucPrivateKey)) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYPAIR_ECC,
|
|
SDF_R_GET_PRIVATE_KEY_FAILED);
|
|
goto end;
|
|
}
|
|
|
|
ret = SAR_OK;
|
|
end:
|
|
EC_KEY_free(ec_key);
|
|
return ret;
|
|
}
|
|
|
|
int SDF_ExportSignPublicKey_ECC(
|
|
void *hSessionHandle,
|
|
unsigned int uiKeyIndex,
|
|
ECCrefPublicKey *pucPublicKey)
|
|
{
|
|
int ret = SDR_UNKNOWERR;
|
|
EVP_PKEY *pkey = NULL;
|
|
unsigned int uiKeyUsage = SGD_SM2_1;
|
|
|
|
/* check arguments */
|
|
if (!hSessionHandle || !pucPublicKey) {
|
|
SDFerr(SDF_F_SDF_EXPORTSIGNPUBLICKEY_ECC,
|
|
ERR_R_PASSED_NULL_PARAMETER);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
|
|
/* load key */
|
|
if (!(pkey = sdf_load_ec_public_key(hSessionHandle,
|
|
uiKeyIndex, uiKeyUsage))) {
|
|
SDFerr(SDF_F_SDF_EXPORTSIGNPUBLICKEY_ECC,
|
|
ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
|
|
/* set return value */
|
|
if (!EC_KEY_get_ECCrefPublicKey(EVP_PKEY_get0_EC_KEY(pkey),
|
|
pucPublicKey)) {
|
|
SDFerr(SDF_F_SDF_EXPORTSIGNPUBLICKEY_ECC,
|
|
ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
ret = SDR_OK;
|
|
|
|
end:
|
|
EVP_PKEY_free(pkey);
|
|
return ret;
|
|
}
|
|
|
|
int SDF_ExportEncPublicKey_ECC(
|
|
void *hSessionHandle,
|
|
unsigned int uiKeyIndex,
|
|
ECCrefPublicKey *pucPublicKey)
|
|
{
|
|
int ret = SDR_UNKNOWERR;
|
|
EVP_PKEY *pkey = NULL;
|
|
unsigned int uiKeyUsage = 1;
|
|
|
|
/* check arguments */
|
|
if (!hSessionHandle || !pucPublicKey) {
|
|
SDFerr(SDF_F_SDF_EXPORTENCPUBLICKEY_ECC,
|
|
ERR_R_PASSED_NULL_PARAMETER);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
|
|
/* load key */
|
|
if (!(pkey = sdf_load_ec_public_key(hSessionHandle,
|
|
uiKeyIndex, uiKeyUsage))) {
|
|
SDFerr(SDF_F_SDF_EXPORTENCPUBLICKEY_ECC,
|
|
ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
|
|
/* set return value */
|
|
if (!EC_KEY_get_ECCrefPublicKey(EVP_PKEY_get0_EC_KEY(pkey),
|
|
pucPublicKey)) {
|
|
SDFerr(SDF_F_SDF_EXPORTENCPUBLICKEY_ECC,
|
|
ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
ret = SDR_OK;
|
|
|
|
end:
|
|
EVP_PKEY_free(pkey);
|
|
return ret;
|
|
}
|
|
|
|
int SDF_GenerateAgreementDataWithECC(
|
|
void *hSessionHandle,
|
|
unsigned int uiISKIndex,
|
|
unsigned int uiKeyBits,
|
|
unsigned char *pucSponsorID,
|
|
unsigned int uiSponsorIDLength,
|
|
ECCrefPublicKey *pucSponsorPublicKey,
|
|
ECCrefPublicKey *pucSponsorTmpPublicKey,
|
|
void **phAgreementHandle)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int SDF_GenerateKeyWithECC(
|
|
void *hSessionHandle,
|
|
unsigned char *pucResponseID,
|
|
unsigned int uiResponseIDLength,
|
|
ECCrefPublicKey *pucResponsePublicKey,
|
|
ECCrefPublicKey *pucResponseTmpPublicKey,
|
|
void *hAgreementHandle,
|
|
void **phKeyHandle)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int SDF_GenerateAgreementDataAndKeyWithECC(
|
|
void *hSessionHandle,
|
|
unsigned int uiISKIndex,
|
|
unsigned int uiKeyBits,
|
|
unsigned char *pucResponseID,
|
|
unsigned int uiResponseIDLength,
|
|
unsigned char *pucSponsorID,
|
|
unsigned int uiSponsorIDLength,
|
|
ECCrefPublicKey *pucSponsorPublicKey,
|
|
ECCrefPublicKey *pucSponsorTmpPublicKey,
|
|
ECCrefPublicKey *pucResponsePublicKey,
|
|
ECCrefPublicKey *pucResponseTmpPublicKey,
|
|
void **phKeyHandle)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* generate a session key and encrypt it with internal public key
|
|
* we can first random a key,
|
|
* export the public key,
|
|
* and then use the SDF_GenerateKeyWithEPK_ECC to encrypt the key
|
|
* the output key handle is only a pointer to the key buffer.
|
|
*/
|
|
int SDF_GenerateKeyWithIPK_ECC(
|
|
void *hSessionHandle,
|
|
unsigned int uiIPKIndex,
|
|
unsigned int uiKeyBits, /* output session key length */
|
|
ECCCipher *pucKey,
|
|
void **phKeyHandle)
|
|
{
|
|
int ret = SDR_UNKNOWERR;
|
|
SDF_KEY *key = NULL;
|
|
unsigned int uiAlgID = SGD_SM2_3;
|
|
|
|
/* check arguments */
|
|
if (!hSessionHandle || !pucKey || !phKeyHandle) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYWITHIPK_ECC,
|
|
ERR_R_PASSED_NULL_PARAMETER);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
if (uiKeyBits <= 0 || uiKeyBits > EVP_MAX_KEY_LENGTH * 8 ||
|
|
uiKeyBits % 8) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYWITHIPK_ECC,
|
|
SDF_R_INVALID_KEY_LENGTH);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
|
|
/* random key */
|
|
if (!(key = OPENSSL_zalloc(sizeof(*key)))) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYWITHIPK_ECC,
|
|
ERR_R_MALLOC_FAILURE);
|
|
goto end;
|
|
}
|
|
key->keylen = uiKeyBits/8;
|
|
if ((ret = SDF_GenerateRandom(hSessionHandle, key->keylen,
|
|
key->key)) != SDR_OK) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYWITHIPK_ECC,
|
|
ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
|
|
/* encrypt key with external ec public key */
|
|
if ((ret = SDF_InternalEncrypt_ECC(
|
|
hSessionHandle,
|
|
uiIPKIndex,
|
|
uiAlgID,
|
|
key->key,
|
|
key->keylen,
|
|
pucKey)) != SDR_OK) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYWITHIPK_ECC,
|
|
ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
|
|
/* set return value */
|
|
*phKeyHandle = key;
|
|
key = NULL;
|
|
ret = SDR_OK;
|
|
|
|
end:
|
|
OPENSSL_clear_free(key, sizeof(*key));
|
|
return ret;
|
|
}
|
|
|
|
int SDF_GenerateKeyWithEPK_ECC(
|
|
void *hSessionHandle,
|
|
unsigned int uiKeyBits,
|
|
unsigned int uiAlgID, /* must be SGD_SM2_3 */
|
|
ECCrefPublicKey *pucPublicKey,
|
|
ECCCipher *pucKey,
|
|
void **phKeyHandle)
|
|
{
|
|
int ret = SDR_UNKNOWERR;
|
|
SDF_KEY *key = NULL;
|
|
|
|
/* check arguments */
|
|
if (!hSessionHandle || !pucPublicKey || !pucKey || !phKeyHandle) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYWITHEPK_ECC,
|
|
ERR_R_PASSED_NULL_PARAMETER);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
if (uiKeyBits <= 0 || uiKeyBits >= EVP_MAX_KEY_LENGTH * 8 ||
|
|
uiKeyBits % 8) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYWITHEPK_ECC,
|
|
SDF_R_INVALID_KEY_LENGTH);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
if (uiAlgID != SGD_SM2_3) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYWITHEPK_ECC,
|
|
SDF_R_INVALID_ALGOR);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
|
|
/* random key */
|
|
if (!(key = OPENSSL_zalloc(sizeof(*key)))) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYWITHEPK_ECC,
|
|
ERR_R_MALLOC_FAILURE);
|
|
goto end;
|
|
}
|
|
key->keylen = uiKeyBits/8;
|
|
if ((ret = SDF_GenerateRandom(hSessionHandle, key->keylen,
|
|
key->key)) != SDR_OK) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYWITHEPK_ECC,
|
|
ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
|
|
/* encrypt key with external ec public key */
|
|
if ((ret = SDF_ExternalEncrypt_ECC(
|
|
hSessionHandle,
|
|
uiAlgID,
|
|
pucPublicKey,
|
|
key->key,
|
|
key->keylen,
|
|
pucKey)) != SDR_OK) {
|
|
SDFerr(SDF_F_SDF_GENERATEKEYWITHEPK_ECC,
|
|
ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
|
|
/* set return value */
|
|
*phKeyHandle = key;
|
|
key = NULL;
|
|
ret = SDR_OK;
|
|
|
|
end:
|
|
OPENSSL_clear_free(key, sizeof(*key));
|
|
return ret;
|
|
}
|
|
|
|
/* import session key
|
|
* use the engine to decrypt the ECCipher
|
|
*/
|
|
int SDF_ImportKeyWithISK_ECC(
|
|
void *hSessionHandle,
|
|
unsigned int uiISKIndex,
|
|
ECCCipher *pucKey,
|
|
void **phKeyHandle)
|
|
{
|
|
int ret = SDR_UNKNOWERR;
|
|
SDF_KEY *key = NULL;
|
|
unsigned int uiAlgID = SGD_SM2_3;
|
|
|
|
/* check arguments */
|
|
if (!hSessionHandle || !pucKey || !phKeyHandle) {
|
|
SDFerr(SDF_F_SDF_IMPORTKEYWITHISK_ECC,
|
|
ERR_R_PASSED_NULL_PARAMETER);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
|
|
/* prepare key */
|
|
if (!(key = OPENSSL_zalloc(sizeof(*key)))) {
|
|
SDFerr(SDF_F_SDF_IMPORTKEYWITHISK_ECC,
|
|
ERR_R_MALLOC_FAILURE);
|
|
goto end;
|
|
}
|
|
key->keylen = EVP_MAX_KEY_LENGTH;
|
|
|
|
/* decrypt with internal ec private key */
|
|
if ((ret = SDF_InternalDecrypt_ECC(
|
|
hSessionHandle,
|
|
uiISKIndex,
|
|
uiAlgID,
|
|
pucKey,
|
|
key->key,
|
|
&key->keylen)) != SDR_OK) {
|
|
SDFerr(SDF_F_SDF_IMPORTKEYWITHISK_ECC,
|
|
ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
|
|
/* set return value */
|
|
*phKeyHandle = key;
|
|
key = NULL;
|
|
ret = SDR_OK;
|
|
|
|
end:
|
|
OPENSSL_clear_free(key, sizeof(*key));
|
|
return ret;
|
|
}
|
|
|
|
int SDF_ExchangeDigitEnvelopeBaseOnECC(
|
|
void *hSessionHandle,
|
|
unsigned int uiKeyIndex,
|
|
unsigned int uiAlgID,
|
|
ECCrefPublicKey *pucPublicKey,
|
|
ECCCipher *pucEncDataIn,
|
|
ECCCipher *pucEncDataOut)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Implementation of SM2 signing
|
|
*
|
|
* Although the digest and signing operations should be the wrapping of the EVP
|
|
* API, it will be simpler when using the native API of the `sm2` module.
|
|
* Another consideration is that the usage of SM2 EVP might be changed, and the
|
|
* operations might also be different from the GM standards, like signing the
|
|
* H(Z||H(M)) instead of signing H(Z||M). So in the GMAPI we use the SM2 API
|
|
* directly.
|
|
*/
|
|
|
|
int SDF_ExternalSign_ECC(
|
|
void *hSessionHandle, /* no use so not checked */
|
|
unsigned int uiAlgID, /* must be SGD_SM2_1 */
|
|
ECCrefPrivateKey *pucPrivateKey,
|
|
unsigned char *pucData, /* digest */
|
|
unsigned int uiDataLength,
|
|
ECCSignature *pucSignature)
|
|
{
|
|
int ret = SDR_UNKNOWERR;
|
|
EC_KEY *ec_key = NULL;
|
|
ECDSA_SIG *sig = NULL;
|
|
|
|
/* check arguments */
|
|
if (!hSessionHandle || !pucData || !pucSignature) {
|
|
SDFerr(SDF_F_SDF_EXTERNALSIGN_ECC,
|
|
ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
if (uiAlgID != SGD_SM2_1) {
|
|
SDFerr(SDF_F_SDF_EXTERNALSIGN_ECC,
|
|
SDF_R_INVALID_ALGOR);
|
|
return 0;
|
|
}
|
|
if (uiDataLength > INT_MAX) {
|
|
SDFerr(SDF_F_SDF_EXTERNALSIGN_ECC,
|
|
SDF_R_INVALID_INPUT_LENGTH);
|
|
return 0;
|
|
}
|
|
|
|
/* load ec private key */
|
|
if (!(ec_key = EC_KEY_new_from_ECCrefPrivateKey(pucPrivateKey))) {
|
|
SDFerr(SDF_F_SDF_EXTERNALSIGN_ECC,
|
|
ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
if (!(sig = SM2_do_sign(pucData, uiDataLength, ec_key))) {
|
|
SDFerr(SDF_F_SDF_EXTERNALSIGN_ECC,
|
|
ERR_R_EC_LIB);
|
|
goto end;
|
|
}
|
|
|
|
/* set return value */
|
|
if (!ECDSA_SIG_get_ECCSignature(sig, pucSignature)) {
|
|
SDFerr(SDF_F_SDF_EXTERNALSIGN_ECC,
|
|
ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
ret = SDR_OK;
|
|
|
|
end:
|
|
EC_KEY_free(ec_key);
|
|
ECDSA_SIG_free(sig);
|
|
return ret;
|
|
}
|
|
|
|
int SDF_ExternalVerify_ECC(
|
|
void *hSessionHandle,
|
|
unsigned int uiAlgID,
|
|
ECCrefPublicKey *pucPublicKey,
|
|
unsigned char *pucDataInput,
|
|
unsigned int uiInputLength,
|
|
ECCSignature *pucSignature)
|
|
{
|
|
int ret = SDR_UNKNOWERR;
|
|
EC_KEY *ec_key = NULL;
|
|
ECDSA_SIG *sig = NULL;
|
|
|
|
/* check arguments */
|
|
if (!hSessionHandle || !pucPublicKey || !pucDataInput ||
|
|
!pucSignature) {
|
|
SDFerr(SDF_F_SDF_EXTERNALVERIFY_ECC,
|
|
ERR_R_PASSED_NULL_PARAMETER);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
if (uiAlgID != SGD_SM2_1) {
|
|
SDFerr(SDF_F_SDF_EXTERNALVERIFY_ECC,
|
|
SDF_R_INVALID_ALGOR);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
if (uiInputLength != SM3_DIGEST_LENGTH) {
|
|
SDFerr(SDF_F_SDF_EXTERNALVERIFY_ECC,
|
|
SDF_R_INVALID_INPUT_LENGTH);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
|
|
/* parse arguments */
|
|
if (!(ec_key = EC_KEY_new_from_ECCrefPublicKey(pucPublicKey))) {
|
|
SDFerr(SDF_F_SDF_EXTERNALVERIFY_ECC,
|
|
SDF_R_INVALID_EC_PUBLIC_KEY);
|
|
goto end;
|
|
}
|
|
if (!(sig = SM2_do_sign(pucDataInput, uiInputLength, ec_key))) {
|
|
SDFerr(SDF_F_SDF_EXTERNALVERIFY_ECC, ERR_R_EC_LIB);
|
|
goto end;
|
|
}
|
|
if (!ECDSA_SIG_get_ECCSignature(sig, pucSignature)) {
|
|
SDFerr(SDF_F_SDF_EXTERNALVERIFY_ECC, ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
|
|
/* set return value */
|
|
ret = SDR_OK;
|
|
|
|
end:
|
|
EC_KEY_free(ec_key);
|
|
ECDSA_SIG_free(sig);
|
|
return ret;
|
|
}
|
|
|
|
int SDF_ExternalEncrypt_ECC(
|
|
void *hSessionHandle,
|
|
unsigned int uiAlgID, /* SGD_SM2_3 */
|
|
ECCrefPublicKey *pucPublicKey,
|
|
unsigned char *pucData,
|
|
unsigned int uiDataLength,
|
|
ECCCipher *pucEncData)
|
|
{
|
|
int ret = SDR_UNKNOWERR;
|
|
EC_KEY *ec_key = NULL;
|
|
SM2_CIPHERTEXT_VALUE *cv = NULL;
|
|
SM2_ENC_PARAMS params;
|
|
|
|
/* check arguments */
|
|
if (!hSessionHandle || !pucPublicKey || !pucData || !pucEncData) {
|
|
SDFerr(SDF_F_SDF_EXTERNALENCRYPT_ECC,
|
|
ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
if (uiAlgID != SGD_SM2_3) {
|
|
SDFerr(SDF_F_SDF_EXTERNALENCRYPT_ECC,
|
|
SDF_R_INVALID_ALGOR);
|
|
return 0;
|
|
}
|
|
/* FIXME
|
|
if (uiDataLength > ECCref_MAX_CIPHER_LEN) {
|
|
SDFerr(SDF_F_SDF_EXTERNALENCRYPT_ECC,
|
|
SDF_R_INVALID_INPUT_LENGTH);
|
|
return 0;
|
|
}
|
|
*/
|
|
|
|
/* parse public key */
|
|
if (!(ec_key = EC_KEY_new_from_ECCrefPublicKey(pucPublicKey))) {
|
|
SDFerr(SDF_F_SDF_EXTERNALENCRYPT_ECC, ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
|
|
/* encrypt */
|
|
(void)SM2_ENC_PARAMS_init_with_recommended(¶ms);
|
|
if (!(cv = SM2_do_encrypt(¶ms, pucData, (size_t)uiDataLength,
|
|
ec_key))) {
|
|
SDFerr(SDF_F_SDF_EXTERNALENCRYPT_ECC, ERR_R_EC_LIB);
|
|
goto end;
|
|
}
|
|
/* encode ciphertext */
|
|
if (!SM2_CIPHERTEXT_VALUE_get_ECCCipher(cv, pucEncData)) {
|
|
SDFerr(SDF_F_SDF_EXTERNALENCRYPT_ECC, ERR_R_EC_LIB);
|
|
goto end;
|
|
}
|
|
|
|
ret = SDR_OK;
|
|
|
|
end:
|
|
EC_KEY_free(ec_key);
|
|
SM2_CIPHERTEXT_VALUE_free(cv);
|
|
return ret;
|
|
}
|
|
|
|
int SDF_ExternalDecrypt_ECC(
|
|
void *hSessionHandle,
|
|
unsigned int uiAlgID,
|
|
ECCrefPrivateKey *pucPrivateKey,
|
|
ECCCipher *pucEncData,
|
|
unsigned char *pucData,
|
|
unsigned int *puiDataLength)
|
|
{
|
|
int ret = SDR_UNKNOWERR;
|
|
EC_KEY *ec_key = NULL;
|
|
SM2_CIPHERTEXT_VALUE *cv = NULL;
|
|
SM2_ENC_PARAMS params;
|
|
size_t siz;
|
|
|
|
/* check arguments */
|
|
if (!hSessionHandle || !pucPrivateKey || !pucEncData ||
|
|
!pucData || !puiDataLength) {
|
|
SDFerr(SDF_F_SDF_EXTERNALDECRYPT_ECC,
|
|
ERR_R_PASSED_NULL_PARAMETER);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
/* FIXME
|
|
if (*puiDataLength < ECCref_MAX_CIPHER_LEN) {
|
|
SDFerr(SDF_F_SDF_EXTERNALDECRYPT_ECC,
|
|
SDF_R_BUFFER_TOO_SMALL);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
*/
|
|
|
|
/* parse arguments */
|
|
if (!(ec_key = EC_KEY_new_from_ECCrefPrivateKey(pucPrivateKey))) {
|
|
SDFerr(SDF_F_SDF_EXTERNALDECRYPT_ECC,
|
|
SDF_R_INVALID_EC_PRIVATE_KEY);
|
|
goto end;
|
|
}
|
|
if (!(cv = SM2_CIPHERTEXT_VALUE_new_from_ECCCipher(pucEncData))) {
|
|
SDFerr(SDF_F_SDF_EXTERNALDECRYPT_ECC,
|
|
SDF_R_INVALID_EC_CIPHERTEXT);
|
|
goto end;
|
|
}
|
|
|
|
/* decrypt */
|
|
(void)SM2_ENC_PARAMS_init_with_recommended(¶ms);
|
|
siz = (size_t)*puiDataLength;
|
|
if (!SM2_do_decrypt(¶ms, cv, pucData, &siz, ec_key)) {
|
|
SDFerr(SDF_F_SDF_EXTERNALDECRYPT_ECC, ERR_R_EC_LIB);
|
|
}
|
|
|
|
/* set return value */
|
|
*puiDataLength = (unsigned int)siz;
|
|
ret = SDR_OK;
|
|
|
|
end:
|
|
EC_KEY_free(ec_key);
|
|
SM2_CIPHERTEXT_VALUE_free(cv);
|
|
return ret;
|
|
}
|
|
|
|
/* internal private key operation will use ENGINE */
|
|
int SDF_InternalSign_ECC(
|
|
void *hSessionHandle,
|
|
unsigned int uiISKIndex,
|
|
unsigned char *pucData,
|
|
unsigned int uiDataLength,
|
|
ECCSignature *pucSignature)
|
|
{
|
|
int ret = 0;
|
|
SDF_SESSION *session = (SDF_SESSION *)hSessionHandle;
|
|
EVP_PKEY_CTX *ctx = NULL;
|
|
EVP_PKEY *pkey = NULL;
|
|
unsigned char buf[256/4 + 32];
|
|
size_t siz;
|
|
|
|
/* check arguments */
|
|
if (!hSessionHandle || !pucData || !pucSignature) {
|
|
SDFerr(SDF_F_SDF_INTERNALSIGN_ECC,
|
|
ERR_R_PASSED_NULL_PARAMETER);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
if (uiDataLength > SM3_DIGEST_LENGTH) {
|
|
SDFerr(SDF_F_SDF_INTERNALSIGN_ECC,
|
|
SDF_R_INVALID_INPUT_LENGTH);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
|
|
/* parse arguments */
|
|
if (!(pkey = sdf_load_ec_private_key(hSessionHandle, uiISKIndex,
|
|
SGD_PK_SIGN))) {
|
|
SDFerr(SDF_F_SDF_INTERNALSIGN_ECC,
|
|
SDF_R_INVALID_KEY_HANDLE);
|
|
goto end;
|
|
}
|
|
|
|
/* sign
|
|
* use the EVP API instead of the native SM2 API to use ENGINE
|
|
*/
|
|
if (!(ctx = EVP_PKEY_CTX_new(pkey, session->engine))) {
|
|
SDFerr(SDF_F_SDF_INTERNALSIGN_ECC, ERR_R_EVP_LIB);
|
|
goto end;
|
|
}
|
|
if (!EVP_PKEY_sign_init(ctx)) {
|
|
SDFerr(SDF_F_SDF_INTERNALSIGN_ECC, ERR_R_EVP_LIB);
|
|
goto end;
|
|
}
|
|
if (!EVP_PKEY_CTX_set_ec_sign_type(ctx, NID_sm_scheme)) {
|
|
SDFerr(SDF_F_SDF_INTERNALSIGN_ECC, ERR_R_EVP_LIB);
|
|
goto end;
|
|
}
|
|
siz = sizeof(buf);
|
|
if (!EVP_PKEY_sign(ctx, buf, &siz, pucData, (size_t)uiDataLength)) {
|
|
SDFerr(SDF_F_SDF_INTERNALSIGN_ECC, ERR_R_EVP_LIB);
|
|
goto end;
|
|
}
|
|
|
|
/* convert signature buf to ECCSignature */
|
|
if (!sdf_decode_ec_signature(pucSignature, buf, siz)) {
|
|
SDFerr(SDF_F_SDF_INTERNALSIGN_ECC, ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
|
|
/* set return value */
|
|
ret = SDR_OK;
|
|
|
|
end:
|
|
EVP_PKEY_CTX_free(ctx);
|
|
EVP_PKEY_free(pkey);
|
|
return ret;
|
|
}
|
|
|
|
int SDF_InternalVerify_ECC(
|
|
void *hSessionHandle,
|
|
unsigned int uiIPKIndex,
|
|
unsigned char *pucData,
|
|
unsigned int uiDataLength,
|
|
ECCSignature *pucSignature)
|
|
{
|
|
int ret = SDR_UNKNOWERR;
|
|
SDF_SESSION *session = (SDF_SESSION *)hSessionHandle;
|
|
EVP_PKEY *pkey = NULL;
|
|
EVP_PKEY_CTX *ctx = NULL;
|
|
unsigned char buf[521/4 + 32];
|
|
size_t siz;
|
|
|
|
/* check arguments */
|
|
if (!hSessionHandle || !pucData || !pucSignature) {
|
|
SDFerr(SDF_F_SDF_INTERNALVERIFY_ECC,
|
|
ERR_R_PASSED_NULL_PARAMETER);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
if (uiDataLength != SM3_DIGEST_LENGTH) {
|
|
SDFerr(SDF_F_SDF_INTERNALVERIFY_ECC,
|
|
SDF_R_INVALID_INPUT_LENGTH);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
|
|
/* parse arguments */
|
|
if (!(pkey = sdf_load_ec_public_key(hSessionHandle, uiIPKIndex,
|
|
SGD_PK_SIGN))) {
|
|
SDFerr(SDF_F_SDF_INTERNALVERIFY_ECC, ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
siz = sizeof(buf);
|
|
if (!sdf_encode_ec_signature(pucSignature, buf, &siz)) {
|
|
SDFerr(SDF_F_SDF_INTERNALVERIFY_ECC, ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
|
|
/* verify with EVP API and ENGINE */
|
|
if (!(ctx = EVP_PKEY_CTX_new(pkey, session->engine))) {
|
|
SDFerr(SDF_F_SDF_INTERNALVERIFY_ECC, ERR_R_EVP_LIB);
|
|
goto end;
|
|
}
|
|
if (!EVP_PKEY_verify_init(ctx)) {
|
|
SDFerr(SDF_F_SDF_INTERNALVERIFY_ECC, ERR_R_EVP_LIB);
|
|
goto end;
|
|
}
|
|
if (!EVP_PKEY_CTX_set_ec_sign_type(ctx, NID_sm_scheme)) {
|
|
SDFerr(SDF_F_SDF_INTERNALVERIFY_ECC, ERR_R_EVP_LIB);
|
|
goto end;
|
|
}
|
|
if (1 != EVP_PKEY_verify(ctx, buf, siz, pucData,
|
|
(size_t)uiDataLength)) {
|
|
SDFerr(SDF_F_SDF_INTERNALVERIFY_ECC, ERR_R_EVP_LIB);
|
|
goto end;
|
|
}
|
|
|
|
ret = SDR_OK;
|
|
|
|
end:
|
|
EVP_PKEY_CTX_free(ctx);
|
|
EVP_PKEY_free(pkey);
|
|
return ret;
|
|
}
|
|
|
|
int SDF_InternalEncrypt_ECC(
|
|
void *hSessionHandle,
|
|
unsigned int uiIPKIndex,
|
|
unsigned int uiAlgID,
|
|
unsigned char *pucData,
|
|
unsigned int uiDataLength,
|
|
ECCCipher *pucEncData)
|
|
{
|
|
int ret = 0;
|
|
EVP_PKEY *pkey = NULL;
|
|
SM2_CIPHERTEXT_VALUE *cv = NULL;
|
|
SM2_ENC_PARAMS params;
|
|
|
|
/* check arguments */
|
|
if (!hSessionHandle || !pucData || !pucEncData) {
|
|
SDFerr(SDF_F_SDF_INTERNALENCRYPT_ECC,
|
|
ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
if (uiDataLength > ECCref_MAX_LEN) {
|
|
SDFerr(SDF_F_SDF_INTERNALENCRYPT_ECC,
|
|
SDF_R_INVALID_INPUT_LENGTH);
|
|
return 0;
|
|
}
|
|
|
|
if (!(pkey = sdf_load_ec_public_key((SDF_SESSION *)hSessionHandle,
|
|
uiIPKIndex, uiAlgID))) {
|
|
SDFerr(SDF_F_SDF_INTERNALENCRYPT_ECC, ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
|
|
(void)SM2_ENC_PARAMS_init_with_recommended(¶ms);
|
|
|
|
/* we need to use the EVP_PKEY interface to use ENGINE ?*/
|
|
if (!(cv = SM2_do_encrypt(¶ms, pucData, (size_t)uiDataLength,
|
|
EVP_PKEY_get0_EC_KEY(pkey)))) {
|
|
SDFerr(SDF_F_SDF_INTERNALENCRYPT_ECC, ERR_R_EC_LIB);
|
|
goto end;
|
|
}
|
|
|
|
if (!SM2_CIPHERTEXT_VALUE_get_ECCCipher(cv, pucEncData)) {
|
|
SDFerr(SDF_F_SDF_INTERNALENCRYPT_ECC, ERR_R_EC_LIB);
|
|
goto end;
|
|
}
|
|
|
|
ret = SDR_OK;
|
|
|
|
end:
|
|
EVP_PKEY_free(pkey);
|
|
SM2_CIPHERTEXT_VALUE_free(cv);
|
|
return ret;
|
|
}
|
|
|
|
int SDF_InternalDecrypt_ECC(
|
|
void *hSessionHandle,
|
|
unsigned int uiISKIndex,
|
|
unsigned int uiAlgID,
|
|
ECCCipher *pucEncData,
|
|
unsigned char *pucData,
|
|
unsigned int *puiDataLength)
|
|
{
|
|
int ret = 0;
|
|
EVP_PKEY *pkey = NULL;
|
|
|
|
|
|
/* check arguments */
|
|
if (!hSessionHandle || !pucEncData || !pucData || !puiDataLength) {
|
|
SDFerr(SDF_F_SDF_INTERNALDECRYPT_ECC,
|
|
ERR_R_PASSED_NULL_PARAMETER);
|
|
return SDR_UNKNOWERR;
|
|
}
|
|
|
|
if (!(pkey = sdf_load_ec_private_key(hSessionHandle,
|
|
uiISKIndex, uiAlgID))) {
|
|
SDFerr(SDF_F_SDF_INTERNALDECRYPT_ECC, ERR_R_GMAPI_LIB);
|
|
goto end;
|
|
}
|
|
|
|
|
|
end:
|
|
return 0;
|
|
}
|
|
|