国密改造已经持续了很长时间了,相信很多从事金融科技类的程序猿都遇到过这个需求。这篇文章就为大家带来笔者对于国密改造的一些经验,主要是代码层面,有兴趣的同学可以研究下国密的算法模型!
注:本文所用到的工具类并非笔者所写!
目录
一、国密简述
国密——国家密码局制定的国家密码算法。主要包含SM1、SM2、SM3、SM4几种方式。
SM1:对称加密,且算法不公开,使用硬件加密,本文不做叙述;
SM2:非对称加密,签名以及生成秘钥速度优于RSA,基于ECC算法,运算效率更高,且更安全;
SM3:摘要,国产杂凑算法,生成长度为256比特,优于MD5以及SHA-1算法;
SM4: 无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度均为128位;
注意
生成SM2 公钥是130 位 前面多了04两个标识符,注意区分!
二、依赖准备
国密主要用到下面的包
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.57</version>
</dependency>
一定注意版本。实际项目中笔者发现项目其他子工程用到1.56版本的包,所以选择了低版本。
三、SM2算法应用
1、生成SM2公私钥
工具类
package cn.test.encrypt.utils.sm2;
import cn.test.encrypt.utils.Util;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;
import java.math.BigInteger;
public class Cipher {
private int ct;
private ECPoint p2;
private SM3Digest sm3keybase;
private SM3Digest sm3c3;
private byte key[];
private byte keyOff;
public Cipher()
{
this.ct = 1;
this.key = new byte[32];
this.keyOff = 0;
}
private void Reset()
{
this.sm3keybase = new SM3Digest();
this.sm3c3 = new SM3Digest();
byte p[] = Util.byteConvert32Bytes(p2.getX().toBigInteger());
this.sm3keybase.update(p, 0, p.length);
this.sm3c3.update(p, 0, p.length);
p = Util.byteConvert32Bytes(p2.getY().toBigInteger());
this.sm3keybase.update(p, 0, p.length);
this.ct = 1;
NextKey();
}
private void NextKey()
{
SM3Digest sm3keycur = new SM3Digest(this.sm3keybase);
sm3keycur.update((byte) (ct >> 24 & 0xff));
sm3keycur.update((byte) (ct >> 16 & 0xff));
sm3keycur.update((byte) (ct >> 8 & 0xff));
sm3keycur.update((byte) (ct & 0xff));
sm3keycur.doFinal(key, 0);
this.keyOff = 0;
this.ct++;
}
public ECPoint Init_enc(SM2 sm2, ECPoint userKey)
{
AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
BigInteger k = ecpriv.getD();
ECPoint c1 = ecpub.getQ();
this.p2 = userKey.multiply(k);
Reset();
return c1;
}
public void Encrypt(byte data[])
{
this.sm3c3.update(data, 0, data.length);
for (int i = 0; i < data.length; i++)
{
if (keyOff == key.length)
{
NextKey();
}
data[i] ^= key[keyOff++];
}
}
public void Init_dec(BigInteger userD, ECPoint c1)
{
this.p2 = c1.multiply(userD);
Reset();
}
public void Decrypt(byte data[])
{
for (int i = 0; i < data.length; i++)
{
if (keyOff == key.length)
{
NextKey();
}
data[i] ^= key[keyOff++];
}
this.sm3c3.update(data, 0, data.length);
}
public void Dofinal(byte c3[])
{
byte p[] = Util.byteConvert32Bytes(p2.getY().toBigInteger());
this.sm3c3.update(p, 0, p.length);
this.sm3c3.doFinal(c3, 0);
Reset();
}
}
package cn.test.encrypt.utils.sm2;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECFieldElement.Fp;
import org.bouncycastle.math.ec.ECPoint;
import java.math.BigInteger;
import java.security.SecureRandom;
public class SM2 {
//国密参数
public static String[] ecc_param = {
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",
"28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",
"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",
"BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"
};
public static SM2 Instance()
{
return new SM2();
}
public final BigInteger ecc_p;
public final BigInteger ecc_a;
public final BigInteger ecc_b;
public final BigInteger ecc_n;
public final BigInteger ecc_gx;
public final BigInteger ecc_gy;
public final ECCurve ecc_curve;
public final ECPoint ecc_point_g;
public final ECDomainParameters ecc_bc_spec;
public final ECKeyPairGenerator ecc_key_pair_generator;
public final ECFieldElement ecc_gx_fieldelement;
public final ECFieldElement ecc_gy_fieldelement;
public SM2()
{
this.ecc_p = new BigInteger(ecc_param[0], 16);
this.ecc_a = new BigInteger(ecc_param[1], 16);
this.ecc_b = new BigInteger(ecc_param[2], 16);
this.ecc_n = new BigInteger(ecc_param[3], 16);
this.ecc_gx = new BigInteger(ecc_param[4], 16);
this.ecc_gy = new BigInteger(ecc_param[5], 16);
this.ecc_gx_fieldelement = new Fp(this.ecc_p, this.ecc_gx);
this.ecc_gy_fieldelement = new Fp(this.ecc_p, this.ecc_gy);
this.ecc_curve = new ECCurve.Fp(this.ecc_p, this.ecc_a, this.ecc_b);
this.ecc_point_g = new ECPoint.Fp(this.ecc_curve, this.ecc_gx_fieldelement, this.ecc_gy_fieldelement);
this.ecc_bc_spec = new ECDomainParameters(this.ecc_curve, this.ecc_point_g, this.ecc_n);
ECKeyGenerationParameters ecc_ecgenparam;
ecc_ecgenparam = new ECKeyGenerationParameters(this.ecc_bc_spec, new SecureRandom());
this.ecc_key_pair_generator = new ECKeyPairGenerator();
this.ecc_key_pair_generator.init(ecc_ecgenparam);
}
}
生成随机秘钥工具类
package cn.test.encrypt.utils.sm2;
import cn.test.encrypt.utils.Util;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;
import java.io.IOException;
import java.math.BigInteger;
public class SM2EncDecUtils {
//生成随机秘钥对
public static SM2KeyVO generateKeyPair(){
SM2 sm2 = SM2.Instance();
AsymmetricCipherKeyPair key = null;
while (true){
key=sm2.ecc_key_pair_generator.generateKeyPair();
if(((ECPrivateKeyParameters) key.getPrivate()).getD().toByteArray().length==32){
break;
}
}
ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();

本文详细介绍了国密算法中的SM2算法,包括SM2的非对称加密、摘要、密钥生成等,并提供了Java实现的代码示例。文章从SM2算法的基本概念出发,逐步解析了如何生成公私钥,以及如何进行数据的加密和解密操作。此外,还展示了如何利用工具类进行辅助操作,如数据转换和加密过程。

2万+

被折叠的 条评论
为什么被折叠?



