| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- package com.ydtech.utils;
- import org.bouncycastle.crypto.params.ECDomainParameters;
- import org.bouncycastle.math.ec.ECCurve;
- import org.bouncycastle.math.ec.ECPoint;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.io.UnsupportedEncodingException;
- import java.math.BigInteger;
- import java.security.SecureRandom;
- import java.util.Arrays;
- public class SM2 {
- private final static Logger LOGGER = LoggerFactory.getLogger(SM2.class);
- public static String sm2Encrypt(String plainText, String pubKey) {
- byte[] data = SM2.encrypt(plainText, pubKey);
- String enData = Base64.encode(data);
- return enData;
- }
- public static String sm2Decrypt(String plainText, String priKey) {
- byte[] encryptData = Base64.decode(plainText);
- String rawData = SM2.decrypt(encryptData, priKey);
- return rawData;
- }
- //国密办文件中推荐的椭圆曲线相关参数
- private static BigInteger n = new BigInteger(
- "FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "7203DF6B" + "21C6052B" + "53BBF409" + "39D54123", 16);
- private static BigInteger p = new BigInteger(
- "FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "00000000" + "FFFFFFFF" + "FFFFFFFF", 16);
- private static BigInteger a = new BigInteger(
- "FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "00000000" + "FFFFFFFF" + "FFFFFFFC", 16);
- private static BigInteger b = new BigInteger(
- "28E9FA9E" + "9D9F5E34" + "4D5A9E4B" + "CF6509A7" + "F39789F5" + "15AB8F92" + "DDBCBD41" + "4D940E93", 16);
- private static BigInteger gx = new BigInteger(
- "32C4AE2C" + "1F198119" + "5F990446" + "6A39C994" + "8FE30BBF" + "F2660BE1" + "715A4589" + "334C74C7", 16);
- private static BigInteger gy = new BigInteger(
- "BC3736A2" + "F4F6779C" + "59BDCEE3" + "6B692153" + "D0A9877C" + "C62A4740" + "02DF32E5" + "2139F0A0", 16);
- private static final int DIGEST_LENGTH = 32;
- private static SecureRandom random = new SecureRandom();
- private static ECCurve.Fp curve = new ECCurve.Fp(p, a, b);
- private static ECPoint G = curve.createPoint(gx, gy);
- private static ECDomainParameters ecc_bc_spec = new ECDomainParameters(curve, G, n);
- /**
- * 以16进制打印字节数组
- *
- * @param b
- */
- public static void printHexString(byte[] b) {
- for (int i = 0; i < b.length; i++) {
- String hex = Integer.toHexString(b[i] & 0xFF);
- if (hex.length() == 1) {
- hex = '0' + hex;
- }
- System.out.print(hex.toUpperCase());
- }
- System.out.println();
- }
- /**
- * 随机数生成器
- *
- * @param max
- * @return
- */
- private static BigInteger random(BigInteger max) {
- BigInteger r = new BigInteger(256, random);
- while (r.compareTo(max) >= 0) {
- r = new BigInteger(128, random);
- }
- return r;
- }
- /**
- * 判断字节数组是否全0
- *
- * @param buffer
- * @return
- */
- private static boolean allZero(byte[] buffer) {
- for (int i = 0; i < buffer.length; i++) {
- if (buffer[i] != 0) {
- return false;
- }
- }
- return true;
- }
- /**
- * 公钥加密
- *
- * @param input 加密原文
- * @param pubKeyStr 公钥
- * @return
- */
- public static byte[] encrypt(String input, String pubKeyStr) {
- ECPoint publicKey = curve.decodePoint(hexStr2Bytes(pubKeyStr));
- byte[] inputBuffer = new byte[0];
- try {
- inputBuffer = input.getBytes("UTF8");
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- byte[] C1Buffer;
- ECPoint kpb;
- byte[] t;
- do {
- /* 1 产生随机数k,k属于[1, n-1] */
- BigInteger k = random(n);
- /* 2 计算椭圆曲线点C1 = [k]G = (x1, y1) */
- ECPoint C1 = G.multiply(k);
- C1Buffer = C1.getEncoded(false);
- /*
- * 3 计算椭圆曲线点 S = [h]Pb
- */
- BigInteger h = ecc_bc_spec.getH();
- if (h != null) {
- ECPoint S = publicKey.multiply(h);
- if (S.isInfinity()) {
- throw new IllegalStateException();
- }
- }
- /* 4 计算 [k]PB = (x2, y2) */
- kpb = publicKey.multiply(k).normalize();
- /* 5 计算 t = KDF(x2||y2, klen) */
- byte[] kpbBytes = kpb.getEncoded(false);
- t = KDF(kpbBytes, inputBuffer.length);
- } while (allZero(t));
- /* 6 计算C2=M^t */
- byte[] C2 = new byte[inputBuffer.length];
- for (int i = 0; i < inputBuffer.length; i++) {
- C2[i] = (byte) (inputBuffer[i] ^ t[i]);
- }
- /* 7 计算C3 = Hash(x2 || M || y2) */
- byte[] C3 = sm3hash(kpb.getXCoord().toBigInteger().toByteArray(), inputBuffer,
- kpb.getYCoord().toBigInteger().toByteArray());
- /* 8 输出密文 C=C1 || C2 || C3 */
- byte[] encryptResult = new byte[C1Buffer.length + C2.length + C3.length];
- System.arraycopy(C1Buffer, 0, encryptResult, 0, C1Buffer.length);
- System.arraycopy(C2, 0, encryptResult, C1Buffer.length, C2.length);
- System.arraycopy(C3, 0, encryptResult, C1Buffer.length + C2.length, C3.length);
- return encryptResult;
- }
- /**
- * 私钥解密
- *
- * @param encryptData 密文数据字节数组
- * @param priKeyStr 解密私钥
- * @return
- */
- public static String decrypt(byte[] encryptData, String priKeyStr) {
- BigInteger privateKey = new BigInteger(priKeyStr, 16);
- byte[] C1Byte = new byte[65];
- System.arraycopy(encryptData, 0, C1Byte, 0, C1Byte.length);
- ECPoint C1 = curve.decodePoint(C1Byte).normalize();
- /*
- * 计算椭圆曲线点 S = [h]C1 是否为无穷点
- */
- BigInteger h = ecc_bc_spec.getH();
- if (h != null) {
- ECPoint S = C1.multiply(h);
- if (S.isInfinity()) {
- throw new IllegalStateException();
- }
- }
- /* 计算[dB]C1 = (x2, y2) */
- ECPoint dBC1 = C1.multiply(privateKey).normalize();
- /* 计算t = KDF(x2 || y2, klen) */
- byte[] dBC1Bytes = dBC1.getEncoded(false);
- int klen = encryptData.length - 65 - DIGEST_LENGTH;
- byte[] t = KDF(dBC1Bytes, klen);
- if (allZero(t)) {
- System.err.println("all zero");
- throw new IllegalStateException();
- }
- /* 计算M'=C2^t */
- byte[] M = new byte[klen];
- for (int i = 0; i < M.length; i++) {
- M[i] = (byte) (encryptData[C1Byte.length + i] ^ t[i]);
- }
- /* 计算 u = Hash(x2 || M' || y2) 判断 u == C3是否成立 */
- byte[] C3 = new byte[DIGEST_LENGTH];
- System.arraycopy(encryptData, encryptData.length - DIGEST_LENGTH, C3, 0, DIGEST_LENGTH);
- byte[] u = sm3hash(dBC1.getXCoord().toBigInteger().toByteArray(), M,
- dBC1.getYCoord().toBigInteger().toByteArray());
- if (Arrays.equals(u, C3)) {
- try {
- return new String(M, "UTF8");
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- return null;
- } else {
- return null;
- }
- }
- /**
- * 判断是否在范围内
- *
- * @param param
- * @param min
- * @param max
- * @return
- */
- private static boolean between(BigInteger param, BigInteger min, BigInteger max) {
- if (param.compareTo(min) >= 0 && param.compareTo(max) < 0) {
- return true;
- } else {
- return false;
- }
- }
- /**
- * 判断生成的公钥是否合法
- *
- * @param publicKey
- * @return
- */
- private static boolean checkPublicKey(ECPoint publicKey) {
- if (!publicKey.isInfinity()) {
- BigInteger x = publicKey.getXCoord().toBigInteger();
- BigInteger y = publicKey.getYCoord().toBigInteger();
- if (between(x, new BigInteger("0"), p) && between(y, new BigInteger("0"), p)) {
- BigInteger xResult = x.pow(3).add(a.multiply(x)).add(b).mod(p);
- BigInteger yResult = y.pow(2).mod(p);
- if (yResult.equals(xResult) && publicKey.multiply(n).isInfinity()) {
- return true;
- }
- }
- }
- return false;
- }
- /**
- * 字节数组拼接
- *
- * @param params
- * @return
- */
- private static byte[] join(byte[]... params) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- byte[] res = null;
- try {
- for (int i = 0; i < params.length; i++) {
- baos.write(params[i]);
- }
- res = baos.toByteArray();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return res;
- }
- /**
- * sm3摘要
- * @param params
- * @return
- */
- private static byte[] sm3hash(byte[]... params) {
- byte[] res = null;
- try {
- res = SM3.hash(join(params));
- } catch (IOException e) {
- e.printStackTrace();
- }
- return res;
- }
- /**
- * 密钥派生函数
- * @param Z
- * @param klen 生成klen字节数长度的密钥
- * @return
- */
- private static byte[] KDF(byte[] Z, int klen) {
- int ct = 1;
- int end = (int) Math.ceil(klen * 1.0 / 32);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- for (int i = 1; i < end; i++) {
- baos.write(sm3hash(Z, SM3.toByteArray(ct)));
- ct++;
- }
- byte[] last = sm3hash(Z, SM3.toByteArray(ct));
- if (klen % 32 == 0) {
- baos.write(last);
- } else {
- baos.write(last, 0, klen % 32);
- }
- return baos.toByteArray();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
- public static byte[] hexStr2Bytes(String src) {
- int l = src.length() / 2;
- byte[] ret = new byte[l];
- for (int i = 0; i < l; ++i) {
- int m = i * 2 + 1;
- int n = m + 1;
- ret[i] = uniteBytes(src.substring(i * 2, m), src.substring(m, n));
- }
- return ret;
- }
- private static byte uniteBytes(String src0, String src1) {
- byte b0 = Byte.decode("0x" + src0);
- b0 = (byte) (b0 << 4);
- byte b1 = Byte.decode("0x" + src1);
- byte ret = (byte) (b0 | b1);
- return ret;
- }
- }
|