國密算法--Openssl 實現國密算法(基礎介紹和產生秘鑰對)


國密非對稱加密算法

又稱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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM