再探國密,SM2和SM4實現的數字信封對接國企


事情起因

事情發生在兩天前,一位朋友找到我問我SM2解密報錯問題,hutool庫和純bc庫都無法解密,而且在私鑰前面加00,密文加04也無法解碼.

事情經過

大致上就是解密過程,有兩部,外層解密和內層解密,外層是有SM4解密文件,得到內層文件,如下圖

image

解密過程

大家假如對國密算法(SM)不是很熟悉,就會去百度上搜索,當然這個問題也沒法谷歌,國外用的確實比較少,很多人會遇見SM2解密時候,

  • 私鑰加00 .
    因為這個是java的鍋,javaBigInteger轉換byte[]占用最低高位來表示符號,所以私鑰一單沒法用32Byte表示就要出現33Byte現象.謹記私鑰d是一個大正整數.
  • 密文加0x04
    這個是標識,一般會在工具類封裝
  • 公鑰加0x04,小部分是0x02
    主要是因為公鑰有很多分類,0x04代表未壓縮的,也就是64Byte,對接某些C類語言不用,具體見實現.

但是這個並不是這次解密錯誤的原因,在使用上述方式后解密過程會報錯,Invalid point encoding 0x30
具體的原因是因為在SM4.key這個加密的文件是使用ASN.1編碼的導致需要先把編碼后的密文解析為正常的C1C3C2新國標GM/T 0003.4-2012的密文之后進行解析.其他自行參考.

解密代碼參考
import cn.hutool.crypto.BCUtil;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.zz.gmhelper.FileUtil;
import org.zz.gmhelper.SM2Util;
import org.zz.gmhelper.SM4Util;

import java.math.BigInteger;
import java.util.Arrays;

public static void main(String[] args) {
try {
	//私鑰,這個是d值產生的,本質是一個正整數,下面是假的,換成自己的私鑰
	String priHex = "8778888XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
	//加密后的SM4密鑰文件
	String keyPath = "/Users/lin/Desktop/gmhelper/gmhelper/src/main/resources/sm4.key";
	//最終db文件的數據壓縮包
	String zipPath = "/Users/lin/Desktop/gmhelper/gmhelper/src/main/resources/xxxxxxxx_xxxxx_xxxxx.zip";
	//解密得到的數據文件
	String unzipPath = "/Users/lin/Desktop/gmhelper/gmhelper/src/main/resources/1.db";

	//獲取由d值生成的私鑰
	ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
		new BigInteger(ByteUtils.fromHexString(priHex)), SM2Util.DOMAIN_PARAMS);
	//讀取ASN.1 der編碼的sm4密鑰文件
	byte[] fData = FileUtil.readFile(keyPath);
	//讀取sm4加密的db文件
	byte[] dbData = FileUtil.readFile(zipPath);
	//解密der編碼密文到C1C3C2
	byte[] r =  SM2Util.decodeDERSM2Cipher(fData);
	//解密
	byte[] decryptedData = SM2Util.decrypt(priKey, r);
	String sm4Key =  new String(decryptedData).substring(0,16);

	//解密db文件
	byte[] dd = SM4Util.decrypt_ECB_NoPadding(sm4Key.getBytes(),dbData);
	FileUtil.writeFile(unzipPath,dd);

	} catch (Exception exception) {
	System.out.println(exception.getMessage());
	}
	}
public class FileUtil {
    public static void writeFile(String filePath, byte[] data) throws IOException {
        try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw")) {
            raf.write(data);
        }
    }

    public static byte[] readFile(String filePath) throws IOException {
        byte[] data;
        try (RandomAccessFile raf = new RandomAccessFile(filePath, "r")) {
            data = new byte[(int) raf.length()];
            raf.read(data);
            return data;
        }
    }
加密過程

相對於解密過程,加密過程就比較輕松了,但是請注意,加密之后的密文有一個04,請手動去除,之后進行ASN.1編碼

加密過程參考代碼
//導入的包
import cn.hutool.crypto.BCUtil;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.zz.gmhelper.FileUtil;
import org.zz.gmhelper.SM2Util;
import org.zz.gmhelper.SM4Util;

import java.math.BigInteger;
import java.util.Arrays;

public  static  void getEncodeSM4Key(byte[] cipher){
try {
	//公鑰,不加04
	String pubHex = "0D1762507F6BD5152545DE6F771396A9FA40958743DD75FE7FB71FBA3D56D045C595C8011E316E0A43CAFFA6FB5C9E2DE97F2EEF8289404EEA7CAA6E484BD4AB";
	//生成的加密sm4文件路徑
	String keyPath = "G:\\code\\project\\Java\\gmhelper\\gmhelper\\src\\main\\resources\\sm4der.key";

	String pubX = pubHex.substring(0,64);
	String pubY = pubHex.substring(64,128);

	//生成公鑰,BC庫封裝的工具類
	ECPublicKeyParameters ecPublicKeyParameters = BCUtil.toSm2Params(pubX,pubY);
	//正常加密C1C3C2
	byte[] sm4eKey = SM2Util.encrypt(ecPublicKeyParameters,cipher);

	byte[] sm4dKey = new byte[sm4eKey.length-1];
	//去掉加密后的首位04,注意
	System.arraycopy(sm4eKey, 1, sm4dKey, 0, sm4dKey.length);

	//編碼后的der
	byte[] sm4DerKey = SM2Util.encodeSM2CipherToDER(sm4dKey);
	//保存為文件
	FileUtil.writeFile(keyPath,sm4DerKey);
	System.out.println(Arrays.toString(FileUtil.readFile(keyPath)));
}catch (Exception e){
	System.out.println(e.getMessage());
}

工具類參考https://github.com/ZZMarquis/gmhelper

文檔參考 http://www.gmbz.org.cn/main/bzlb.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM