This commit is contained in:
Zhi Guan
2015-10-11 11:56:45 +08:00
parent b4ad0da508
commit 3f21c9d3d0
33 changed files with 739 additions and 402 deletions

View File

@@ -6,10 +6,36 @@
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/rand.h>
#include <oepnssl/kdf.h>
#include "sm2_enc.h"
#include <openssl/kdf.h>
#include "sm2.h"
void SM2_CIPEHRTEXT_VALUE_free(SM2_CIPHERTEXT_VALUE *cv)
int SM2_CIPHERTEXT_VALUE_size(const EC_GROUP *ec_group,
point_conversion_form_t point_form, size_t mlen,
const EVP_MD *mac_md)
{
int ret = 0;
EC_POINT *point = EC_POINT_new(ec_group);
BN_CTX *bn_ctx = BN_CTX_new();
size_t len;
if (!point || !bn_ctx) {
goto end;
}
if (!(len = EC_POINT_point2oct(ec_group, point, point_form,
NULL, 0, bn_ctx))) {
goto end;
}
len += mlen + EVP_MD_size(mac_md);
ret = len;
end:
if (point) EC_POINT_free(point);
if (bn_ctx) BN_CTX_free(bn_ctx);
return ret;
}
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);
@@ -17,9 +43,141 @@ void SM2_CIPEHRTEXT_VALUE_free(SM2_CIPHERTEXT_VALUE *cv)
OPENSSL_free(cv);
}
SM2_CIPHERTEXT_VALUE *SM2_do_encrypt(
const EVP_MD *kdf_md, const EVP_MD *mac_md,
const void *in, size_t inlen, const EC_KEY *ec_key);
int SM2_CIPHERTEXT_VALUE_encode(const SM2_CIPHERTEXT_VALUE *cv,
const EC_GROUP *ec_group, point_conversion_form_t point_form,
unsigned char *buf, size_t *buflen)
{
int ret = 0;
BN_CTX *bn_ctx = BN_CTX_new();
size_t ptlen, cvlen;
if (!bn_ctx) {
return 0;
}
if (!(ptlen = EC_POINT_point2oct(ec_group, cv->ephem_point,
point_form, NULL, 0, bn_ctx))) {
goto end;
}
cvlen = ptlen + cv->ciphertext_size + cv->mactag_size;
if (!buf) {
*buflen = cvlen;
ret = 1;
goto end;
} else if (*buflen < cvlen) {
goto end;
}
if (!(ptlen = EC_POINT_point2oct(ec_group, cv->ephem_point,
point_form, buf, *buflen, bn_ctx))) {
goto end;
}
buf += ptlen;
memcpy(buf, cv->ciphertext, cv->ciphertext_size);
buf += cv->ciphertext_size;
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,
point_conversion_form_t point_form, const EVP_MD *mac_md,
const unsigned char *buf, size_t buflen)
{
int ok = 0;
SM2_CIPHERTEXT_VALUE *ret = NULL;
BN_CTX *bn_ctx = NULL;
int len = SM2_CIPHERTEXT_VALUE_size(ec_group, point_form, 0, mac_md);
int ptlen = len - EVP_MD_size(mac_md);
if (!(len = SM2_CIPHERTEXT_VALUE_size(ec_group, point_form, 0, mac_md))) {
goto end;
}
if (buflen <= len) {
goto end;
}
if (!(ret = OPENSSL_malloc(sizeof(SM2_CIPHERTEXT_VALUE)))) {
goto end;
}
ret->ephem_point = EC_POINT_new(ec_group);
ret->ciphertext_size = buflen - len;
ret->ciphertext = OPENSSL_malloc(ret->ciphertext_size);
if (!ret->ephem_point || !ret->ciphertext) {
goto end;
}
if (!(bn_ctx = BN_CTX_new())) {
goto end;
}
if (!EC_POINT_oct2point(ec_group, ret->ephem_point, buf, len, bn_ctx)) {
goto end;
}
memcpy(ret->ciphertext, buf + ptlen, ret->ciphertext_size);
ret->mactag_size = EVP_MD_size(mac_md);
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 SM2_CIPHERTEXT_VALUE *cv,
int indent, unsigned long flags)
{
OPENSSL_assert(0);
return 0;
}
int SM2_encrypt(const EVP_MD *kdf_md, const EVP_MD *mac_md,
point_conversion_form_t point_form, unsigned char *out, size_t *outlen,
const unsigned char *in, size_t inlen, 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, point_form, inlen, mac_md))) {
goto end;
}
if (!out) {
*outlen = (size_t)len;
return 1;
} else if (*outlen < (size_t)len) {
return 0;
}
if (!(cv = SM2_do_encrypt(kdf_md, mac_md, in, inlen, ec_key))) {
goto end;
}
if (!SM2_CIPHERTEXT_VALUE_encode(cv, ec_group, point_form, out, outlen)) {
goto end;
}
ret = 1;
end:
if (cv) SM2_CIPHERTEXT_VALUE_free(cv);
return ret;
}
SM2_CIPHERTEXT_VALUE *SM2_do_encrypt(const EVP_MD *kdf_md, const EVP_MD *mac_md,
const unsigned char *in, size_t inlen, EC_KEY *ec_key)
{
int ok = 0;
SM2_CIPHERTEXT_VALUE *cv = NULL;
@@ -34,25 +192,26 @@ SM2_CIPHERTEXT_VALUE *SM2_do_encrypt(
EVP_MD_CTX *md_ctx = NULL;
unsigned char buf[(OPENSSL_ECC_MAX_FIELD_BITS + 7)/4 + 1];
int nbytes;
size_t len;
int i;
if (!ec_group || !pub_key) {
goto err;
goto end;
}
if (!kdf) {
goto err;
goto end;
}
/* init ciphertext_value */
if (!(cv = OPENSSL_malloc(sizeof(SM2_CIPHERTEXT_VALUE)))) {
goto err;
goto end;
}
bzero(cv, sizeof(SM2_CIPHERTEXT_VALUE));
cv->ephem_point = EC_POINT_new(ec_group);
cv->ciphertext = OPENSSL_malloc(inlen);
cv->ciphertext_size = inlen;
if (!cv->ephem_point || !cv->ciphertext) {
goto err;
goto end;
}
point = EC_POINT_new(ec_group);
@@ -62,17 +221,17 @@ SM2_CIPHERTEXT_VALUE *SM2_do_encrypt(
bn_ctx = BN_CTX_new();
md_ctx = EVP_MD_CTX_create();
if (!point || !n || !h || !k || !bn_ctx || !md_ctx) {
goto err;
goto end;
}
/* init ec domain parameters */
if (!EC_GROUP_get_order(ec_group, n, bn_ctx)) {
goto err;
goto end;
}
if (!EC_GROUP_get_cofactor(ec_group, h, bn_ctx)) {
goto err;
goto end;
}
nbytes = (EC_GROPU_get_degree(ec_group) + 7) / 8;
nbytes = (EC_GROUP_get_degree(ec_group) + 7) / 8;
OPENSSL_assert(nbytes == BN_num_bytes(n));
/* check sm2 curve and md is 256 bits */
@@ -89,24 +248,24 @@ SM2_CIPHERTEXT_VALUE *SM2_do_encrypt(
/* A2: C1 = [k]G = (x1, y1) */
if (!EC_POINT_mul(ec_group, cv->ephem_point, k, NULL, NULL, bn_ctx)) {
goto err;
goto end;
}
/* A3: check [h]P_B != O */
if (!EC_POINT_mul(ec_group, point, NULL, pub_key, h, bn_ctx)) {
goto err;
goto end;
}
if (EC_POINT_is_at_infinity(ec_group, point)) {
goto err;
goto end;
}
/* A4: compute ECDH [k]P_B = (x2, y2) */
if (!EC_POINT_mul(ec_group, point, NULL, pub_key, k, bn_ctx)) {
goto err;
goto end;
}
if (!(len = EC_POINT_point2oct(ec_group, point,
POINT_CONVERSION_UNCOMPRESSED, buf, sizeof(buf), bn_ctx))) {
goto err;
goto end;
}
OPENSSL_assert(len == nbytes * 2 + 1);
@@ -134,24 +293,24 @@ SM2_CIPHERTEXT_VALUE *SM2_do_encrypt(
/* A7: C3 = Hash(x2 || M || y2) */
if (!EVP_DigestInit_ex(md_ctx, mac_md, NULL)) {
goto err;
goto end;
}
if (!EVP_DigestUpdate(md_ctx, buf + 1, nbytes)) {
goto err;
goto end;
}
if (!EVP_DigestUpdate(md_ctx, in, inlen)) {
goto err;
goto end;
}
if (!EVP_DigestUpdate(md_ctx, buf + 1 + nbytes, nbytes)) {
goto err;
goto end;
}
if (!EVP_DigestFinal_ex(md_ctx, cv->mactag, &cv->mactag_size)) {
goto err;
goto end;
}
ok = 1;
err:
end:
if (!ok && cv) {
SM2_CIPHERTEXT_VALUE_free(cv);
cv = NULL;
@@ -166,12 +325,47 @@ err:
return cv;
}
int SM2_do_decrypt(const SM2_CIPHERTEXT_VALUE *cv,
const EVP_MD *kdf_md, const EVP_MD *mac_md,
unsigned char *out, size_t *outlen, EC_KEY *ec_key)
int SM2_decrypt(const EVP_MD *kdf_md, const EVP_MD *mac_md,
point_conversion_form_t point_form, const unsigned char *in,
size_t inlen, unsigned char *out, size_t *outlen, EC_KEY *ec_key)
{
int ret = 0
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, point_form, 0, mac_md))) {
goto end;
}
if (inlen <= len) {
goto end;
}
if (!out) {
*outlen = inlen - len;
return 1;
} else if (outlen < inlen - len) {
return 0;
}
if (!(cv = SM2_CIPHERTEXT_VALUE_decode(ec_group, point_form, mac_md, in, inlen))) {
goto end;
}
if (!SM2_do_decrypt(kdf_md, mac_md, cv, out, outlen, ec_key)) {
goto end;
}
ret = 1;
end:
if (cv) SM2_CIPHERTEXT_VALUE_free(cv);
return ret;
}
int SM2_do_decrypt(const EVP_MD *kdf_md, const EVP_MD *mac_md,
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(kdf_md);
@@ -182,14 +376,16 @@ int SM2_do_decrypt(const SM2_CIPHERTEXT_VALUE *cv,
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 nbytes;
size_t size;
int i;
if (!ec_group || !pub_key) {
goto err;
if (!ec_group || !pri_key) {
goto end;
}
if (!kdf) {
goto err;
goto end;
}
if (!out) {
@@ -197,7 +393,7 @@ int SM2_do_decrypt(const SM2_CIPHERTEXT_VALUE *cv,
return 1;
}
if (*outlen < cv->ciphertext_size) {
goto err;
goto end;
}
/* init vars */
@@ -207,17 +403,17 @@ int SM2_do_decrypt(const SM2_CIPHERTEXT_VALUE *cv,
bn_ctx = BN_CTX_new();
md_ctx = EVP_MD_CTX_create();
if (!point || !n || !h || !bn_ctx || !md_ctx) {
goto err;
goto end;
}
/* init ec domain parameters */
if (!EC_GROUP_get_order(ec_group, n, bn_ctx)) {
goto err;
goto end;
}
if (!EC_GROUP_get_cofactor(ec_group, h, bn_ctx)) {
goto err;
goto end;
}
nbytes = (EC_GROPU_get_degree(ec_group) + 7) / 8;
nbytes = (EC_GROUP_get_degree(ec_group) + 7) / 8;
OPENSSL_assert(nbytes == BN_num_bytes(n));
/* check sm2 curve and md is 256 bits */
@@ -227,23 +423,23 @@ int SM2_do_decrypt(const SM2_CIPHERTEXT_VALUE *cv,
/* B2: check [h]C1 != O */
if (!EC_POINT_mul(ec_group, point, NULL, cv->ephem_point, h, bn_ctx)) {
goto err;
goto end;
}
if (EC_POINT_is_at_infinity(ec_group, point)) {
goto err;
goto end;
}
/* B3: compute ECDH [d]C1 = (x2, y2) */
if (!EC_POINT_mul(ec_group, point, NULL, cv->ephem_point, pri_key, bn_ctx)) {
goto err;
goto end;
}
if (!(len = EC_POINT_point2oct(ec_group, point,
if (!(size = EC_POINT_point2oct(ec_group, point,
POINT_CONVERSION_UNCOMPRESSED, buf, sizeof(buf), bn_ctx))) {
goto err;
goto end;
}
/* B4: compute t = KDF(x2 || y2, clen) */
kdf(buf - 1, len - 1, out, outlen);
kdf(buf - 1, size - 1, out, outlen);
/* B5: compute M = C2 xor t */
@@ -253,26 +449,27 @@ int SM2_do_decrypt(const SM2_CIPHERTEXT_VALUE *cv,
/* B6: check Hash(x2 || M || y2) == C3 */
if (!EVP_DigestInit_ex(md_ctx, mac_md, NULL)) {
goto err;
goto end;
}
if (!EVP_DigestUpdate(md_ctx, buf + 1, nbytes)) {
goto err;
goto end;
}
if (!EVP_DigestUpdate(md_ctx, out, *outlen)) {
goto err;
goto end;
}
if (!EVP_DigestUpdate(md_ctx, buf + 1 + nbytes, nbytes)) {
goto err;
goto end;
}
if (!EVP_DigestFinal_ex(md_ctx, mac, &maclen)) {
goto err;
goto end;
}
if (cv->mactag_size != maclen || memcmp(cv->mactag, mac, maclen)) {
goto err;
if (cv->mactag_size != maclen ||
memcmp(cv->mactag, mac, maclen)) {
goto end;
}
ret = 1;
err:
end:
if (point) EC_POINT_free(point);
if (n) BN_free(n);
if (h) BN_free(h);