詳解國密SM2的加密和解密

在上一篇文章《解讀國密非對稱加密算法SM2》介紹了國密非對稱算法SM2,在文章中說到,如果現有的網絡庫中已經實現ECC算法,只需加入SM2命名曲線的參數即可。這對於ECDHE密鑰協商和ECDSA數字簽名這兩種用途而言確實是足夠的。現有的網絡庫,很少將ECC算法直接用於加密和解密。但在實現ECC_SM4_SM3這個密碼套件中,在密鑰交換過程中,存在客戶端將Pre-Master Secret使用 SM2 公鑰加密後傳給服務器端的步驟。所以我們需要實現 SM2 的加密和解密。

如何使用 SM2 算法進行加密和解密,可以參考的資料是《GMT 0003.4-2012 SM2橢圓曲線公鑰密碼算法第4部分:公鑰加密算法》。但這份文檔有些地方描述的並不是很清楚,實現起來也是很頭疼,在參考了GmSSL開源項目的源碼之後,總算把這個過程梳理清楚了。先總結一下,把其中容易出錯的位置重點說明一下,供大家參考。

先來看看國密文檔中關於加密流程的描述:

  1. 在A1步驟中,需要注意不能使用C語言中簡單的隨機數函數,因爲這裏 k 是一個很大的數字,有32字節,在GmSSL是用 BIGNUM 結構來表示的。在一般網絡庫中都會定義這種大整數類型,也會提供了隨機函數發生器。

  2. 在A2步驟中,一般實現了ECC算法的網絡庫都實現了 [k]G 這種運算,找到使用即可。將C1轉化爲比特串,需要考慮CPU大小端的問題,通常網絡庫有現成的函數。

  3. 在A3步驟中,剛開始看文檔沒明白 h 值是什麼,後來才理解到這就是曲線參數的 cofactor,而且這個步驟主要是驗證公鑰PB的有效性,略過也沒問題。

  4. 在A5步驟中,有個KDF函數需要實現。KDF函數的流程如下,其中的Hv函數請使用SM3:

  1. A7步驟的Hash也採用SM3

  2. 在最後拼接 C1 || C3 || C2 步驟,並不是把這些字節拼接起來就完事,我喫過大虧。因爲在解密步驟中,還需要用到 x1、y1、C3、C2這幾個參數,如果拼接成一個bit串,接收方如何拆分?如果我們內部使用,當然可以根據它們各自的長度(對於指定SM2曲線和SM3哈希算法,x1, y1, C3的長度是固定的)來拆分,但這樣不夠靈活,萬一換了命名曲線或哈希算法呢?在文檔中沒有找到說明,但我研究了GmSSL的源碼,才弄明白要採用ASN.1 DER編碼,這樣接受方就可以通過DER解碼,分別拿到x1、y1、C3、C2參數值。關於DER編碼解碼,請參考相關的資料,一般網絡庫都會提供DER編解碼的函數,我們只要調用就可以了。

最後這一步,要是隻看這份文檔,就會掉進一個大坑。我在本地實現了SM2的加密和解密,使用 《GMT 0003.4-2012》文檔附錄中的數據進行測試,也都通過,但在與第三方服務器端對接時,總是解密失敗,後來才發現是因爲這個原因。

國密文檔中關於解密流程的描述:

實現了加密流程後,解密流程的實現就簡單了,這裏不再過多描述。

《GMT 0003.4-2012》文檔附錄A中的測試數據非常有用,有每個步驟的計算結果,可用於排查哪個步驟實現出現問題,在開發中要充分利用。

小結

非對稱加密算法通常很少直接用於數據的加密和解密,主要是考慮到其速度遠低於對稱加密算法。在ECC_SM4_SM3密碼套件中,SM2用於密鑰交換(客戶端生成Pre-Master Secret,加密後傳輸給服務器端)。當然,如果在程序中直接使用SM2加密信用卡卡號之類的小數據也是可以的。

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

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