橢圓曲線的公鑰密鑰算法實現


  RSA的安全性基於兩個大素數的反向求解問題沒有解決,是一種比較簡單的密碼算法,但是RSA的效率低,需要設置很長的密鑰才能保證算法的安全,但是密鑰越長算法效率越低。ECC相比於RSA是一種比較新的公鑰密碼算法,相同的密鑰長度ECC更安全。 

  橢圓曲線上的兩個點P和G,而且P=kG,G是橢圓曲線上的基點,k是私鑰,P是公鑰。給定k和G,根據加法法則計算P很容易,但是給定P和G計算k很難。

  橢圓曲線的加法計算如圖所示。A和B連接起來相較於第三點,再過這個點做與Y軸的平行線,相較於另外一個點,而這個點就是A+B的結果。

                       

 

  橢圓曲線y^2=x^3+ax+b(modP),modP就是把橢圓曲線定義在有限域GF(P)上,使得光滑的橢圓曲線變成一個個點,這些點沒有任何規律。越沒有規律就表示越難破解。如圖所示P=23,(0,1)是基點。

 

   因此,G前面的數,是非常難求的,可以作為私鑰。

橢圓曲線的加解密過程

  1、選擇一條橢圓曲線EC(a,b),取橢圓曲線上的一點作為基點G

  2、選擇一個大數作為私鑰k,並生成公鑰P=kG;

  3、加密:選擇一個隨機數r,將明文M生成密文C,C是密文也是一個點對;

    C=(rG,M+rP)

  4、解密:收到M+rP;接收方是知道私鑰k;

      M+rP-krG=M+rkG-rkG=M

OpenSSL橢圓曲線的密鑰結構體

struct ec_key_st {
    const EC_KEY_METHOD *meth;
    ENGINE *engine;
    int version;
    EC_GROUP *group; //密鑰參數
    EC_POINT *pub_key; //公鑰
    BIGNUM *priv_key;  //私鑰
    unsigned int enc_flag;
    point_conversion_form_t conv_form;
    int references;
    int flags;
    CRYPTO_EX_DATA ex_data;
    CRYPTO_RWLOCK *lock;
};

在生成密鑰之前,需要由用戶選擇一種橢圓曲線設定參數,可以通過以下代碼查看該版本的openssl庫所支持的曲線。選擇其中一條。

int len= EC_get_builtin_curves(NULL, 0); //橢圓曲線個數
    EC_builtin_curve *curves = (EC_builtin_curve*)malloc(sizeof(EC_builtin_curve)*len);
    EC_get_builtin_curves(curves, len);
    for (int i = 0; i < len; i++)
    {
        cout << "nid:" << curves[i].nid << " " << curves[i].comment << endl;
    }
delete [] curves;

部分結果

 

 指定某一條橢圓曲線,獲取該曲線的參數(p,a,b,G)生成密鑰

//int nid = curves[56].nid ,選擇曲線成功返回曲線的一些參數
EC_GROUP* EC_GROUP_new_by_curve_name(int nid);
//設置密鑰參數,成功返回1
int  EC_KEY_set_group(EC_KEY *eckey, EC_GROUP*group);
//生成密鑰,成功返回1
int EC_KEY_generate_key(EC_KEY*eckey);
//驗證密鑰
int EC_KEY_check_key(EC_KEY*eckey);

將EC_KEY格式的密鑰存放在EVP_PKEY中

//生成EVP_PKEY對象,記得使用完畢后調用EVP_PKEY_free()釋放
EVP_PKEY*EVP_PKEY_new();
//成功返回1
int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, struct ec_key_st *key);

使用EVP接口進行加解密

//使用pkey和ENGINE e中指定的算法分配公鑰算法上下文
//成功返回上下文
EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e);
//加密初始化
int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx);
//加密
//@ctx:上下文;@out:輸出空間:@outlen:輸出大小
//@in:輸入;@inlen:輸入大小
int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx,
                     unsigned char *out, size_t *outlen,
                     const unsigned char *in, size_t inlen);
//解密
int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx,
                     unsigned char *out, size_t *outlen,
                     const unsigned char *in, size_t inlen);

代碼實現

EVP_PKEY *ECCGenKey()
{
    
    EC_KEY*eckey = EC_KEY_new();
    //選擇橢圓曲線,設置生成密鑰參數,國密SM2支持加解密
    //secp256k1 不支持加解密,支持簽名和密鑰交換
    int len= EC_get_builtin_curves(NULL, 0);
    EC_builtin_curve *curves = (EC_builtin_curve*)malloc(sizeof(EC_builtin_curve)*len);
    EC_get_builtin_curves(curves, len);
    for (int i = 0; i < len; i++)
    {
        cout << "nid:" << curves[i].nid << " " << curves[i].comment << endl;
    }
    int nid = curves[56].nid;
    EC_GROUP* group = EC_GROUP_new_by_curve_name(nid);
    if (!group)
    {
        ERR_print_errors_fp(stderr);
        EC_KEY_free(eckey);
        return nullptr;
    }
delete[] curves;
//設置密鑰參數 EC_KEY_set_group(eckey, group); //生成密鑰 int re = EC_KEY_generate_key(eckey); if (re != 1) { ERR_print_errors_fp(stderr); EC_KEY_free(eckey); return nullptr; } re = EC_KEY_check_key(eckey); cout << "re:" << re << endl; //將密鑰存在EVP_PKEY中 EVP_PKEY*pkey = EVP_PKEY_new(); EVP_PKEY_set1_EC_KEY(pkey, eckey); EC_KEY_free(eckey); return pkey; } int main() { unsigned char data[] = "hello,i am tangxiao"; unsigned char out[1024] = { 0 }; unsigned char out2[1024] = { 0 }; int datasize = sizeof(data); EVP_PKEY* pkey = ECCGenKey(); //生成EVP_PKEY_CT上下文 auto ctx = EVP_PKEY_CTX_new(pkey, NULL); if (!ctx) { ERR_print_errors_fp(stderr); } //加密初始化 int ret = EVP_PKEY_encrypt_init(ctx); if (ret != 1) { cout << ret << endl; ERR_print_errors_fp(stderr); } size_t outlen = sizeof(out); EVP_PKEY_encrypt(ctx, out, &outlen, data, datasize); cout << "outlen:" << outlen << "||" << out << endl; cout << "------------解密---------------" << endl; int ret = EVP_PKEY_encrypt_init(ctx); if (ret != 1) { cout << ret << endl; ERR_print_errors_fp(stderr); } int insize = outlen; outlen = sizeof(out2); EVP_PKEY_decrypt(ctx, out2, &outlen, out, insize); EVP_PKEY_free(pkey); EVP_PKEY_CTX_free(ctx); return 0; }


免責聲明!

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



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