解讀國密非對稱加密算法SM2

本文先介紹非對稱加密算法,然後聊一聊橢圓曲線密碼算法(Elliptic Curve Cryptography,ECC),最後纔是本文的主題國密非對稱加密算法SM2。因爲我的數學知識有限,對於算法涉及的一些複雜的理論知識,也是不懂,所以本文不會涉及理論,僅僅從編程的角度解讀一下SM2。

在進行國密算法開發的這段時間,我主要參考的書籍是《深入淺出HTTPS:從原理到實戰》,微信讀書上也有電子版,如果你也是進行網絡安全方面的開發,建議你讀一讀。這篇文章中的密碼學基礎知識也是來自此書。

對計算機安全有點基礎知識的人們應該知道,在密碼學中,用於數據加密的算法主要有兩種:對稱加密算法(Symmetric-keyAlgorithms)和非對稱加密算法(Asymmetrical Cryptography)。所謂對稱加密算法,就是加密密鑰和解密密鑰相同,這個很好理解,就像我們給房間上鎖,鎖門的鑰匙和開門的鑰匙是一樣的。而非對稱密鑰加密算法則是加密密鑰和解密密鑰不同,這個有點違反普通常理,但確實存在這樣的算法,其背後的理論非常複雜。我們不需要懂得多少其背後的理論,也可以採用非對稱密碼算法做很多安全方面的工作。

在整個密碼學體系中,非對稱加密算法用途更廣,可以用在加密解密、密鑰協商、數字簽名等方面。所以本文先介紹一下非對稱加密算法。

非對稱加密算法

非對稱加密算法也稱作公開密鑰算法(Public Key Cryptography),有着一對密鑰:公鑰(Public Key)和私鑰(Private Key)。

  1. 加密解密

非對稱加密算法的首要用途是加密解密,通常加密解密過程如下圖所示:

公開密鑰算法加密解密過程

需要注意的是,上面只是其中一種用法,反過來,採用私鑰加密,公鑰解密也可以的。具體採用哪種方式,取決於使用場景。

非對稱加密算法的安全性建立在複雜的數學模型之上,其背後的理論不用去深究。我們需要知道的是其安全性和密鑰對的長度有關,儘量選擇較長的密鑰長度。例如,對於RSA非對稱加密算法來說,一個2048比特長度的密鑰對被認爲是安全的。但較長的密鑰長度會帶來運算速度問題,需要綜合權衡。

  1. 密鑰協商

非對稱密鑰算法存在加解密速度慢的問題,因此不能用於需要頻繁加密大量數據的場景,這個時候需要用到對稱密鑰加密算法。問題是,怎麼保證對稱密鑰的安全呢?特別是互聯網網絡通信中,密鑰如何通過不安全的網絡發送,如何保證對方會安全的存儲密鑰?

這個時候,可以採用動態密鑰,也叫作會話密鑰:

  • 會話密鑰的作用就是爲了加密解密通信數據,也就是對稱加密算法可以使用會話密鑰進行加密解密。

  • 在加密解密通信數據之前,客戶端和服務器端協商出會話密鑰,而會話密鑰只有服務器端和特定的客戶端才能知曉。

  • 會話密鑰的意思就是該密鑰不用存儲,一旦客戶端和服務器端的連接關閉,該密鑰就會消失,由於密鑰不用存儲,安全性就得到了很大的保障。

會話密鑰可通過密鑰協商算法完成,但密鑰協商算法可以有很多種,目前主要採用的密鑰協商算法有RSA密鑰協商算法DH密鑰協商算法

  1. 數字簽名

數字簽名可以想象爲現實世界中的合同簽名,其主要作用是防抵賴,比如你給對方發送了一段消息,然後你否認這個消息是你發送的。

在現實世界中,有哪些行爲或者約定可以防止人抵賴呢?最明顯的就是合同,合同一般需要人簽字或者按指紋。有了合同,合同簽署人就無法否認合同的合法性,原因就在於法律規定,指紋具備唯一性,每個人的指紋是不同的,或者說指紋就代表了一個人。

在密碼學中,如果一個消息也含有特殊的指紋,那麼它是否就不能抵賴呢?非對稱加密算法中,私鑰只有密鑰對的生成者持有,如果不考慮密鑰泄露的問題,私鑰擁有者使用密鑰(注意不是加密操作)簽署一條消息,然後發送給任意的接收方,接收方只要擁有私鑰對應的公鑰,就能成功反解簽署消息,由於只有私鑰持有者才能“簽署”消息,不能抵賴說這條簽署消息不是他發送的,這就是數字簽名技術的全部。

簽名生成流程:

簽名流程

簽名驗證流程:

驗籤流程

需要注意,上面只是總的流程,簽名算法也有很多種,各種算法在實現上還是有很多不同,請根據需要再深入到具體的算法中。

非對稱密鑰算法中最出名、使用最廣泛的要數RSA算法,該算法是Ron Rivest、Adi Shamir、Leonard Adleman三個人創建的,以三個人名字的首字母命名。算法自1977年公開,沿用至今,體現出理論知識的威力。然而,前面也說過,RSA的安全性和密鑰長度有關,隨着計算機運算速度的提升,需要更長的密鑰長度保證安全性。問題是,密鑰長度越長,生成密鑰的時間也越長,加密解密的速度也越慢。

這麼些年來,密碼學家也沒有閒着,設計出了新一代的公開密鑰算法:橢圓曲線密碼算法(ECC)。

ECC

ECC主要的優點就是安全性,極短的密鑰能夠提供很大的安全性。比如224比特的ECC密鑰和2048比特的RSA密鑰可以達到同樣的安全水平,由於ECC密鑰具有很短的長度,運算速度非常快。

ECC基於非常複雜的算法,我看了一些這方面的理論知識,也是雲裏霧裏,所以這裏只說說和我們使用和編程相關的基礎知識。

不理解ECC理論知識沒有關係,但需要了解以下這張圖:

ECC模型

ECC橢圓曲線由很多點組成,這些點由特定的方程式組成的,比如方程式可以是y^2 = x^3 + ax + b,這些點連接起來就是一條曲線,但曲線並不是一個橢圓。

橢圓曲線有個特點,任意兩個點能夠得到這條橢圓曲線上的另外一點,這個操作稱爲打點,經過多次(比如d次)打點後,能夠生成一個最終點(F)。

在上面的圖中,A點稱爲基點(G)或者生成器。A可以和自己打點從而生成B點,在實際應用的時候,一般有基點就可以了。經過多次打點,就得到了最終點G。

ECC密碼學的關鍵點就在於就算知道具體方程式、基點(G)、最終點(F),也無法知曉一共打點了多少次(d)。

ECC中,打點次數(d)就是私鑰,這通常是一個隨機數,公鑰就是最終點(F),包含(x,y)兩個分量,通常組合成一個數字來傳輸和存儲。

ECC由方程式(比如a、b這樣的方程式參數)、基點(G)、質數(P)組成。理論上方程式和各種參數組合可以是任意的,但是在密碼學中,爲了安全,系統預先定義了一系列的曲線,稱爲命名曲線(name curve),比如secp256k1就是一個命名曲線。對於開發者而言,在使用ECC密碼學的時候,就是選擇具體的命名曲線。

說到這兒,和國密SM2算法有什麼關係?

國密SM2算法

SM2算法就是一種ECC算法,準確來說,就是設計了一條ECC命名曲線。這算抄襲麼?也不是,因爲設計一條安全的命名曲線,也是一件非常難的事情,需要豐富的理論知識。ECC本質上就是一個數學公式,任何人基於公式都可以設計出橢圓曲線,但要注意ECC離散對數問題(Elliptic-Curve Discrete-Logarithm Problem,簡稱ECDLP),如果實現不當,那麼ECC公式就會存在安全風險。一些組織爲此還定義了命名曲線的一些設計標準,不同的設計標準有不同的目標,比如有的以安全性爲首要目標,有的以效率爲首要目標。

在《GMT 0003-2012》這份標準中,有SM2算法的設計背景知識,有興趣的可以瞭解,對於開發者而言,最重要的是《GMT 0003.5-2012》標準中的曲線參數:

p、a、b、G(x,y)和n

現在的網絡庫,比如NSS、OpenSSL、libtomcrypt等,都有ECC算法的支持,要在網絡庫中加入SM2算法支持,只需加入命名曲線的參數即可。

比如在GmSSL代碼的 ec_curve.c 文件中就有 sm2p256v1 命名曲線的參數定義:

static const struct {
    EC_CURVE_DATA h;
    unsigned char data[0 + 32 * 6];
} _EC_SM2_PRIME_256V1 = {
    {
        NID_X9_62_prime_field, 0, 32, 1
    },
    {
        /* no seed */
        /* p */
        0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        /* a */
        0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
        /* b */
        0x28, 0xE9, 0xFA, 0x9E, 0x9D, 0x9F, 0x5E, 0x34, 0x4D, 0x5A, 0x9E, 0x4B,
        0xCF, 0x65, 0x09, 0xA7, 0xF3, 0x97, 0x89, 0xF5, 0x15, 0xAB, 0x8F, 0x92,
        0xDD, 0xBC, 0xBD, 0x41, 0x4D, 0x94, 0x0E, 0x93,
        /* x */
        0x32, 0xC4, 0xAE, 0x2C, 0x1F, 0x19, 0x81, 0x19, 0x5F, 0x99, 0x04, 0x46,
        0x6A, 0x39, 0xC9, 0x94, 0x8F, 0xE3, 0x0B, 0xBF, 0xF2, 0x66, 0x0B, 0xE1,
        0x71, 0x5A, 0x45, 0x89, 0x33, 0x4C, 0x74, 0xC7,
        /* y */
        0xBC, 0x37, 0x36, 0xA2, 0xF4, 0xF6, 0x77, 0x9C, 0x59, 0xBD, 0xCE, 0xE3,
        0x6B, 0x69, 0x21, 0x53, 0xD0, 0xA9, 0x87, 0x7C, 0xC6, 0x2A, 0x47, 0x40,
        0x02, 0xDF, 0x32, 0xE5, 0x21, 0x39, 0xF0, 0xA0,
        /* order */
        0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0x72, 0x03, 0xDF, 0x6B, 0x21, 0xC6, 0x05, 0x2B,
        0x53, 0xBB, 0xF4, 0x09, 0x39, 0xD5, 0x41, 0x23
    }
};

代碼中的order就是參數表中的 n。對於大部分ECC操作來說,不需要該值,但在計算簽名的時候會對n取模。

小結

本文從非對稱密碼算法開始,逐步介紹到國密SM2算法。我們可以看到,SM2並不是一個全新設計的算法,而是藉助現有的ECC理論,設計了一條命名曲線。這樣,在已經實現了ECC算法的網絡庫上增加SM2算法的支持就非常簡單,只需要將曲線參數添加即可。

但這是否就已經完全實現了SM2算法呢?也不是,因爲SM2算法不僅用在加解密,還用在數字簽名、密鑰協商中,國密標準另外定義了數字簽名算法、密鑰交換協議、公鑰加密算法,所以要把這些都實現完整,纔算實現完全了國密SM2算法。

如果大家有什麼問題,歡迎交流。

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