文章目录
严重声明:本文章只做技术讲解,不会涉及商业机密,如有侵权,请联系本人删除!
概要
随着信息安全意识的提升,国密算法在保障数据安全方面发挥着至关重要的作用。当前趋势下,国内大部分加密机厂商均已国产算法代替了国际算法,这些厂商包括江南科友、网御星云、天融信、三未信安、山东得安、卫士通、山东渔翁、无锡江南、江南天安、江南博仁、兴唐通信、中安网脉、君众甲匠、立思辰、江南信安、山东确信、信安世纪等等。此前博主已经写了很多关于国密算法SM2、SM3、SM4的代码实现,涵盖了多种开发语言之前的互通,有兴趣的可以点击主页查看置顶博客。
再次声明,博主没有加密机的任何源码,均以伪代码代替,本篇博客主要演示讲解java代码如何实现与加密机的交互,基于1.64版本的bc算法包(其他版本可以参考博主另外一篇博客做升级降级处理,传送门java bcprov 国密 依赖 jar包 版本 升级 降级 教程),包含加密机主要功能接口,其他开发语言可以参考我之前的博客进行调整。
主要功能接口
1、生成非对称密钥
1.1、介绍
调用加密机的生成非对称密钥对接口,不同厂商的接口ID不一样,此处不列举接口ID。该功能接口需要指定一个密钥名称,然后返回明文hex格式公钥(不同加密机厂商可能返回编码格式有区别),密文hex格式私钥(安全性),类似于java中bcprov算法包中ECKeyPairGenerator类的generateKeyPair方法,该方法得到的AsymmetricCipherKeyPair对象,从中可以获取ECPublicKeyParameters公钥值和ECPrivateKeyParameters私钥值,再转换成hex模式。
1.2、java代码演示
生成密钥的代码博主在之前的代码中演示过,传送门java国密 C#国密 golang国密 NodeJS国密汇总(一),需要注意的是加密机的接口返回的明文公钥前面的标志位04大概率是去掉了的。
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
import java.security.SecureRandom;
public class Sm2KeyPair {
public static void main(String[] args) {
// 初始化
ECKeyPairGenerator keyGen = new ECKeyPairGenerator();
keyGen.init(new ECKeyGenerationParameters(Sm2Params.SM2_DOMAIN_PARAMETERS, new SecureRandom()));
// 生成
AsymmetricCipherKeyPair tempPair = keyGen.generateKeyPair();
// 获取对象
ECPublicKeyParameters pubParameters = (ECPublicKeyParameters) tempPair.getPublic();
ECPrivateKeyParameters pvkParameters = (ECPrivateKeyParameters) tempPair.getPrivate();
// 获取值
byte[] privateKeyBytes = pvkParameters.getD().toByteArray();
ECPoint q = pubParameters.getQ();
byte[] publicKeyBytes = q.getEncoded(false);
// 转换格式
String privateKeyHex = Hex.toHexString(privateKeyBytes);
System.out.println("java privateKeyHex -->" + privateKeyHex);
String publicKeyHex = Hex.toHexString(publicKeyBytes);
System.out.println("java publicKeyHex -->" + publicKeyHex);
// 生成结果
// java privateKeyHex -->00cc5ed0948826adb773cafd4b7514f5ff35ef05bd6374f07007049fec62bca144
// java publicKeyHex -->04b5ce6fb3a4cb301b4d06f4d53a0995caf8cbdb269af30f38868a39390139daba8f1c0daab5d73c7a0de9ed02986bb404196d035005958203abd1dc9eab7c345e
// 加密机接口伪代码,根据具体情况自行调整
// String keyName = "test";
// String response = 加密机.生成非对称密钥(keyName);
}
}
2、导入公钥
2.1、介绍
这个接口主要功能是把第三方的公钥灌入加密机,也就是上一章节中生成出来的公钥导入加密机,私钥自己留存,然后根据后续业务场景再调用签名接口或者数字信封接口(下面章节会依次讲解)。请求报文中主要上送密钥名称和hex格式公钥值,响应成功或失败相关信息。
2.2、java代码演示
// 加密机接口伪代码,根据具体情况自行调整
// String keyName = "test";
// String publicKey = "去掉04标志位的hex字符串";
// String response = 加密机.导入公钥(keyName, publicKey);
3、数字信封数据加密、解密
3.1、介绍
加密这个接口主要功能是使用对称密钥sm4Key对报文msg加密得到msgBySm4,然后使用非对称密钥sm2Key对对称密钥sm4Key加密得到sm4KeyBySm2,其中非对称密钥sm2Key就是1.2章节中生成的公钥,对称密钥sm4Key是加密机自动生成。请求报文中主要上送密钥名称、待加密的明文,响应报文中包含密文msgBySm4和密文密钥sm4KeyBySm2。解密反之,不再赘述。
3.2、java代码演示
此前博主分别在两篇博文中演示了sm4对称加密和sm2非对称加密,传送门java国密 C#国密 golang国密 NodeJS国密汇总(四),java国密 C#国密 golang国密 NodeJS国密汇总(二)。这里演示融合后的代码。
请仔细阅读注释和伪代码。
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.engines.SM4Engine;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
public class DETest {
public static void main(String[] args) {
// 私钥(标志位00)
String privateKeyHex = "00cc5ed0948826adb773cafd4b7514f5ff35ef05bd6374f07007049fec62bca144";
// 公钥(自己使用时候,需要加上标志位04)
String publicKeyHex = "04b5ce6fb3a4cb301b4d06f4d53a0995caf8cbdb269af30f38868a39390139daba8f1c0daab5d73c7a0de9ed02986bb404196d035005958203abd1dc9eab7c345e";
// 明文
String msg = "hello";
// 数字信封加密开始
// 加密前明文填充,PKCS7Padding,如果使用其他工具类,则无需下面这些繁琐的过程
byte[] input = msg