载入天数...载入时分秒...

再探国密,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

posted @ 2021-12-15 17:21  旧信  阅读(6985)  评论(12编辑  收藏  举报