國密非對稱加密算法
又稱sm2,它是采取了ECC(曲線加密算法)中的一條固定的曲線,實際上就是ECC算法。 因為openssl里面不包含sm2算法,所以就要重新進行封裝…. …
對於ECC算法我就不介紹了,網上關於它的介紹一抓一大把,丟給你們一個鏈接ECC算法介紹。
現在對ECC加密算法做個大致的介紹:
所有非對稱加密算法都有公鑰和私鑰,它們都可以用下面這個公式概括:
A = k * G
公鑰:A , G
私鑰:k , G
在ECC加密中 G是基准點,k是小於n(基准點的階)的一個素數, A是加密曲線上的一個點
ECC的加密曲線是不固定的,選擇一條好的加密曲線是很重要的,而且無論是加密還是解密我們都需要用到這條曲線,固定一條ECC加密曲線需要六個參數:
P(參數范圍)
a,b(曲線參數)
(Gx,Gy)(基准點)
n(基准點的階)
h(余因子, h = #E(Fq)/n,其中n是基點G的階,這個是可選參數。)
相比到這我們已經有些頭大了,這么多參數要設置?別慌這些在sm2算法里面都是固定的
/*Sm2 中指定的參數 確定下y2 = x3 + ax + b 曲線*/
#define _P "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF"
#define _a "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC"
#define _b "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93"
#define _n "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"
#define _Gx "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7"
#define _Gy "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"
我們所做的一切都是基於sm2中的那條曲線,以上就是理論知識的介紹。
下面我們將如何利用openssl中的ECC算法去實現sm2,這里不得不說,openssl這個東西…有點難用啊。這個大家做好心理准備,要寫很多期的,我們今天先說如何生成sm2的key;
首先我們要先得到國密這條曲線,直接貼代碼有點太不負責任了,我先給大家先說一寫基本的東西:
先講幾個結構體
//BN_CTX openssl中加密算法結構體,里面包含各種加密算法的函數指針
typedef struct bignum_ctx BN_CTX;
//EC_GROUP ecc算法中的組結構體,里面包含着曲線信息
typedef struct ec_group_st
/*
EC_METHOD *meth;
-- field definition
-- curve coefficients
-- optional generator with associated information (order, cofactor)
-- optional extra data (precomputed table for fast computation of multiples of generator)
-- ASN1 stuff
*/
EC_GROUP;
//EC_POINT ecc算法中的點結構體,里面有x,y,z三個值來確地曲線上的一個點
typedef struct ec_point_st EC_POINT;
//EC_KEY ecc算法中的秘鑰結構體,里面包含私鑰、公鑰、曲線信息
typedef struct ec_key_st EC_KEY;
然后我說一下生成key的過程:
//1.先要獲取sm2曲線
//先實例化一個 組對象
EC_GROUP *EC_GROUP_new_curve_GF2m(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
//說明:生成二進制域上的橢圓曲線,輸入參數為p,a和b
//傳入曲線參數
int EC_GROUP_set_curve_GFp(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
//說明:設置素數域橢圓曲線參數;
//設置基准坐標點
int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx)
//說明:設置素數域橢圓曲線上點point的幾何坐標;
//將基准座標傳入組對象
int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor)
//說明:設置橢圓曲線的基G;generator、order和cofactor為輸入參數;
//2.生成秘鑰對
//在sm2曲線上生成秘鑰對
int EC_KEY_generate_key(EC_KEY *eckey)
//說明:生成橢圓曲線公私鑰;
//獲取公鑰坐標點
const EC_POINT* EC_KEY_get0_public_key(EC_KEY *eckey)
//說明:獲取公鑰。
//獲取私鑰素數
const BIGNUM* EC_KEY_get0_private_key(EC_KEY *eckey)
//說明:獲取私鑰
好了 ,下面到了最重要的一步,貼代碼:
include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/ebcdic.h>
#include <openssl/ecdsa.h>
/*Sm2 中指定的參數 確定下y2 = x3 + ax + b 曲線*/
#define _P "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF"
#define _a "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC"
#define _b "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93"
#define _n "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"
#define _Gx "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7"
#define _Gy "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"
....
int sm2_gen_key(PSM2_KEY sm2key)
{
int ret = -1;
EC_KEY* key = NULL;
BN_CTX *ctx = NULL;
EC_GROUP* group = NULL;
EC_POINT* point_p = NULL;
const EC_POINT *point_q = NULL;
BIGNUM *p, *a, *b, *gx, *gy, *z;
assert(sm2key);
p = BN_new();
a = BN_new();
b = BN_new();
gx = BN_new();
gy = BN_new();
z = BN_new();
//初始化一個空算法組
group = EC_GROUP_new(EC_GFp_mont_method());
//將國密算法的參數轉為大數
BN_hex2bn(&p, _P);
BN_hex2bn(&a, _a);
BN_hex2bn(&b, _b);
BN_hex2bn(&gx, _Gx);
BN_hex2bn(&gy, _Gy);
BN_hex2bn(&z, _n); //素數P的階
ctx = BN_CTX_new();
//先確定sm2曲線
//傳入a,b參數
if (!EC_GROUP_set_curve_GFp(group, p, a, b,ctx))
{
goto err_process;
}
//取曲線上的三個點
point_p = EC_POINT_new(group);
//設置基點坐標
if (!EC_POINT_set_affine_coordinates_GFp(group, point_p, gx, gy, ctx))
{
goto err_process;
}
//
////確定P點事否在曲線上
if (!EC_POINT_is_on_curve(group, point_p, ctx))
{
ret = -2;
goto err_process;
}
//設置橢圓曲線的基G,完成了國密曲線
if(!EC_GROUP_set_generator(group, point_p, z, BN_value_one()))
{
ret = -3;
goto err_process;
}
//生成國密Key
key = EC_KEY_new();
if (!EC_KEY_set_group(key, group))
{
ret = -4;
goto err_process;
}
if(!EC_KEY_generate_key(key))
{
ret = -5;
goto err_process;
}
printf("gen key success:\n the prv is %s\n",
BN_bn2hex(EC_KEY_get0_private_key(key)));
sm2key->prv_key.bytes = BN_bn2bin(EC_KEY_get0_private_key(key), sm2key->prv_key.k);
point_q = EC_KEY_get0_public_key(key);
if(!EC_POINT_get_affine_coordinates_GFp(group, point_q, gx, gy , NULL))
{
goto err_process;
}
sm2key->pub_key.bytes = BN_bn2bin(gx, sm2key->pub_key.x);
BN_bn2bin(gy, sm2key->pub_key.y);
ret = 0;
err_process:
if (point_p != NULL)
{
EC_POINT_free(point_p);
}
if (group != NULL)
{
EC_GROUP_free(group);
}
if (ctx != NULL)
{
BN_CTX_free(ctx);
}
if (key != NULL)
{
EC_KEY_free(key);
}
return ret;
}
