java SM2解密

时间:2024-10-06 07:28:20

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 "