mirror of
https://github.com/guanzhi/GmSSL.git
synced 2026-05-11 10:56:17 +08:00
Update SM9 key agreement
This commit is contained in:
@@ -464,11 +464,6 @@ int SM9_decrypt(int type,
|
||||
C2 = ASN1_STRING_get0_data(sm9cipher->c2);
|
||||
C2_len = ASN1_STRING_length(sm9cipher->c2);
|
||||
|
||||
/* check mac length */
|
||||
if (ASN1_STRING_length(sm9cipher->c3) != EVP_MD_size(md)) {
|
||||
SM9err(SM9_F_SM9_DECRYPT, ERR_R_SM9_LIB);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* unwrap key */
|
||||
keylen = C2_len + EVP_MD_size(md);
|
||||
@@ -489,6 +484,12 @@ int SM9_decrypt(int type,
|
||||
}
|
||||
*outlen = C2_len;
|
||||
|
||||
/* check mac length */
|
||||
if (ASN1_STRING_length(sm9cipher->c3) != EVP_MD_size(md)) {
|
||||
SM9err(SM9_F_SM9_DECRYPT, ERR_R_SM9_LIB);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* C3 = Hv(C2||K2) */
|
||||
memcpy(key, C2, C2_len);
|
||||
if (!EVP_Digest(key, keylen, mac, &maclen, md, NULL)) {
|
||||
|
||||
@@ -28,6 +28,8 @@ static ERR_STRING_DATA SM9_str_functs[] = {
|
||||
"SM9EncParameters_get_key_length"},
|
||||
{ERR_FUNC(SM9_F_SM9PUBLICPARAMETERS_GET_POINT_SIZE),
|
||||
"SM9PublicParameters_get_point_size"},
|
||||
{ERR_FUNC(SM9_F_SM9_COMPUTE_SHARE_KEY_A), "SM9_compute_share_key_A"},
|
||||
{ERR_FUNC(SM9_F_SM9_COMPUTE_SHARE_KEY_B), "SM9_compute_share_key_B"},
|
||||
{ERR_FUNC(SM9_F_SM9_DECRYPT), "SM9_decrypt"},
|
||||
{ERR_FUNC(SM9_F_SM9_DO_DECRYPT), "SM9_do_decrypt"},
|
||||
{ERR_FUNC(SM9_F_SM9_DO_ENCRYPT), "SM9_do_encrypt"},
|
||||
@@ -65,6 +67,8 @@ static ERR_STRING_DATA SM9_str_reasons[] = {
|
||||
{ERR_REASON(SM9_R_INVALID_ID_LENGTH), "invalid id length"},
|
||||
{ERR_REASON(SM9_R_INVALID_INPUT), "invalid input"},
|
||||
{ERR_REASON(SM9_R_INVALID_KEM_KEY_LENGTH), "invalid kem key length"},
|
||||
{ERR_REASON(SM9_R_INVALID_KEY_AGREEMENT_CHECKSUM),
|
||||
"invalid key agreement checksum"},
|
||||
{ERR_REASON(SM9_R_INVALID_KEY_LENGTH), "invalid key length"},
|
||||
{ERR_REASON(SM9_R_INVALID_MD), "invalid md"},
|
||||
{ERR_REASON(SM9_R_INVALID_PAIRING_TYPE), "invalid pairing type"},
|
||||
|
||||
@@ -47,6 +47,9 @@
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/sm9.h>
|
||||
#include "sm9_lcl.h"
|
||||
@@ -129,6 +132,8 @@ int SM9_generate_key_exchange(unsigned char *R, size_t *Rlen,
|
||||
/* R = r * Q */
|
||||
|| !EC_POINT_mul(group, Q, NULL, Q, r, bn_ctx)
|
||||
|| (len = EC_POINT_point2oct(group, Q, point_form, R, *Rlen, bn_ctx)) <= 0) {
|
||||
SM9err(SM9_F_SM9_GENERATE_KEY_EXCHANGE, ERR_R_SM9_LIB);
|
||||
goto end;
|
||||
}
|
||||
*Rlen = len;
|
||||
|
||||
@@ -159,27 +164,313 @@ end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* check peer's R in E(F_p)
|
||||
* e = g2' = g1 = e(peer_R, sk)
|
||||
* g3' = g3 = g2'^r = g1^r = er
|
||||
* S' = H(0x82 || g1' || H(g2' || g3' || ID_A || ID_B || R_A || R_B))
|
||||
* SA = H(0x83 || g1' || H(g2' || g3' || ID_A || ID_B || R_A || R_B))
|
||||
* KA = KDF(ID_A || ID_B || R_A || R_B || g1' || g2' || g3')
|
||||
*
|
||||
* KB = KDF(ID_A || ID_B || R_A || R_B || g1 || g2 || g3)
|
||||
* SB = H(0x82 || g1 || Hash(g2 || g3 || ID_A || ID_B || R_A || R_B))
|
||||
* SA'= H(0x83 || g1 || Hash(g2 || g3 || ID_A || ID_B || R_A || R_B))
|
||||
*
|
||||
*/
|
||||
int SM9_compute_share_key(unsigned char *key, size_t keylen,
|
||||
unsigned char *peer_mac, size_t *peer_maclen, /* compure with received peer's mac */
|
||||
unsigned char *mac, size_t *maclen, int compute_mac, /* send to peer */
|
||||
const unsigned char *peer_R, size_t peer_Rlen, /* recv from peer */
|
||||
const unsigned char *R, size_t Rlen, /* cached from SM9_generate_key_exchange */
|
||||
const BIGNUM *r, /* cached from SM9_generate_key_exchange */
|
||||
const char *peer_id, size_t peer_idlen,
|
||||
SM9PrivateKey *sk, int initiator)
|
||||
int SM9_compute_share_key_A(int type,
|
||||
unsigned char *SKA, size_t SKAlen,
|
||||
unsigned char SA[32], /* optional, send to B */
|
||||
const unsigned char SB[32], /* optional, recv from B */
|
||||
const BIGNUM *rA,
|
||||
const unsigned char RA[65],
|
||||
const unsigned char RB[65],
|
||||
const unsigned char g1[384],
|
||||
const char *IDB, size_t IDBlen,
|
||||
SM9PrivateKey *skA)
|
||||
{
|
||||
return 0;
|
||||
int ret = 0;
|
||||
const EVP_MD *md = EVP_sm3();
|
||||
const char *IDA;
|
||||
int IDAlen;
|
||||
EC_GROUP *group = NULL;
|
||||
EC_POINT *P = NULL;
|
||||
EVP_MD_CTX *md_ctx = NULL;
|
||||
BN_CTX *bn_ctx = NULL;
|
||||
fp12_t g;
|
||||
point_t deA;
|
||||
const BIGNUM *p = SM9_get0_prime();
|
||||
unsigned char x82[1] = {0x82};
|
||||
unsigned char x83[1] = {0x83};
|
||||
unsigned char buf[384 * 2];
|
||||
unsigned char counter[4] = {0, 0, 0, 1};
|
||||
unsigned char dgst[EVP_MAX_MD_SIZE];
|
||||
unsigned int dgstlen;
|
||||
|
||||
/* get IDA */
|
||||
IDA = ASN1_STRING_get0_data(skA->identity);
|
||||
IDAlen = ASN1_STRING_length(skA->identity);
|
||||
|
||||
/* malloc */
|
||||
if (!(group = EC_GROUP_new_by_curve_name(NID_sm9bn256v1))
|
||||
|| !(P = EC_POINT_new(group))
|
||||
|| !(md_ctx = EVP_MD_CTX_new())
|
||||
|| !(bn_ctx = BN_CTX_new())) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_MALLOC_FAILURE);
|
||||
goto end;
|
||||
}
|
||||
BN_CTX_start(bn_ctx);
|
||||
if (!point_init(&deA, bn_ctx)
|
||||
|| !fp12_init(g, bn_ctx)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_MALLOC_FAILURE);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* parse deA */
|
||||
if (ASN1_STRING_length(skA->privatePoint) != 129
|
||||
|| !point_from_octets(&deA, ASN1_STRING_get0_data(skA->privatePoint), p, bn_ctx)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_SM9_LIB);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* parse RB */
|
||||
if (!EC_POINT_oct2point(group, P, RB, 65, bn_ctx)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_SM9_LIB);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* g2' = e(RB, deA) */
|
||||
if (!rate_pairing(g, &deA, P, bn_ctx) || !fp12_to_bin(g, buf)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_SM9_LIB);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* g3' = (g2')^r_A */
|
||||
if (!fp12_pow(g, g, rA, p, bn_ctx) || fp12_to_bin(g, buf + 384)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_SM9_LIB);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* compute optional S1 */
|
||||
if (SA) {
|
||||
unsigned char S1[32];
|
||||
|
||||
/* dgst = H(g2 || g3 || ID_A || ID_B || R_A || R_B) */
|
||||
if (!EVP_DigestInit_ex(md_ctx, md, NULL)
|
||||
|| !EVP_DigestUpdate(md_ctx, buf, sizeof(buf))
|
||||
|| !EVP_DigestUpdate(md_ctx, IDA, IDAlen)
|
||||
|| !EVP_DigestUpdate(md_ctx, IDB, IDBlen)
|
||||
|| !EVP_DigestUpdate(md_ctx, RA + 1, 64)
|
||||
|| !EVP_DigestUpdate(md_ctx, RB + 1, 64)
|
||||
|| !EVP_DigestFinal_ex(md_ctx, dgst, &dgstlen)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_EVP_LIB);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* S1 = H(0x82 || g1' || dgst) */
|
||||
if (!EVP_DigestInit_ex(md_ctx, md, NULL)
|
||||
|| !EVP_DigestUpdate(md_ctx, x82, 1)
|
||||
|| !EVP_DigestUpdate(md_ctx, g1, 384)
|
||||
|| !EVP_DigestUpdate(md_ctx, dgst, dgstlen)
|
||||
|| !EVP_DigestFinal_ex(md_ctx, S1, &dgstlen)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_EVP_LIB);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* given SB, check if S1 == SB */
|
||||
if (SB) {
|
||||
if (memcmp(S1, SB, dgstlen) != 0) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, SM9_R_INVALID_KEY_AGREEMENT_CHECKSUM);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* SKA = KDF(ID_A || ID_B || R_A || R_B || g1 || g2 || g3, Klen) */
|
||||
while (SKAlen > 0) {
|
||||
unsigned char key[64];
|
||||
unsigned int len;
|
||||
|
||||
if (!EVP_DigestInit_ex(md_ctx, md, NULL)
|
||||
|| !EVP_DigestUpdate(md_ctx, IDA, IDAlen)
|
||||
|| !EVP_DigestUpdate(md_ctx, IDB, IDBlen)
|
||||
|| !EVP_DigestUpdate(md_ctx, RA + 1, 64)
|
||||
|| !EVP_DigestUpdate(md_ctx, RB + 1, 64)
|
||||
|| !EVP_DigestUpdate(md_ctx, g1, 384)
|
||||
|| !EVP_DigestUpdate(md_ctx, buf, sizeof(buf))
|
||||
|| !EVP_DigestFinal_ex(md_ctx, key, &len)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_EVP_LIB);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (len > SKAlen)
|
||||
len = SKAlen;
|
||||
memcpy(SKA, key, len);
|
||||
|
||||
SKA += len;
|
||||
SKAlen -= len;
|
||||
counter[3]++;
|
||||
}
|
||||
|
||||
if (SA) {
|
||||
/* SA = H(0x83 || g1 || dgst) */
|
||||
if (!EVP_DigestInit_ex(md_ctx, md, NULL)
|
||||
|| !EVP_DigestUpdate(md_ctx, x83, 1)
|
||||
|| !EVP_DigestUpdate(md_ctx, g1, 384)
|
||||
|| !EVP_DigestUpdate(md_ctx, dgst, dgstlen)
|
||||
|| !EVP_DigestFinal_ex(md_ctx, SA, &dgstlen)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_EVP_LIB);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
end:
|
||||
EC_GROUP_free(group);
|
||||
EC_POINT_free(P);
|
||||
EVP_MD_CTX_free(md_ctx);
|
||||
fp12_cleanup(g);
|
||||
point_cleanup(&deA);
|
||||
if (bn_ctx) {
|
||||
BN_CTX_end(bn_ctx);
|
||||
}
|
||||
BN_CTX_free(bn_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SM9_compute_share_key_B(int type,
|
||||
unsigned char *SKB, size_t SKBlen,
|
||||
unsigned char SB[32], /* optional, send to A */
|
||||
unsigned char S2[32], /* optional, to be compared with recved SA */
|
||||
const BIGNUM *rB,
|
||||
const unsigned char RB[65],
|
||||
const unsigned char RA[65],
|
||||
const unsigned char g2[384],
|
||||
const char *IDA, size_t IDAlen,
|
||||
SM9PrivateKey *skB)
|
||||
{
|
||||
int ret = 0;
|
||||
const EVP_MD *md = EVP_sm3();
|
||||
const char *IDB;
|
||||
int IDBlen;
|
||||
EC_GROUP *group = NULL;
|
||||
EC_POINT *P = NULL;
|
||||
EVP_MD_CTX *md_ctx = NULL;
|
||||
BN_CTX *bn_ctx = NULL;
|
||||
fp12_t g;
|
||||
point_t deB;
|
||||
const BIGNUM *p = SM9_get0_prime();
|
||||
unsigned char x82[1] = {0x82};
|
||||
unsigned char x83[1] = {0x83};
|
||||
unsigned char g1[384];
|
||||
unsigned char g3[384];
|
||||
unsigned char counter[4] = {0, 0, 0, 1};
|
||||
unsigned char key[EVP_MAX_MD_SIZE];
|
||||
unsigned int len;
|
||||
|
||||
/* get IDB */
|
||||
IDB = ASN1_STRING_get0_data(skB->identity);
|
||||
IDBlen = ASN1_STRING_length(skB->identity);
|
||||
|
||||
/* malloc */
|
||||
if (!(group = EC_GROUP_new_by_curve_name(NID_sm9bn256v1))
|
||||
|| !(P = EC_POINT_new(group))
|
||||
|| !(md_ctx = EVP_MD_CTX_new())
|
||||
|| !(bn_ctx = BN_CTX_new())) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_MALLOC_FAILURE);
|
||||
goto end;
|
||||
}
|
||||
BN_CTX_start(bn_ctx);
|
||||
if (!point_init(&deB, bn_ctx)
|
||||
|| !fp12_init(g, bn_ctx)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_MALLOC_FAILURE);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* parse deB */
|
||||
if (ASN1_STRING_length(skB->privatePoint) != 129
|
||||
|| !point_from_octets(&deB, ASN1_STRING_get0_data(skB->privatePoint), p, bn_ctx)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_SM9_LIB);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* parse RA */
|
||||
if (!EC_POINT_oct2point(group, P, RA, 65, bn_ctx)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_SM9_LIB);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* g1 = e(RA, deB) */
|
||||
if (!rate_pairing(g, &deB, P, bn_ctx) || !fp12_to_bin(g, g1)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_SM9_LIB);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* g3 = (g1)^r_B */
|
||||
if (!fp12_pow(g, g, rB, p, bn_ctx) || fp12_to_bin(g, g3)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_SM9_LIB);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* SKB = KDF(ID_A || ID_B || R_A || R_B || g1 || g2 || g3, Klen) */
|
||||
while (SKBlen > 0) {
|
||||
if (!EVP_DigestInit_ex(md_ctx, md, NULL)
|
||||
|| !EVP_DigestUpdate(md_ctx, IDA, IDAlen)
|
||||
|| !EVP_DigestUpdate(md_ctx, IDB, IDBlen)
|
||||
|| !EVP_DigestUpdate(md_ctx, RA + 1, 64)
|
||||
|| !EVP_DigestUpdate(md_ctx, RB + 1, 64)
|
||||
|| !EVP_DigestUpdate(md_ctx, g1, 384)
|
||||
|| !EVP_DigestUpdate(md_ctx, g2, 384)
|
||||
|| !EVP_DigestUpdate(md_ctx, g3, 384)
|
||||
|| !EVP_DigestFinal_ex(md_ctx, key, &len)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_EVP_LIB);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (len > SKBlen)
|
||||
len = SKBlen;
|
||||
memcpy(SKB, key, len);
|
||||
|
||||
SKB += len;
|
||||
SKBlen -= len;
|
||||
counter[3]++;
|
||||
}
|
||||
|
||||
/* compute optional S1 */
|
||||
if (S2 && SB) {
|
||||
/* dgst = H(g2 || g3 || ID_A || ID_B || R_A || R_B) */
|
||||
if (!EVP_DigestInit_ex(md_ctx, md, NULL)
|
||||
|| !EVP_DigestUpdate(md_ctx, g2, 384)
|
||||
|| !EVP_DigestUpdate(md_ctx, g3, 384)
|
||||
|| !EVP_DigestUpdate(md_ctx, IDA, IDAlen)
|
||||
|| !EVP_DigestUpdate(md_ctx, IDB, IDBlen)
|
||||
|| !EVP_DigestUpdate(md_ctx, RA + 1, 64)
|
||||
|| !EVP_DigestUpdate(md_ctx, RB + 1, 64)
|
||||
|| !EVP_DigestFinal_ex(md_ctx, key, &len)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_EVP_LIB);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* SB = H(0x82 || g1 || dgst) */
|
||||
if (!EVP_DigestInit_ex(md_ctx, md, NULL)
|
||||
|| !EVP_DigestUpdate(md_ctx, x82, 1)
|
||||
|| !EVP_DigestUpdate(md_ctx, g1, 384)
|
||||
|| !EVP_DigestUpdate(md_ctx, key, len)
|
||||
|| !EVP_DigestFinal_ex(md_ctx, SB, &len)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_EVP_LIB);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* S2 = H(0x83 || g1 || dgst) */
|
||||
if (!EVP_DigestInit_ex(md_ctx, md, NULL)
|
||||
|| !EVP_DigestUpdate(md_ctx, x83, 1)
|
||||
|| !EVP_DigestUpdate(md_ctx, g1, 384)
|
||||
|| !EVP_DigestUpdate(md_ctx, key, len)
|
||||
|| !EVP_DigestFinal_ex(md_ctx, S2, &len)) {
|
||||
SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_EVP_LIB);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
end:
|
||||
EC_GROUP_free(group);
|
||||
EC_POINT_free(P);
|
||||
EVP_MD_CTX_free(md_ctx);
|
||||
fp12_cleanup(g);
|
||||
point_cleanup(&deB);
|
||||
if (bn_ctx) {
|
||||
BN_CTX_end(bn_ctx);
|
||||
}
|
||||
BN_CTX_free(bn_ctx);
|
||||
OPENSSL_cleanse(key, sizeof(key));
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user