1. 程式人生 > >小王的尷尬日常(四)--openssl 實現國密演算法(簽名和驗籤)

小王的尷尬日常(四)--openssl 實現國密演算法(簽名和驗籤)

昨天呢,更新了加密和解密的實現,今天我們接著來簽名和驗籤。
還是按照王氏慣例先說一下這個理論知識:

下列符號適用於本部分。
A,B:使用公鑰密碼系統的兩個使用者。
a,b: Fq中的元素,它們定義Fq上的一條橢圓曲線E。
2dA:使用者A的私鑰。
E(Fq): Fq上橢圓曲線E 的所有有理點(包括無窮遠點O)組成的集合。
e:密碼雜湊函式作用於訊息M的輸出值。
e′:密碼雜湊函式作用於訊息M ′的輸出值。
Fq
:包含q個元素的有限域。
G:橢圓曲線的一個基點,其階為素數。
Hv
( ):訊息摘要長度為v位元的密碼雜湊函式。
IDA:使用者A的可辨別標識。
M:待簽名的訊息。
M ′:待驗證訊息。
modn:模n運算。例如, 23mod7=2。
n:基點G的階(n是#E(Fq)的素因子)。
O:橢圓曲線上的一個特殊點,稱為無窮遠點或零點,是橢圓曲線加法群的單位元。
PA:使用者A的公鑰。
q:有限域Fq中元素的數目。
x ∥ y: x與y的拼接,其中x、 y可以是位元串或位元組串。
ZA:關於使用者A的可辨別標識、部分橢圓曲線系統引數和使用者A公鑰的雜湊值。
(r,s):傳送的簽名。
(r′,s′):收到的簽名。
[k]P:橢圓曲線上點P的k倍點,即, [k]P= P + P + · · · + P(k個P, k是正整數)。
[x,y]:大於或等於x且小於或等於y的整數的集合。
⌈x⌉:頂函式,大於或等於x的最小整數。例如, ⌈7⌉=7, ⌈8.3⌉=9。
⌊x⌋:底函式,小於或等於x的最大整數。例如, ⌊7⌋=7, ⌊8.3⌋=8。
#E(Fq): E(Fq)上點的數目,稱為橢圓曲線E(Fq)的階。

sm2簽名演算法流程

設待簽名的訊息為M,為了獲取訊息M的數字簽名(r,s),作為簽名者的使用者A應實現以下運算步
驟:
A1:置M=ZA ∥ M;
A2:計算e = Hv(M),按本文字第1部分4.2.3和4.2.2給出的細節將e的資料型別轉換為整數;
A3:用隨機數發生器產生隨機數k ∈[1,n-1];
A4:計算橢圓曲線點(x1,y1)=[k]G,按本文字第1部分4.2.7給出的細節將x1的資料型別轉換為整
數;
A5:計算r=(e+x1) modn,若r=0或r+k=n則返回A3;
A6:計算s = ((1 + dA)−1 · (k − r · dA)) modn,若s=0則返回A3;
A7:按本文字第1部分4.2.1給出的細節將r、 s的資料型別轉換為位元組串,訊息M 的簽名為(r,s)。

下面是流程圖:
簽名演算法流程圖

sm2演算法驗籤流程

為了檢驗收到的訊息M ′及其數字簽名(r′, s′),作為驗證者的使用者B應實現以下運算步驟:
B1:檢驗r′ ∈[1,n-1]是否成立,若不成立則驗證不通過;
B2:檢驗s′ ∈[1,n-1]是否成立,若不成立則驗證不通過;
B3:置M ′=ZA ∥ M ′;
B4:計算e′ = Hv(M ′),按本文字第1部分4.2.3和4.2.2給出的細節將e′的資料型別轉換為整數;
B5:按本文字第1部分4.2.2給出的細節將r′、 s′的資料型別轉換為整數,計算t = (r′ + s′) modn,
若t = 0,則驗證不通過;
B6:計算橢圓曲線點(x′ 1; y1 ′ )=[s′]G + [t]PA;
B7:按本文字第1部分4.2.7給出的細節將x′ 1的資料型別轉換為整數,計算R = (e′ + x′ 1) modn,檢
驗R=r′是否成立,若成立則驗證通過;否則驗證不通過。

下面是流程圖:
驗籤流程圖

最後是最關鍵的一步上程式碼:
簽名的程式碼

int iret;
    unsigned char ENTLA[3] = {0};
    unsigned char ZA[33] = {0};

    unsigned char* Z = NULL, *M1 = NULL;
    int z_len;

    EC_POINT* kG = NULL;
    BIGNUM* k = NULL, *e = NULL, *kGx = NULL, 
        *kGy= NULL, *r=NULL, *s=NULL, *dA=NULL; 


    ENTLA[0] = (ida_len>>8)&0xff;
    ENTLA[1] = ida_len&0xff;

    z_len = ida_len + 194;
    Z = new unsigned char[z_len + 1];

    memset(Z, 0, z_len + 1);
    memcpy(Z, ENTLA, 2);
    memcpy(&Z[2], IDA, ida_len);
    BN_bn2bin(this->a, &Z[ida_len+2]);
    BN_bn2bin(this->b, &Z[ida_len+34]);
    BN_bn2bin(this->gx, &Z[ida_len+66]);
    BN_bn2bin(this->gy, &Z[ida_len + 98]);
    BN_bn2bin(this->pubx, &Z[ida_len + 130]);
    BN_bn2bin(this->puby, &Z[ida_len + 162]);

    if(!hash(Z, z_len, ZA, "sha256"))
    {
        iret = -1;
        goto signature_end;
    }

    M1 = new unsigned char[33 + m_len];
    memset(M1, 0, 33 + m_len);
    memcpy(M1, ZA, 32);
    memcpy(&M1[32], M, m_len);

    if(!hash(M1, m_len + 32, ZA, "sha256"))
    {
        iret = -2;
        goto signature_end;
    }

    k = BN_new();
    BN_rand_range(k, this->z);

    e = BN_new();
    BN_bin2bn(ZA, 32, e);

    kG = EC_POINT_new(this->mGroup);
    EC_POINT_mul(this->mGroup, kG, NULL, 
        this->mGP, k, this->ctx);

    kGx = BN_new();
    kGy = BN_new();

    if(!EC_POINT_get_affine_coordinates_GFp(this->mGroup, 
        kG, kGx, kGy, this->ctx))
    {
        iret = -3;
        goto signature_end;
    }

    r = BN_new();
    s = BN_new();

    //r=(e+x1) modn

    BN_add(s, kGx, e);
    BN_mod(r, s, this->z, this->ctx);

    //s=((k − r*dA)*(1 + dA)逆)modn
    dA = BN_new();
    BN_copy(dA, EC_KEY_get0_private_key(this->mKey));
    BN_mul(s, r, dA, this->ctx);
    BN_sub(k, k, s);

    BN_add_word(dA, 1);

    BN_mod_inverse(s, dA, this->z, this->ctx);
    BN_mod_mul(s, s, k, this->z ,this->ctx);
    BN_bn2bin(r, out);
    BN_bn2bin(s, &out[BN_num_bytes(r)]);

signature_end:
    if(M1 != NULL) delete[] M1;
    if(Z != NULL) delete[] Z;

    M1 = NULL;
    Z = NULL;

    if(kG != NULL)EC_POINT_free(kG);

    if(k != NULL)BN_free(k);
    if(e != NULL)BN_free(e);
    if(kGx != NULL)BN_free(kGx);
    if(kGy != NULL)BN_free(kGy);
    if(r != NULL)BN_free(r);
    if(s != NULL)BN_free(s);
    if(dA != NULL)BN_free(dA);

    return iret;

驗籤的演算法

int iret;
    unsigned char br[65] = {0};
    unsigned char bs[65] = {0};

    int z_len;
    unsigned char* Z = NULL, *M1 = NULL; 
    unsigned char ZA[33] = {0};
    unsigned char ENTLA[3] = {0};

    EC_POINT* T = NULL, *sG = NULL, *tPa= NULL;
    BIGNUM* r = NULL, *s = NULL, *temp= NULL, 
        *e = NULL, *t = NULL, *x = NULL, *y = NULL;

    memcpy(&br[32], sign, 32);
    memcpy(&bs[32], &sign[32], 32);

    r = BN_new();
    s = BN_new();

    BN_bin2bn(br, 64, r);
    BN_bin2bn(bs, 64, s);

    temp = BN_new();
    BN_one(temp);

    if( BN_ucmp( r, this->z)>0 
        || BN_ucmp(s, this->z)>0 
        || BN_ucmp(temp, r) > 0 
        || BN_ucmp(temp, s) > 0)
    {
        iret = -1;
        goto verify_end;
    }

    z_len = ida_len + 194;
    Z = new unsigned char[z_len + 1];


    ENTLA[0] = (ida_len>>8)&0xff;
    ENTLA[1] = ida_len&0xff;

    memset(Z, 0, z_len + 1);
    memcpy(Z, ENTLA, 2);
    memcpy(&Z[2], IDA, ida_len);
    BN_bn2bin(this->a, &Z[ida_len+2]);
    BN_bn2bin(this->b, &Z[ida_len+34]);
    BN_bn2bin(this->gx, &Z[ida_len+66]);
    BN_bn2bin(this->gy, &Z[ida_len + 98]);
    BN_bn2bin(this->pubx, &Z[ida_len + 130]);
    BN_bn2bin(this->puby, &Z[ida_len + 162]);


    hash(Z, z_len, ZA, "sha256");

    M1 = new unsigned char[33 + m_len];
    memset(M1, 0, 33 + m_len);
    memcpy(M1, ZA, 32);
    memcpy(&M1[32], M, m_len);

    hash(M1, m_len + 32, ZA, "sha256");

    e = BN_new();
    BN_bin2bn(ZA, 32, e);

    t = BN_new();
    BN_mod_add(t, r, s, this->z, this->ctx);

    sG = EC_POINT_new(this->mGroup);
    tPa = EC_POINT_new(this->mGroup);

    EC_POINT_mul(this->mGroup, sG, NULL, 
        this->mGP, s, this->ctx);

    EC_POINT_mul(this->mGroup, tPa, NULL, 
        EC_KEY_get0_public_key(this->mKey),
        t, this->ctx);

    T = EC_POINT_new(this->mGroup);
    EC_POINT_add(this->mGroup, T, sG, tPa, this->ctx);

    x = BN_new();
    y = BN_new();

    if(!EC_POINT_get_affine_coordinates_GFp(this->mGroup,
        T, x, y, this->ctx))
    {
        iret = -2;
        goto verify_end;
    }

    BN_mod_add(temp, x, e, this->z, this->ctx);

    if(BN_cmp(temp, r))
    {
        iret = -3;
        goto verify_end;
    }

verify_end:
    if (Z!= NULL)delete[] Z;
    if(M1 != NULL)delete[] M1;

    Z = NULL;
    M1 = NULL;

    if (sG != NULL)EC_POINT_free(sG);
    if (tPa != NULL)EC_POINT_free(tPa);
    if (T != NULL)EC_POINT_free(T);

    if(r != NULL) BN_free(r);
    if(s != NULL)BN_free(s);
    if(temp != NULL)BN_free(temp);
    if(e != NULL)BN_free(e);
    if(t != NULL)BN_free(t);
    if(x != NULL)BN_free(x);
    if(y != NULL)BN_free(y);

    return iret;

這只是程式碼的實現,後面我會對演算法的效率進行優化,但說實在的我們呼叫了openssl 優化幅度可能不大,牛逼的可以自己去全部實現以下,而且現在很少有人用軟演算法了,大家都用硬體加密了。

相關推薦

尷尬日常--openssl 實現演算法簽名

昨天呢,更新了加密和解密的實現,今天我們接著來簽名和驗籤。 還是按照王氏慣例先說一下這個理論知識: 下列符號適用於本部分。 A,B:使用公鑰密碼系統的兩個使用者。 a,b: Fq中的元素,它們定義Fq上的一條橢圓曲線E。 2dA:使用

尷尬日常---Openssl 實現演算法(基礎介紹產生祕鑰對)

國密非對稱加密演算法又稱sm2,它是採取了ECC(曲線加密演算法)中的一條固定的曲線,實際上就是ECC演算法。 那麼這次讓我尷尬的是什麼呢?我現在維護一個專案,裡面包含了大量的加密演算法,而且很多是自己實現的,其中ECC演算法就有問題,現在打算用openssl

尷尬日常--Openssl 實現演算法加密解密

上一次講了產生金鑰,這次我們講一下加密解密的實現。 先說一下加密解密的流程,一下這些內容都是從國密局釋出的國密標準文件裡面摘錄出來的。大家可以去國密局的網站上自己下載。 下列符號適用於本部分。 A,B:使用公鑰密碼系統的兩個使用者。 a,b

數字證書應用綜合揭祕包括證書生成、加密、解密、簽名

引言 數字證書是一個經證書授權中心數字簽名的包含公開金鑰擁有者資訊以及公開金鑰的檔案。為現實網路安全化標準,如今大部分的 B2B、B2C、P2P、O2O 等商業網站,含有重要企業資料個人資料的資訊資信網站,政府機構金融機構等服務網站大部分都使用了數字證書來加強網路的安全性。數字證書一般由經過國家認證的權威機

OpenSSL 命令詳解——摘要演算法簽名

鋒影 email:[email protected] 如果你認為本系列文章對你有所幫助,請大家有錢的捧個錢場,點選此處贊助,贊助額0.1元起步,多少隨意 用什麼摘要演算法指令代替時,預設使用該演算法,但也可以指定其他演算法。 使用指令 

Spring Boot + Java爬蟲 + 部署到Linux八、Nginx實現反向代理、動靜分離websocket處理

    Nginx (engine x) 是一個高效能的HTTP和反向代理伺服器,也是一個IMAP/POP3/SMTP伺服器。所以,我們就用Nginx來實現反向代理和動靜分離的功能。    反向代理,通過搜尋、百科也可以大概知道。不過因為同為代理,所以總是和正向的代理區分不了

SM系列演算法

原文地址:科普一下SM系列國密演算法(從零開始學區塊鏈 189) 眾所周知,為了保障商用密碼的安全性,國家商用密碼管理辦公室制定了一系列密碼標準,包括SM1(SCB2)、SM2、SM3、SM4、SM7、SM9、祖沖之密碼演算法(ZUC)那等等。其中SM1、SM4、SM7、祖沖之密碼(ZUC)是對稱演算法;SM

openssl rsa 加密,解密,簽名簡單例子

#include<openssl/pem.h> #include<openssl/ssl.h> #include<openssl/rsa.h> #include<openssl/evp.h> #include<opens

iOS中使用Openssl X509證書進行字串簽名

利用openssl 和x509證書對字串進行簽名和驗籤 //簽名 -(NSString *)rsaSignStringwithString:(NSString *)stringToSign { _signErrorMessage = [[NSStringalloc]ini

日常訓練&知識學習」莫隊演算法:樹上莫隊Count on a tree II,SPOJ COT2

題意與分析 題意是這樣的,給定一顆節點有權值的樹,然後給若干個詢問,每次詢問讓你找出一條鏈上有多少個不同權值。 寫這題之前要參看我的三個blog:CFR326D2E、CFR340D2E和HYSBZ-1086,然後再看這幾個Blog—— 參考A:https://blog.sengxian.com/algori

Hadoop學習記錄、hadoop實現檔案操作

1.從Hadoop URL讀取資料 類似cat命令 public class URLCat { static{ URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory()); }

Spring基礎學習 AOP 註解實現

配置XML  applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"

機器學習——協同過濾的ALS演算法2、主成分分析

Kendall秩相關係數(Kendall rank correlation coefficient) 對於秩變數對(xi,yi),(xj,yj): (xi−xj)(yi−yj)⎧⎩⎨>0,=0,<0,concordantneither con

C#簡單的JPush極光推送 API實現推送功能來自mojocube的博客

size 返回 log c# api live str -s 周期 APP推送功能大家應該都了解了,目前主要的有百度、極光等幾家公司提供推送服務,下面說一下極光推送API的簡單實現推送通知功能。 註冊完極光的賬號後,就可以創建應用,建好後會得到AppKey和Master

Java運算符使用總結重點:自增自減、位運算邏輯運算

運算 計算器 可讀性 過多 移位運算 style avi 學會 new Java運算符共包括這幾種:算術運算符、比較運算符、位運算符、邏輯運算符、賦值運算符和其他運算符。(該圖來自網絡) 簡單的運算符,就不過多介紹使用了,可自行測試。關於賦值運算,可以結合算術運

Java RSA SHA1withRSA簽名

enc exce x509 get ont pat ram sign ase static { try { SIGNATURE = Signature.getInstance("SHA1withRSA", "BC"); } catch (N

二進制安裝kubernetes v1.11.2 第三章 二進制文件下載kubectl部署

github size date 令行 uber jin config文件 建議 根證書 繼續部署。 四、kubernetes 二進制文件下載 下載頁面:https://github.com/kubernetes/kubernetes/blob/master/CHANGEL

十大經典排序演算法動圖演示 十大經典排序演算法動圖演示

十大經典排序演算法(動圖演示)   0、演算法概述 0.1 演算法分類 十種常見排序演算法可以分為兩大類: 非線性時間比較類排序:通過比較來決定元素間的相對次序,由於其時間複雜度不能突破O(nlogn),因此稱為非線性時間比較類排序。 線性

(排序演算法)linux c語言實現選擇排序演算法氣泡排序的略微改進版

 快速排序演算法和氣泡排序演算法是差不多的,都是要兩層迴圈,外迴圈是要比較的個數,其實就是元素的個數,內迴圈就是外層那個標記和其他的比較大小, 氣泡排序是相鄰的兩個,兩兩比較,最後交換出一個最大或者最小值, 快速排序是在氣泡排序的基礎上,找出那個最小的或者最大的,但是不是直接交換,

Linux 基礎知識 rpm 命令安裝軟體 、第三方平臺的搭建 網路源

一、RPM簡單介紹 RPM是Linux開發商將原始碼在特定硬體平臺和作業系統平臺上編譯後,記載軟體相依性應編輯成檔案,並將這兩者打包成的一個特殊格式的檔案。使用RPM安裝後,各文件會被安裝到特定的目錄下,所以很方便查詢、升級(使用YUM)與解除安裝。 二、下載軟體安裝包 我的軟體