對接JAVA SM2加密遇到的坑

遇到有接口須要使用國密的SM2算法,對方使用的是JAVA,咱們使用的是go,原覺得都是標準算法不會有什麼大問題,結果巨坑沒法..java

對方使用的加密模塊,SM2.java和SM2KeyPairs.java,不知道最初是誰開發的,網上貌似不少都是這個版本的實現,可是和go的交互老是有問題,用這個java模塊加密的,go裏面怎麼也沒法正確解密。仔細覈對以後發現,這個java模塊有幾個地方並不符合GB/T32891的標準。算法

SM2加密的流程

  1. SM2使用的橢圓曲線基點記爲G,私鑰爲整數d, 公鑰爲P = dG.,這裏K、G爲橢圓曲線上的點,d爲正整數
  2. 選擇隨機整數k,計算 C1 = kG, C4 = kP
  3. 以點C4的X/Y兩座標爲參數,計算一組字節流T,與明文進行異或運算,結果爲C2
  4. 已C1和明文組合,用SM3算法計算哈希值C3
  5. 將C一、C二、C3組合爲加密後的密文

這裏只要獲得C4,便能進行解密,而C4 = kP = kdP = dkP = d(kC) = dC1。而C1是密文的一部分,因此有了私鑰d即可以進行解密。數組

這裏的P、G、C一、C4是橢圓曲線上的點,點的乘法只具備幾何意義上,並不是2X3=6的算術運算。編碼

SM2 java模塊與標準差別

1. 加密密文的組合

加密後的密文,標準爲C1 || C3 || C2,C3位SM3哈系值,而這個庫中結果爲 C1 || C2 || C3。加密

2. Java BigInteger的最高位爲1時編碼錯誤

Java中,BigInteger的最高位爲1時,toByteArray()獲得的字節數組會多一位,在前面多了一個爲0的字節,應該是要表示爲正數。致使運算結果和其餘語言的不一致。spa

3. 計算T時的差別

計算T時,須要用點C4的X座標和Y座標組合進行,這個庫裏直接調用bouncycastle庫裏,ECPoint類的getEncoded()的方法,獲得的結果是在字節流里加了一個字節(0x4),實際是不須要的,致使計算的字節流T有差別code

4. 取點的X/Y座標時沒有正則化

java的bouncycastle庫裏,在橢圓曲線的計算中,使用了X/Y/Z三個座標,而其餘的實現多是沒有Z座標的,因此調用點的座標的時候,應該調用normalize()方法正則化後使用,這時Z座標是1。orm

而在這個庫中,並無進行正則化的操做,致使加密結果沒法與其餘程序進行交互,除非對方也使用的bouncycastle庫,可實現方式與其相似。接口

相關文章
相關標籤/搜索