SM2算法+開發中注意事項

目錄

前言

1.概述:

2.術語解讀:(簡單的這裏不做解釋,具體請看文末文檔)

3.基礎參數:

4.密鑰對生成

4.1 公私鑰原理

4.2 公私鑰的生成

4.2.1  私鑰:

4.2.2  簽證書:

4.2.3 用私鑰對證書進行自簽名

4.2.4 證書格式轉換

4.2.5 查看證書內容

5.簽名算法

5.1 預處理1

5.2 預處理2

5.3數字簽名的生成算法及流程

5.4數字簽名的驗證算法及流程


經歷過國密的坑,這裏來對國密進行總結。本篇主要講的SM2國密算法。

前言

先來個SM2和RSA比較

        SM2是國家密碼管理局於2010年12月17日發佈的“橢圓曲線公鑰密碼算法”。這裏附上國家密碼管理局發佈這篇算法的公告地址:http://www.sca.gov.cn/sca/xwdt/2010-12/17/content_1002386.shtml。本篇博客基本是對這篇算法的粗淺解讀,具體密碼算法精髓,則需要你們自行領悟了。

      SM2和橢圓曲線算法是什麼關係?

     一提起曲線,大家就會想到方程,橢圓曲線算法是通過方程確定的,SM2算法採用的橢圓曲線方程爲:
y2 = x3 + ax + b 。在SM2算法標準中,通過指定a、b係數,確定了唯一的標準曲線。同時,爲了將曲線映射爲加密算法,SM2標準中還確定了其它參數,供算法程序使用。
橢圓曲線算法是什麼原理?
本文不探討橢圓曲線的數學理論,僅通過圖示展示算法原理。請參見下圖:

上圖爲方程:y2 = x3–x的曲線。
1、P點爲基點;
2、通過P點做切線,交與點 2P點,在2P’點做豎線,交與2P點,2P點即爲P點的2倍點;
3、進一步,P點和2P點之間做直線,交與3P’點,在3P’點做豎線,交與3P點,3P點即爲P點的3倍點;
4、同理,可以計算出P點的4、5、6、… 倍點;
5、如果給定圖上Q點是P的一個倍點,請問Q是P的幾倍點呢?
6、直觀上理解,正向計算一個倍點是容易的,反向計算一個點是P的幾倍點則困難的多。
在橢圓曲線算法中,將倍數d做爲私鑰,將Q做爲公鑰。當然,橢圓曲線算法還有更嚴格的計算過程,相對圖示要複雜的多。
 

1.概述:

        數字簽名算法由一個簽名者對數據產生數字簽名,並由一個驗證者驗證簽名的可靠性。每個簽名者都有一個公鑰和一個私鑰,其中私鑰用於產生簽名,驗證者用簽名者的公鑰驗證簽名。在簽名的生成過程之前,要用密碼雜湊算法對 ZA和待籤消息 M
M進行壓縮;在驗證過程之前,要用密碼雜湊算法對 ZA 和待籤消息 M進行同樣的壓縮。

2.術語解讀:(簡單的這裏不做解釋,具體請看文末文檔)

        雜湊函數 hash function:將一個比特串映射爲一個固定長度比特串的函數。該函數滿足如下性質:
a) 對於任意給定的輸出,要找到其對應的輸入,在計算上是不可行的;
b) 對於任意給定的輸入,要找到輸出相同的另一個輸入,在計算上是不可行的。注:計算可行性依賴於具體的安全需求和環境。

3.基礎參數:

        橢圓曲線系統參數包括有限域Fq的規模q(當q=2^{a}時,還包括元素表示法的標識和約化多項式); 定義橢圓曲線E(Fq)的方程的兩個元素a、b∈Fq;E(Fq)上的基點G=(x,yG) (G̸=O),其中xG和yG是Fq中 的兩個元素;G的階n及其它可選項(如n的餘因子h等)。

       在前後端SM2加解密簽名應用中,請預先商定一組稱爲橢圓曲線域參數的系統參數。橢圓曲線域參數生成需要大量的計算,耗時較長,一旦生成之後可以長期、廣泛地使用,因此通常由可信的機構經過反覆生成不同的橢圓曲線域參數並挑選出安全性和性能俱佳的公佈爲標準(推薦參數)。我們在用java bc庫,或者GMSSL,亦或OpenSSL 加密庫SM2簽名的時候,請確認你們的橢圓曲線域參數一致,否則聯調不通。(一般庫默認256比特的素數域橢圓曲線域參數

4.密鑰對生成

4.1 公私鑰原理

  

4.2 公私鑰的生成

這裏用GMSSL命令生成SM2證書。

4.2.1  私鑰:

gmssl ecparam -genkey -name sm2p256v1 -text -out user.key

4.2.2  簽證書:

gmssl req -new -key user.key -out user.req。   簽證書會提示以下信息:

What you are about to enter is what is called a Distinguished Name or a DN.

There are quite a few fields but you can leave some blank

For some fields there will be a default value。

證書包含唯一標示,從安全角度考慮建議用公司名或者個人唯一標示,不要用默認。

4.2.3 用私鑰對證書進行自簽名

   gmssl x509 -req -days 3650 -sm3 -in user.req -signkey user.key -out user.crt。有效期建議一年。

4.2.4 證書格式轉換

crt轉cer :gmssl x509 -inform pem -in user.crt -outform der -out user.cer

cer轉p12:openssl pkcs12 -export -clcerts -in user.cer -inkey prikey.pem -out shfft.p12

crt轉p12:將client.crt和client.key轉換爲pkcs12:

openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12

4.2.5 查看證書內容

查看EC私鑰文件

cat attestation_key.pem 

查看crt :gmssl x509 -in user.crt -text -noout 

查看cer:   gmssl x509 -in user.cer -inform der -text -noout

 openssl 生成SM2的公私鑰的方法,可參考鏈接:https://blog.csdn.net/dong_beijing/article/details/81365060。(具體是否可行還未驗證)

5.簽名算法

5.1 預處理1

      我們在用java bc庫,或者GMSSL,亦或OpenSSL 加密庫SM2簽名的時候,庫通常會給我們設置默認值ID爲1234567812345678,或者[email protected]。我們在前後端進行聯調的時候,請確認ID必須一致,否則聯調肯定不通。可以前後端統一設置爲一樣。沒有設置的話,庫會採用默認值,這時候請注意庫不同可能默認值不同。個人建議安全性的話不要用默認值,統一設置。

5.2 預處理2

        預處理2是指使用Z值和待簽名消息,通過SM3運算得到雜湊值H的過程。雜湊值H用於SM2數字簽名。

輸入: Z:字節串,預處理2的輸入
             M:字節串,待簽名消息
輸出: H:字節串,雜湊值
             計算公式:H=SM3(Z∣∣M)

5.3數字簽名的生成算法及流程

SM2簽名是指使用預處理2的結果和簽名者的私鑰,通過簽名計算得到簽名結果的過程。

輸入:d  SM2PrivateKey,簽名者私鑰

            H  字節串,預處理2的結果

輸出:sign SM2Signature,簽名值

先來看張流程圖

             

        sign SM2Signature,簽名值。最終輸出的簽名值,不同的庫可能輸出不同。比如java BC庫最終輸出的是base64的字符串;OpenSSl,GMSSL輸出的是16進制;還有C實現的算法庫輸出的R和S字符串,不同庫之間使用要注意轉換。其中R,S的如何轉換成base64一個簽名值字符串,可以使用OpenSSL裏的Api來轉換如下代碼。而java bc庫裏是R,S用ASN1編碼後得到base64的簽名結果。我逆推並沒成功,具體bc庫怎麼ASN1編碼還有待查看源碼

    BIGNUM *a = NULL;
    BIGNUM *b = NULL;
    const char *signR = [strR cStringUsingEncoding:NSUTF8StringEncoding];
    const char *signS = [strS cStringUsingEncoding:NSUTF8StringEncoding];
    BN_hex2bn(&a,signR);
    BN_hex2bn(&b,signS);
    ECDSA_SIG *sm2sigTemp = ECDSA_SIG_new();
    int setSIG = ECDSA_SIG_set0(sm2sigTemp, a, b);
    if (!setSIG) {
        return nil;
    }
    unsigned char *pp = NULL;
    int toChar = i2d_ECDSA_SIG(sm2sigTemp, &pp);
    if (!toChar) {
        return nil;
    }
    unsigned char sm2signature[toChar];
    memcpy(sm2signature, pp, toChar);
    NSString *signResult =[FFT_Base64 base64StringFromData:[NSData dataWithBytes:sm2signature length:toChar]];

5.4數字簽名的驗證算法及流程

   SM2簽名驗證是指使用預處理2的結果、簽名值和簽名者的公鑰,通過驗籤計算確定簽名是否通過驗證的過程。

輸入:H 字節串,預處理2的結果

           sign SM2Signature,簽名值

            Q PublicKey,簽名者的公鑰

輸出:爲真表示驗證通過,爲假表示驗證不通過

  https://www.cnblogs.com/wsonepiece/p/3977021.html

         目前java bc庫和基於OpenSSL 的C 算法庫能夠很好的實現SM2加解密算法和簽名。而java bc 和GMSSL也能夠實現,並得到驗證,但是沒有項目應用。但是最新的OpenSSL庫也支持SM2了,但是和java bc庫對接時,出現bc庫簽名的內容,OpenSSL庫可以驗證通過,OpenSSL庫簽名的內容,java bc庫卻不能夠驗證通過,這是個坑,具體內容爲什麼,因爲缺乏比較懂 java bc庫的人員配合,導致一致沒有找到原因擱淺

最後感謝博主zcc0721,主要參考他的文章,寫得非常好。

參考鏈接:https://blog.csdn.net/u013137970/article/details/84573200#1__2

                   https://www.cnblogs.com/wsonepiece/p/3977021.html

國家密碼管理局關於發佈《SM2橢圓曲線公鑰密碼算法》公告:http://www.sca.gov.cn/sca/xwdt/2010-12/17/content_1002386.shtml

個人Github文檔地址:https://github.com/yazhouZhang/SM2-SM3-SM4-SM9

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章