SM2_SM3_SM4Encrypt
項目介紹
最近有一個項目需要用到國密算法 , 具體是需要對接硬件加密機調用加密機的JAVA接口實現國密的一整套流程 , 但是由於公司測試環境和阿里雲硬件加密機不通 , 所以只能自己模擬加密機的接口實現一套國密的軟加密實現 。將有關國密的代碼提取並分享出來 , 並且提供了詳細的測試代碼以供參考 。
項目中包括SM2算法的加密/解密/簽名/驗簽 , SM3算法的摘要計算 , SM4算法的對稱加密/解密 , 以及相應算法的公私鑰對的生成方法。
項目測試腳本使用
在項目中的test包下SecurityTestAll.java類中的main方法下有SM2/SM3/SM4的按照加解密流程實現的一整套測試腳本 , 直接直接執行可以輸出如下測試結果:
--產生SM2秘鑰--:
公鑰:04ec7e40b8dfa4b14383f703ec5403b71db0ab505b9fc41f0df45a9910a307dfbd5b3c5afdd4b90d79fa0ab70d53fd88422df77e09b254a53e72b4857f74ab1da4
私鑰:58967e2beb6fffd3c96545eebd3000b39c10087d48faa0d41f9c7bf3720e0ea4
--測試加密開始--
原文UTF-8轉hex:49204c6f766520596f75
加密:
密文:1b40e51d8462d97ac1cc9929039313152b8067eecfcff7ba0348a721d3f4d257e83f924364b84147879906d62a72472403a3c3d36d4cf243055ff77a4c794909673cc0e39954fbc8b01c50a4b708216d4d19c400719734b98bc0a6d7da92a078b6ef8dd9713cee910276
解密:I Love You
--測試加密結束--
--測試SM2簽名--
原文hex:49204c6f766520596f75
簽名測試開始:
軟加密簽名結果:3046022100d2665f92221efd00aa96d2729475aa05690bd10766641fd169c6e13c1a441b87022100c8ff9f00c7bb0a8308e183629cebef53e4fd65542c7ee6068275a606e3010088
加密機簽名結果:d2665f92221efd00aa96d2729475aa05690bd10766641fd169c6e13c1a441b87c8ff9f00c7bb0a8308e183629cebef53e4fd65542c7ee6068275a606e3010088
驗簽1,軟件加密方式:
軟件加密方式驗簽結果:true
驗簽2,硬件加密方式:
簽名R:d2665f92221efd00aa96d2729475aa05690bd10766641fd169c6e13c1a441b87
簽名S:c8ff9f00c7bb0a8308e183629cebef53e4fd65542c7ee6068275a606e3010088
硬件加密方式驗簽結果:true
--簽名測試結束--
--SM3摘要測試--
hash:700B1D31B7BF81A3CE2B5AC97057AE783C9C51F56FA4EA14E13CF3EC6E58159A
--SM3摘要結束--
--生成SM4秘鑰--
sm4Key:c8e8e733ac8c4043a1d6464ae82d70e6
--生成SM4結束--
--SM4的CBC加密--
密文:046be2948f89c9f78e9248fc562a9d0c
CBC解密
解密結果:I Love You
--ECB加密--
ECB密文:851b68592ac1a029976204ef66f62a5d
ECB解密
ECB解密結果:I Love You
下面將會說明使用此加解密包會遇到的問題以及解決方案 , 沒有發現的問題后續還會做補充。
SM2
SM2秘鑰格式說明
在本項目中 , SM2算法中秘鑰都是在DER編碼下輸出的 , SM2秘鑰的組成部分有 私鑰D 、公鑰X 、 公鑰Y , 他們都可以用長度為64的16進制的HEX串表示 。在加解密調用的時候都會將hexString轉換成byte[]后再作為參數傳入。其中SM2公鑰並不是直接由X+Y表示 , 而是額外添加了一個頭 , 比如在硬件加密機中這個頭為:"3059301306072A8648CE3D020106082A811CCF5501822D03420004"。頭的具體表示信息如下
30 (SEQUENCE TAG: SubjectPublicKeyInfo)
59 -len
30 (SEQUENCE TAG: AlgorithmIdentifier)
13 (SEQUENCE LEN=19)
06 (OID TAG: Algorithm)
07 - len
2A8648CE3D0201 (OID VALUE="1.2.840.10045.2.1": ecPublicKey/Unrestricted Algorithm Identifier) --
06 TAG: ECParameters:NamedCurve
08 -len
2A811CCF5501822D (OID VALUE="1.2.840.10045.3.1.7": 國密新曲線--Secp256r1/prime256v1) -- 變量
03 - STRING TAG: SubjectPublicKey:ECPoint
42 - len 66
00 - 填充bit數為0
04 - 無壓縮 就代表公鑰的 , 還需要有一個Head
想詳細了解DER編碼的道友可以參考這篇文章: ECC公鑰格式詳解
需要注意的是 , 在本項目中硬件加密機中公鑰的頭為"3059301306072A8648CE3D020106082A811CCF5501822D03420004" , 而軟加密中的公鑰頭為"04" , 如果有需要對接加密機的道友 , 需要注意這里公鑰頭的問題 。 在類SM2KeyVO.java中的getPubHexInHard()和getPriHexInSoft()方法就是用來解決軟件加密和硬件加密機中頭不一致的問題。
SM2簽名說明
SM2簽名結果可以分解為簽名R和簽名S , 在本項目中簽名返回的簽名結果軟件加密和硬件加密也存在頭不一致的情況 , 硬件加密機返回的簽名結果是標准的R+S , 而軟件加密返回的簽名結果有所不同 , 如果需要對接加密機的道友 , 可以參考類SM2SignVO.java中的getSm2_signForSoft()和getSm2_signForHard()方法 , 可以在標准硬件加密機簽名結果和軟件加密結果中切換。
SM4
SM4秘鑰說明
由於SM4秘鑰長度為32位的hex串 , 所以本項目中直接使用UUID隨機生成的秘鑰串。
SM4的ECB模式和CBC
SM4加解密涉及到ECB模式和CBC模式 , ECB模式簡單有利於計算,但是存在被攻擊的可能 , CBC模式更加安全 , 在加解密的過程中需要傳入一個IV值 , 在本項目中IV值均設置為16進制下的字符串:"31313131313131313131313131313131" , 其實就是UTF-8下的16個"1" 通過getBytes[].toHexString()得來的 , 這個值可以根據需要修改。
在SM4加密算法中 , 要求原始數據長度必須是長度為32的整數倍hex串 , 但是在實際情況中數據長度並不能保證這么長 , 這里就涉及到了原始數據填充的問題 , 在類SM4.java文件中padding()方法使用基於PBOC2.0的加解密數據填充規范 , 在數據后填充一個0x80和多個0x00來解決數據長度填充的問題。
最后
如果發現錯誤 , 請不吝賜教!
源碼在github上,請自取:SM2_SM3_SM4Encrypt github