|
@@ -0,0 +1,262 @@
|
|
|
+package com.usky.fire.service.util;
|
|
|
+
|
|
|
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
|
|
+import org.bouncycastle.crypto.digests.SM3Digest;
|
|
|
+import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
|
|
|
+import org.bouncycastle.crypto.params.ECDomainParameters;
|
|
|
+import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
|
|
|
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
|
|
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
|
|
+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.io.IOException;
|
|
|
+import java.math.BigInteger;
|
|
|
+import java.security.SecureRandom;
|
|
|
+
|
|
|
+public class SM2 {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 国密参数
|
|
|
+ */
|
|
|
+ private static String[] ecc_param = {
|
|
|
+ "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",
|
|
|
+ "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",
|
|
|
+ "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",
|
|
|
+ "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",
|
|
|
+ "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",
|
|
|
+ "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"
|
|
|
+ };
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 公钥
|
|
|
+ */
|
|
|
+ private static final String publicKey = "04dca32e6ddf8d378222ee5debfdcbf5d3e436540fb4d411c813ec0b7f1ede1d243cf6486487731561ed4e88947b3e94e95ae5c30dd5b3cc848404cc2f8cb4f683";
|
|
|
+
|
|
|
+ private final BigInteger ecc_p;
|
|
|
+
|
|
|
+ private final BigInteger ecc_a;
|
|
|
+
|
|
|
+ private final BigInteger ecc_b;
|
|
|
+
|
|
|
+ private final BigInteger ecc_n;
|
|
|
+
|
|
|
+ private final BigInteger ecc_gx;
|
|
|
+
|
|
|
+ private final BigInteger ecc_gy;
|
|
|
+
|
|
|
+ private final ECCurve ecc_curve;
|
|
|
+
|
|
|
+ private final ECPoint ecc_point_g;
|
|
|
+
|
|
|
+ private final ECDomainParameters ecc_bc_spec;
|
|
|
+
|
|
|
+ private final ECKeyPairGenerator ecc_key_pair_generator;
|
|
|
+
|
|
|
+ private final ECFieldElement ecc_gx_fieldelement;
|
|
|
+
|
|
|
+ private final ECFieldElement ecc_gy_fieldelement;
|
|
|
+
|
|
|
+ private static int ct = 1;
|
|
|
+
|
|
|
+ private static ECPoint p2;
|
|
|
+
|
|
|
+ private static SM3Digest sm3keybase;
|
|
|
+
|
|
|
+ private static SM3Digest sm3c3;
|
|
|
+
|
|
|
+ private static byte key[] = new byte[32];
|
|
|
+
|
|
|
+ private static byte keyOff = 0;
|
|
|
+
|
|
|
+ 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 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);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 数据加密
|
|
|
+ *
|
|
|
+ * @param data
|
|
|
+ * @return
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ public static String encrypt(byte[] data) throws IOException {
|
|
|
+
|
|
|
+ if (data == null || data.length == 0) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ byte[] source = new byte[data.length];
|
|
|
+ System.arraycopy(data, 0, source, 0, data.length);
|
|
|
+
|
|
|
+ SM2 sm2 = SM2.Instance();
|
|
|
+ ECPoint userKey = sm2.ecc_curve.decodePoint(hexToByte(publicKey));
|
|
|
+
|
|
|
+ ECPoint c1 = Init_enc(sm2, userKey);
|
|
|
+ Encrypt(source);
|
|
|
+ byte[] c3 = new byte[32];
|
|
|
+ Dofinal(c3);
|
|
|
+
|
|
|
+ return byteToHex(c1.getEncoded()) + byteToHex(c3) + byteToHex(source);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void Reset() {
|
|
|
+ sm3keybase = new SM3Digest();
|
|
|
+ sm3c3 = new SM3Digest();
|
|
|
+
|
|
|
+ byte p[] = byteConvert32Bytes(p2.getX().toBigInteger());
|
|
|
+ sm3keybase.update(p, 0, p.length);
|
|
|
+ sm3c3.update(p, 0, p.length);
|
|
|
+
|
|
|
+ p = byteConvert32Bytes(p2.getY().toBigInteger());
|
|
|
+ sm3keybase.update(p, 0, p.length);
|
|
|
+ ct = 1;
|
|
|
+ NextKey();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void NextKey() {
|
|
|
+ SM3Digest sm3keycur = new SM3Digest(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);
|
|
|
+ keyOff = 0;
|
|
|
+ ct++;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static 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();
|
|
|
+ p2 = userKey.multiply(k);
|
|
|
+ Reset();
|
|
|
+ return c1;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void Encrypt(byte data[]) {
|
|
|
+ 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 static void Dofinal(byte c3[]) {
|
|
|
+ byte p[] = byteConvert32Bytes(p2.getY().toBigInteger());
|
|
|
+ sm3c3.update(p, 0, p.length);
|
|
|
+ sm3c3.doFinal(c3, 0);
|
|
|
+ Reset();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 大数字转换字节流(字节数组)型数据
|
|
|
+ *
|
|
|
+ * @param n
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 十六进制串转化为byte数组
|
|
|
+ *
|
|
|
+ * @return the array of byte
|
|
|
+ */
|
|
|
+ public static byte[] hexToByte(String hex) throws IllegalArgumentException {
|
|
|
+ if (hex.length() % 2 != 0) {
|
|
|
+ throw new IllegalArgumentException();
|
|
|
+ }
|
|
|
+ char[] arr = hex.toCharArray();
|
|
|
+ byte[] b = new byte[hex.length() / 2];
|
|
|
+ for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {
|
|
|
+ String swap = "" + arr[i++] + arr[i];
|
|
|
+ int byteint = Integer.parseInt(swap, 16) & 0xFF;
|
|
|
+ b[j] = new Integer(byteint).byteValue();
|
|
|
+ }
|
|
|
+ return b;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 字节数组转换为十六进制字符串
|
|
|
+ *
|
|
|
+ * @param b byte[] 需要转换的字节数组
|
|
|
+ * @return String 十六进制字符串
|
|
|
+ */
|
|
|
+ public static String byteToHex(byte b[]) {
|
|
|
+ if (b == null) {
|
|
|
+ throw new IllegalArgumentException("Argument b ( byte array ) is null! ");
|
|
|
+ }
|
|
|
+ String hs = "";
|
|
|
+ String stmp = "";
|
|
|
+ for (int n = 0; n < b.length; n++) {
|
|
|
+ stmp = Integer.toHexString(b[n] & 0xff);
|
|
|
+ if (stmp.length() == 1) {
|
|
|
+ hs = hs + "0" + stmp;
|
|
|
+ } else {
|
|
|
+ hs = hs + stmp;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return hs.toLowerCase();
|
|
|
+ }
|
|
|
+
|
|
|
+}
|