JAVA实现 SM2 解密
- 1、引入Maven库
- 2、密码工具类
- 3、安全工具类
- 4.SM2工具类
- 5、Utils类
SM2Utils里面标注了,需要改成自己的密钥,记得修改,测试方法在SM2Utils里面。
1、引入Maven库
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.54</version>
</dependency>
2、密码工具类
package com.ruoyi.web.controller.tool.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(this.p2.getX().toBigInteger());
this.sm3keybase.update(p, 0, p.length);
this.sm3c3.update(p, 0, p.length);
p = Util.byteConvert32Bytes(this.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)(this.ct >> 24 & 0xFF));
sm3keycur.update((byte)(this.ct >> 16 & 0xFF));
sm3keycur.update((byte)(this.ct >> 8 & 0xFF));
sm3keycur.update((byte)(this.ct & 0xFF));
sm3keycur.doFinal(this.key, 0);
this.keyOff = 0;
this.ct += 1;
}
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 (this.keyOff == this.key.length)
NextKey();
int tmp37_36 = i;
byte[] tmp37_35 = data;
Cipher tmp44_43 = this;
byte tmp48_45 = tmp44_43.keyOff; tmp44_43.keyOff = (byte)(tmp48_45 + 1); tmp37_35[tmp37_36] = (byte)(tmp37_35[tmp37_36] ^ this.key[tmp48_45]);
}
}
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 (this.keyOff == this.key.length)
NextKey();
int tmp26_25 = i;
byte[] tmp26_24 = data;
Cipher tmp33_32 = this;
byte tmp37_34 = tmp33_32.keyOff; tmp33_32.keyOff = (byte)(tmp37_34 + 1); tmp26_24[tmp26_25] = (byte)(tmp26_24[tmp26_25] ^ this.key[tmp37_34]);
}
this.sm3c3.update(data, 0, data.length);
}
public void Dofinal(byte[] c3) {
byte[] p = Util.byteConvert32Bytes(this.p2.getY().toBigInteger());
this.sm3c3.update(p, 0, p.length);
this.sm3c3.doFinal(c3, 0);
Reset();
}
}
3、安全工具类
package com.ruoyi.web.controller.tool.util;
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.ECCurve.Fp;
import org.bouncycastle.math.ec.ECFieldElement;
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 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 static SM2 Instance()
{
return new SM2();
}
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 ECFieldElement.Fp(this.ecc_p, this.ecc_gx);
this.ecc_gy_fieldelement = new ECFieldElement.Fp(this.ecc_p, this.ecc_gy);
this.ecc_curve = new 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 = new ECKeyGenerationParameters(this.ecc_bc_spec, new SecureRandom());
this.ecc_key_pair_generator = new ECKeyPairGenerator();
this.ecc_key_pair_generator.init(ecc_ecgenparam);
}
}
4.SM2工具类
将下面的密钥改成自己的
package com.ruoyi.web.controller.tool.util;
import org.bouncycastle.math.ec.ECPoint;
import java.io.IOException;
import java.math.BigInteger;
public class SM2Utils
{
public static byte[] decrypt(String data0)
{
try
{
byte[] encryptedData = Util.hexToByte(data0);
if ((encryptedData == null) || (encryptedData.length == 0)) {
return null;
}
String data = Util.byteToHex(encryptedData);
byte[] c1Bytes = Util.hexToByte(data.substring(0, 130));
int c2Len = encryptedData.length - 97;
byte[] c2 = Util.hexToByte(data.substring(130, 130 + 2 * c2Len));
byte[] c3 = Util.hexToByte(data.substring(130 + 2 * c2Len, 194 + 2 * c2Len));
SM2 sm2 = new SM2();
//TODO 改自己的密钥
BigInteger userD = new BigInteger(1, Util.hexToByte("自己的密钥"));
ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);
Cipher cipher = new Cipher();
cipher.Init_dec(userD, c1);
cipher.Decrypt(c2);
cipher.Dofinal(c3);
return c2;
} catch (Exception e) {
e.printStackTrace();
System.out.print("时间:" + System.currentTimeMillis() + "解密失败:" + e.getMessage()); }
return null;
}
public static void main(String[] args)
throws IOException
{
byte[] decrypt = decrypt("加密信息");
String newInfo = new String(decrypt, "utf-8");
System.out.println("解密后信息:" + newInfo);
}
}
5、Utils类
package com.ruoyi.web.controller.tool.util;
import java.math.BigInteger;
public class Util
{
private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
public static byte[] intToBytes(int num)
{
byte[] bytes = new byte[4];
bytes[0] = (byte)(0xFF & num >> 0);
bytes[1] = (byte)(0xFF & num >> 8);
bytes[2] = (byte)(0xFF & num >> 16);
bytes[3] = (byte)(0xFF & num >> 24);
return bytes;
}
public static int byteToInt(byte[] bytes)
{
int num = 0;
int temp = (0xFF & bytes[0]) << 0;
num |= temp;
temp = (0xFF & bytes[1]) << 8;
num |= temp;
temp = (0xFF & bytes[2]) << 16;
num |= temp;
temp = (0xFF & bytes[3]) << 24;
num |= temp;
return num;
}
public static byte[] longToBytes(long num)
{
byte[] bytes = new byte[8];
for (int i = 0; i < 8; ++i) {
bytes[i] = (byte)(int)(0xFF & num >> i * 8);
}
return bytes;
}
public static byte[] byteConvert32Bytes(BigInteger n)
{
byte[] tmpd = (byte[])null;
if (n == null) {
return null;
}
if (n.toByteArray().length == 33) {
tmpd = new byte[32];
System.arraycopy(n.toByteArray(), 1, tmpd, 0, 32);
}
else if (n.toByteArray().length == 32) {
tmpd = n.toByteArray();
}
else {
tmpd = new byte[32];
for (int i = 0; i < 32 - n.toByteArray().length; ++i) {
tmpd[i] = 0;
}
System.arraycopy(n.toByteArray(), 0, tmpd, 32 - n.toByteArray().length, n.toByteArray().length);
}
return tmpd;
}
public static BigInteger byteConvertInteger(byte[] b)
{
if (b[0] < 0) {
byte[] temp = new byte[b.length + 1];
temp[0] = 0;
System.arraycopy(b, 0, temp, 1, b.length);
return new BigInteger(temp);
}
return new BigInteger(b);
}
public static String getHexString(byte[] bytes)
{
return getHexString(bytes, true);
}
public static String getHexString(byte[] bytes, boolean upperCase)
{
String ret = "";
for (int i = 0; i < bytes.length; ++i) {
ret = ret + Integer.toString((bytes[i] & 0xFF) + 256, 16).substring(1);
}
return ((upperCase) ? ret.toUpperCase() : ret);
}
public static void printHexString(byte[] bytes)
{
for (int i = 0; i < bytes.length; ++i) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
System.out.print("0x" + hex.toUpperCase() + ",");
}
System.out.println("");
}
public static byte[] hexStringToBytes(String hexString)
{
if ((hexString == null) || (hexString.equals(""))) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; ++i) {
int pos = i * 2;
d[i] = (byte)(charToByte(hexChars[pos]) << 4 | charToByte(hexChars[(pos + 1)]));
}
return d;
}
public static byte charToByte(char c)
{
return (byte)"0123456789ABCDEF".indexOf(c);
}
public static char[] encodeHex(byte[] data)
{
return encodeHex(data, true);
}
public static char[] encodeHex(byte[] data, boolean toLowerCase)
{
return encodeHex(data, (toLowerCase) ? DIGITS_LOWER : DIGITS_UPPER);
}
protected static char[] encodeHex(byte[] data, char[] toDigits)
{
int l = data.length;
char[] out = new char[l << 1];
int i = 0; for (int j = 0; i < l; ++i) {
out[(j++)] = toDigits[((0xF0 & data[i]) >>> 4)];
out[(j++)] = toDigits[(0xF & data[i])];
}
return out;
}
public static String encodeHexString(byte[] data)
{
return encodeHexString(data, true);
}
public static String encodeHexString(byte[] data, boolean toLowerCase)
{
return encodeHexString(data, (toLowerCase) ? DIGITS_LOWER : DIGITS_UPPER);
}
protected static String encodeHexString(byte[] data, char[] toDigits)
{
return new String(encodeHex(data, toDigits));
}
public static byte[] decodeHex(char[] data)
{
int len = data.length;
if ((len & 0x1) != 0) {
throw new RuntimeException("Odd number of characters.");
}
byte[] out = new byte[len >> 1];
int i = 0; for (int j = 0; j < len; ++i) {
int f = toDigit(data[j], j) << 4;
++j;
f |= toDigit(data[j], j);
++j;
out[i] = (byte)(f & 0xFF);
}
return out;
}
protected static int toDigit(char ch, int index)
{
int digit = Character.digit(ch, 16);
if (digit == -1) {
throw new RuntimeException("Illegal hexadecimal character "