精华内容
下载资源
问答
  • java国密算法实现

    2019-01-07 17:32:40
    java 国密算法sm2、sm3 详细使用参考:https://blog.csdn.net/weixin_30512027/article/details/86013878
  • 使用最新的openssl1.1.1h、curl-7.74.0、vs2010编译的libcurl.dll,编译后的curl.exe已经测试过了可以打开https网站,指令:curl.exe https://mail.qq.com -k
  • java调用Gmssl中国密接口进行对称与非对称加解密等运算,动态so库进行接口jni方式调用,采取接口形式对外暴露,方便对接系统调用相关java接口进行相关运算操作。
  • 2、fabric国密改造中使用(主要是为了匹配其他语言库例如:java,js等库) 主要功能 GMSM包含以下主要功能 SM2: 国密椭圆曲线算法库 . 支持Generate Key, Sign, Verify基础操作 . 支持加密和不加密的pem文件格式...
  • SM2国密算法JAVA版,其中包含了加密和解密。附使用教程;代码经过本人测试通过。另:可与C#版SM2加解密互通 C#地址:https://download.csdn.net/download/qq137669431/11157399
  • 国密SSL系列之Java编程

    千次阅读 2020-08-24 13:19:24
    Java自身通过JCE和JSSE支持标准的SSL协议,但并不支持国密SSL协议。本文描述了Java使用国密JCE和国密JSSE开发一个简单的客户端程序,连接国密Web网站,发送HTTP请求,并接收HTTP应答。 2 环境 JRE是jre8。 国密...

    1 背景

         Java自身通过JCE和JSSE支持标准的SSL协议,但并不支持国密SSL协议。本文描述了Java使用国密JCE和国密JSSE开发一个简单的客户端程序,连接国密Web网站,发送HTTP请求,并接收HTTP应答。

    2 环境

    JRE是jre8。

    国密JCE和国密JSSE。下载参https://www.gmssl.cn/gmssl/index.jsp?go=gmsdk

    gmjce.jar和gmjsse.jar放到jre的lib/ext/目录下

    3 源码

    package cn.gmssl.test;

     

    import java.net.*;

    import java.io.*;

    import java.security.*;

    import java.security.cert.*;

     

    import javax.net.*;

    import javax.net.ssl.*;

     

    public class SocketGet

    {

        public static void main(String[] args)

        {

            SocketFactory fact = null;

            SSLSocket socket = null;

           

            String addr"ebssec.boc.cn";

            int port = 443;

            String uri = "/";

     

            try

            {

                if(args.length > 0)

                {

                   addr = args[0];

                   port = Integer.parseInt(args[1]);

                   uri = args[2];

                }

               

                System.out.println("\r\naddr="+addr);

                System.out.println("port="+port);

                System.out.println("uri="+uri);

               

                // 加载国密提供者

               Security.insertProviderAt(new cn.gmssl.jce.provider.GMJCE(), 1);

               Security.insertProviderAt(new cn.gmssl.jsse.provider.GMJSSE(), 2);

     

               fact = createSocketFactory(null, null);

                socket = (SSLSocket)fact.createSocket();

                socket.setTcpNoDelay(true);

     

                System.out.println("\r\nGM SSL connecting...");

                socket.connect(new InetSocketAddress(addr, port), 5000);

                socket.setTcpNoDelay(true);

                socket.startHandshake();

     

                System.out.println("Connected!\n");

     

                DataInputStream in = new DataInputStream(socket.getInputStream());

                OutputStream out = socket.getOutputStream();

               

                String s = "GET " + uri + " HTTP/1.1\r\n";

                s+= "Accept: */*\r\n";

                s+= "User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)\r\n";

                s+= "Host: " + addr + (port == 443 ? "" : ":"+port) + "\r\n";

                s+= "Connection: Close\r\n";

                s+= "\r\n";

                out.write(s.getBytes());

                out.flush();

     

                // 读取HTTP

                while(true)

                {

                   byte[] lineBuffer = ReadLine.read(in);

                   if ( lineBuffer == null || lineBuffer.length == 0)

                   {

                       System.out.println();

                       break;

                   }

                   String line = new String(lineBuffer);

                   System.out.println(line);

                }

     

               // 读取HTTP内容

               {

                    byte[] buf = new byte[1024];

                    while(true)

                    {

                         int len = in.read(buf);

                         if(len == -1)

                         {

                            break;

                         }

                        System.out.println(new String(buf,  0,  len));

                    }

               }

     

                in.close();

                out.close();

            }

            catch(Exception e)

            {

                e.printStackTrace();

            }

            finally

            {

                try

                {

                    socket.close();

                }

                catch(Exception e)

                {}

            }

        }

     

        private static SSLSocketFactory createSocketFactory(KeyStore kepair, char[] pwd) throws Exception

       {

            X509TrustManager[] trust = { new MyTrustAllManager() };

     

            KeyManager[] kms = null;

            if (kepair != null)

            {

               KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");

               kmf.init(kepair, pwd);

               kms = kmf.getKeyManagers();

            }

     

            // 使用国密SSL

            SSLContext ctx = SSLContext.getInstance(cn.gmssl.jsse.provider.GMJSSE.GMSSLv11, cn.gmssl.jsse.provider.GMJSSE.NAME);

     

            java.security.SecureRandom secureRandom = new java.security.SecureRandom();

            ctx.init(kms, trust, secureRandom);

           

            SSLSocketFactory factory = ctx.getSocketFactory();

            return factory;

       }

    }

     

    class MyTrustAllManager implements X509TrustManager

    {

       private X509Certificate[] issuers;

     

       public MyTrustAllManager()

       {

           this.issuers = new X509Certificate[0];

       }

     

       public X509Certificate[] getAcceptedIssuers()

       {

           return issuers ;

       }

     

       public void checkClientTrusted(X509Certificate[] chain, String authType)

       {}

     

       public void checkServerTrusted(X509Certificate[] chain, String authType)

       {}

    }

     

    class ReadLine

    {

        public static final byte[] CRLF = {'\r', '\n'};

        public static final byte CR = '\r';

        public static final byte LF = '\n';

     

        private static final int LINE_MAX_SIZE = 16384;

     

        public static byte[] read(DataInputStream in) throws IOException, SocketException

        {

            ByteArrayOutputStream baosnew ByteArrayOutputStream();

            DataOutputStream s = new DataOutputStream(baos);

            boolean previousIsCR = false;

     

            int len = 0;

            byte b = 0;

     

            try

            {

                b = in.readByte();

                len ++;

            }

            catch(EOFException e)

            {

                return new byte[0];

            }

     

            while(true)

            {

                if(b == LF)

                {

                    if(previousIsCR)

                    {

                        s.flush();

                        byte[] rs = baos.toByteArray();

                        s.close();

                        return rs;

                    }

                    else

                    {

                        s.flush();

                        byte[] rs = baos.toByteArray();

                        s.close();

                        return rs;

                    }

                }

                else if(b == CR)

                {

                    if(previousIsCR)

                    {

                        s.writeByte(CR);

                    }

                    previousIsCR = true;

                }

                else

                {

                    if(previousIsCR)

                    {

                        s.writeByte(CR);

                    }

                    previousIsCR = false;

                    s.write(b);

                }

     

                if(len > LINE_MAX_SIZE)

                {

                s.close();

                    throw new IOException("Reach line size limit");

                }

     

                try

                {

                    b = in.readByte();

                    len ++;

                }

                catch(EOFException e)

                {

                    s.flush();

                    byte[] rs = baos.toByteArray();

                    s.close();

                    return rs;

                }

            }

        }

    }

    4 注释

    首先要注册国密提供者

        Security.insertProviderAt(new cn.gmssl.jce.provider.GMJCE(), 1);

               Security.insertProviderAt(new cn.gmssl.jsse.provider.GMJSSE(), 2);

    其中要使用国密SSL来连接

            SSLContext ctx = SSLContext.getInstance(cn.gmssl.jsse.provider.GMJSSE.GMSSLv11, cn.gmssl.jsse.provider.GMJSSE.NAME);

    是不是比想象中要简单?

    5 测试运行

    java cn.gmssl.test.SocketGet

     

    addr=ebssec.boc.cn

    port=443

    uri=/

     

    GM SSL connecting...

    Connected!

     

    HTTP/1.1 200 OK

    Date: Mon, 24 Aug 2020 03:45:28 GMT

    Last-Modified: Sat, 27 Jun 2015 16:48:38 GMT

    Accept-Ranges: bytes

    Content-Length: 156

    Cache-Control: max-age=300

    Expires: Mon, 24 Aug 2020 03:50:28 GMT

    Vary: Accept-Encoding,User-Agent

    Connection: close

    Content-Type: text/html

     

    <!DOCTYPE html><html><head><meta http-equiv="refresh" content="0;url=/boc15/login.html"><meta name="renderer" content="ie-stand"></head><body></body></html>

    8 小结

         通过使用国密JCE和国密JSSE,Java很容易编程来使用国密SSL连接国密Web网站。www.gmssl.cn提供了全部免费的测试组件,并且支持双向国密SSL,可供学习和测试。

    展开全文
  • java 国密算法sm2、sm3

    万次阅读 热门讨论 2019-01-07 17:31:56
    国密即国家密码局认定的国产密码算法。主要有SM1,SM2,SM3,SM4。密钥长度和分组长度均为128位。 SM1 为对称加密。其加密强度与AES相当。该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用。 SM2为非...

    国密即国家密码局认定的国产密码算法。主要有SM1,SM2,SM3,SM4。密钥长度和分组长度均为128位。

    SM1 为对称加密。其加密强度与AES相当。该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用。

    SM2为非对称加密,基于ECC。该算法已公开。由于该算法基于ECC,故其签名速度与秘钥生成速度都快于RSA。ECC 256位(SM2采用的就是ECC 256位的一种)安全强度比RSA 2048位高,但运算速度快于RSA。

    SM3 消息摘要。可以用MD5作为对比理解。该算法已公开。校验结果为256位。

    SM4 无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度均为128位。

    由于SM1、SM4加解密的分组大小为128bit,故对消息进行加解密时,若消息长度过长,需要进行分组,要消息长度不足,则要进行填充。

    java代码下载:

    https://download.csdn.net/download/weixin_30512027/10901805

    pom需添加

    <!--国密-->
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>1.56</version>
    </dependency>

    sm2:

    public class SM2 {
    	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 ECDomainParameters ecc_bc_spec;
    	private static int w = (int) Math.ceil(n.bitLength() * 1.0 / 2) - 1;
    	private static BigInteger _2w = new BigInteger("2").pow(w);
    	private static final int DIGEST_LENGTH = 32;
    
    	private static SecureRandom random = new SecureRandom();
    	private static ECCurve.Fp curve;
    	private static ECPoint G;
    	private boolean debug = false;
    
    	public boolean isDebug() {
    		return debug;
    	}
    
    	public void setDebug(boolean debug) {
    		this.debug = debug;
    	}
    
    	/**
    	 * 以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);
    		// int count = 1;
    
    		while (r.compareTo(max) >= 0) {
    			r = new BigInteger(128, random);
    			// count++;
    		}
    
    		// System.out.println("count: " + count);
    		return r;
    	}
    
    	/**
    	 * 判断字节数组是否全0
    	 * 
    	 * @param buffer
    	 * @return
    	 */
    	private boolean allZero(byte[] buffer) {
    		for (int i = 0; i < buffer.length; i++) {
    			if (buffer[i] != 0)
    				return false;
    		}
    		return true;
    	}
    
    	/**
    	 * 公钥加密
    	 * 
    	 * @param input
    	 *            加密原文
    	 * @param publicKey
    	 *            公钥
    	 * @return
    	 */
    	public byte[] encrypt(String input, ECPoint publicKey) {
    
    		byte[] inputBuffer = input.getBytes();
    		if (debug)
    			printHexString(inputBuffer);
    
    		byte[] C1Buffer;
    		ECPoint kpb;
    		byte[] t;
    		do {
    			/* 1 产生随机数k,k属于[1, n-1] */
    			BigInteger k = random(n);
    			if (debug) {
    				System.out.print("k: ");
    				printHexString(k.toByteArray());
    			}
    
    			/* 2 计算椭圆曲线点C1 = [k]G = (x1, y1) */
    			ECPoint C1 = G.multiply(k);
    			C1Buffer = C1.getEncoded(false);
    			if (debug) {
    				System.out.print("C1: ");
    				printHexString(C1Buffer);
    			}
    
    			/*
    			 * 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);
    			// DerivationFunction kdf = new KDF1BytesGenerator(new
    			// ShortenedDigest(new SHA256Digest(), DIGEST_LENGTH));
    			//
    			// t = new byte[inputBuffer.length];
    			// kdf.init(new ISO18033KDFParameters(kpbBytes));
    			// kdf.generateBytes(t, 0, t.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);
    
    		if (debug) {
    			System.out.print("密文: ");
    			printHexString(encryptResult);
    		}
    
    		return encryptResult;
    	}
    
    	/**
    	 * 私钥解密
    	 * 
    	 * @param encryptData
    	 *            密文数据字节数组
    	 * @param privateKey
    	 *            解密私钥
    	 * @return
    	 */
    	public String decrypt(byte[] encryptData, BigInteger privateKey) {
    
    		if (debug)
    			System.out.println("encryptData length: " + encryptData.length);
    
    		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);
    		// DerivationFunction kdf = new KDF1BytesGenerator(new
    		// ShortenedDigest(new SHA256Digest(), DIGEST_LENGTH));
    		// if (debug)
    		// System.out.println("klen = " + klen);
    		// kdf.init(new ISO18033KDFParameters(dBC1Bytes));
    		// kdf.generateBytes(t, 0, t.length);
    
    		if (allZero(t)) {
    			System.err.println("all zero");
    			throw new IllegalStateException();
    		}
    
    		/* 5 计算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]);
    		}
    		if (debug)
    			printHexString(M);
    
    		/* 6 计算 u = Hash(x2 || M' || y2) 判断 u == C3是否成立 */
    		byte[] C3 = new byte[DIGEST_LENGTH];
    
    		if (debug)
    			try {
    				System.out.println("M = " + new String(M, "UTF8"));
    			} catch (UnsupportedEncodingException e1) {
    				// TODO Auto-generated catch block
    				e1.printStackTrace();
    			}
    
    		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)) {
    			if (debug)
    				System.out.println("解密成功");
    			try {
    				return new String(M, "UTF8");
    			} catch (UnsupportedEncodingException e) {
    				e.printStackTrace();
    			}
    			return null;
    		} else {
    			if (debug) {
    				System.out.print("u = ");
    				printHexString(u);
    				System.out.print("C3 = ");
    				printHexString(C3);
    				System.err.println("解密验证失败");
    			}
    			return null;
    		}
    
    	}
    
    	// /**
    	// * SHA摘要
    	// * @param x2
    	// * @param M
    	// * @param y2
    	// * @return
    	// */
    	// private byte[] calculateHash(BigInteger x2, byte[] M, BigInteger y2) {
    	// ShortenedDigest digest = new ShortenedDigest(new SHA256Digest(),
    	// DIGEST_LENGTH);
    	// byte[] buf = x2.toByteArray();
    	// digest.update(buf, 0, buf.length);
    	// digest.update(M, 0, M.length);
    	// buf = y2.toByteArray();
    	// digest.update(buf, 0, buf.length);
    	//
    	// buf = new byte[DIGEST_LENGTH];
    	// digest.doFinal(buf, 0);
    	//
    	// return buf;
    	// }
    
    	/**
    	 * 判断是否在范围内
    	 * 
    	 * @param param
    	 * @param min
    	 * @param max
    	 * @return
    	 */
    	private 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 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);
    
    				if (debug)
    					System.out.println("xResult: " + xResult.toString());
    
    				BigInteger yResult = y.pow(2).mod(p);
    
    				if (debug)
    					System.out.println("yResult: " + yResult.toString());
    
    				if (yResult.equals(xResult) && publicKey.multiply(n).isInfinity()) {
    					return true;
    				}
    			}
    		}
    		return false;
    	}
    
    	/**
    	 * 生成密钥对
    	 * 
    	 * @return
    	 */
    	public SM2KeyPair generateKeyPair() {
    
    		BigInteger d = random(n.subtract(new BigInteger("1")));
    
    		SM2KeyPair keyPair = new SM2KeyPair(G.multiply(d).normalize(), d);
    
    		if (checkPublicKey(keyPair.getPublicKey())) {
    			if (debug)
    				System.out.println("generate key successfully");
    			return keyPair;
    		} else {
    			if (debug)
    				System.err.println("generate key failed");
    			return null;
    		}
    	}
    
    	public SM2() {
    		curve = new ECCurve.Fp(p, // q
    				a, // a
    				b); // b
    		G = curve.createPoint(gx, gy);
    		ecc_bc_spec = new ECDomainParameters(curve, G, n);
    	}
    
    	public SM2(boolean debug) {
    		this();
    		this.debug = debug;
    	}
    
    	/**
    	 * 导出公钥到本地
    	 * 
    	 * @param publicKey
    	 * @param path
    	 */
    	public void exportPublicKey(ECPoint publicKey, String path) {
    		File file = new File(path);
    		try {
    			if (!file.exists())
    				file.createNewFile();
    			byte buffer[] = publicKey.getEncoded(false);
    			FileOutputStream fos = new FileOutputStream(file);
    			fos.write(buffer);
    			fos.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    
    	/**
    	 * 从本地导入公钥
    	 * 
    	 * @param path
    	 * @return
    	 */
    	public ECPoint importPublicKey(String path) {
    		File file = new File(path);
    		try {
    			if (!file.exists())
    				return null;
    			FileInputStream fis = new FileInputStream(file);
    			ByteArrayOutputStream baos = new ByteArrayOutputStream();
    
    			byte buffer[] = new byte[16];
    			int size;
    			while ((size = fis.read(buffer)) != -1) {
    				baos.write(buffer, 0, size);
    			}
    			fis.close();
    			return curve.decodePoint(baos.toByteArray());
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		return null;
    	}
    
    	/**
    	 * 导出私钥到本地
    	 * 
    	 * @param privateKey
    	 * @param path
    	 */
    	public void exportPrivateKey(BigInteger privateKey, String path) {
    		File file = new File(path);
    		try {
    			if (!file.exists())
    				file.createNewFile();
    			ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
    			oos.writeObject(privateKey);
    			oos.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    
    	/**
    	 * 从本地导入私钥
    	 * 
    	 * @param path
    	 * @return
    	 */
    	public BigInteger importPrivateKey(String path) {
    		File file = new File(path);
    		try {
    			if (!file.exists())
    				return null;
    			FileInputStream fis = new FileInputStream(file);
    			ObjectInputStream ois = new ObjectInputStream(fis);
    			BigInteger res = (BigInteger) (ois.readObject());
    			ois.close();
    			fis.close();
    			return res;
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return null;
    	}
    
    	/**
    	 * 字节数组拼接
    	 * 
    	 * @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) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		return res;
    	}
    
    	/**
    	 * 取得用户标识字节数组
    	 * 
    	 * @param IDA
    	 * @param aPublicKey
    	 * @return
    	 */
    	private static byte[] ZA(String IDA, ECPoint aPublicKey) {
    		byte[] idaBytes = IDA.getBytes();
    		int entlenA = idaBytes.length * 8;
    		byte[] ENTLA = new byte[] { (byte) (entlenA & 0xFF00), (byte) (entlenA & 0x00FF) };
    		byte[] ZA = sm3hash(ENTLA, idaBytes, a.toByteArray(), b.toByteArray(), gx.toByteArray(), gy.toByteArray(),
    				aPublicKey.getXCoord().toBigInteger().toByteArray(),
    				aPublicKey.getYCoord().toBigInteger().toByteArray());
    		return ZA;
    	}
    
    	/**
    	 * 签名
    	 * 
    	 * @param M
    	 *            签名信息
    	 * @param IDA
    	 *            签名方唯一标识
    	 * @param keyPair
    	 *            签名方密钥对
    	 * @return 签名
    	 */
    	public Signature sign(String M, String IDA, SM2KeyPair keyPair) {
    		byte[] ZA = ZA(IDA, keyPair.getPublicKey());
    		byte[] M_ = join(ZA, M.getBytes());
    		BigInteger e = new BigInteger(1, sm3hash(M_));
    		// BigInteger k = new BigInteger(
    		// "6CB28D99 385C175C 94F94E93 4817663F C176D925 DD72B727 260DBAAE
    		// 1FB2F96F".replace(" ", ""), 16);
    		BigInteger k;
    		BigInteger r;
    		do {
    			k = random(n);
    			ECPoint p1 = G.multiply(k).normalize();
    			BigInteger x1 = p1.getXCoord().toBigInteger();
    			r = e.add(x1);
    			r = r.mod(n);
    		} while (r.equals(BigInteger.ZERO) || r.add(k).equals(n));
    
    		BigInteger s = ((keyPair.getPrivateKey().add(BigInteger.ONE).modInverse(n))
    				.multiply((k.subtract(r.multiply(keyPair.getPrivateKey()))).mod(n))).mod(n);
    
    		return new Signature(r, s);
    	}
    
    	/**
    	 * 验签
    	 * 
    	 * @param M
    	 *            签名信息
    	 * @param signature
    	 *            签名
    	 * @param IDA
    	 *            签名方唯一标识
    	 * @param aPublicKey
    	 *            签名方公钥
    	 * @return true or false
    	 */
    	public boolean verify(String M, Signature signature, String IDA, ECPoint aPublicKey) {
    		if (!between(signature.r, BigInteger.ONE, n))
    			return false;
    		if (!between(signature.s, BigInteger.ONE, n))
    			return false;
    
    		byte[] M_ = join(ZA(IDA, aPublicKey), M.getBytes());
    		BigInteger e = new BigInteger(1, sm3hash(M_));
    		BigInteger t = signature.r.add(signature.s).mod(n);
    
    		if (t.equals(BigInteger.ZERO))
    			return false;
    
    		ECPoint p1 = G.multiply(signature.s).normalize();
    		ECPoint p2 = aPublicKey.multiply(t).normalize();
    		BigInteger x1 = p1.add(p2).normalize().getXCoord().toBigInteger();
    		BigInteger R = e.add(x1).mod(n);
    		if (R.equals(signature.r))
    			return true;
    		return false;
    	}
    
    	/**
    	 * 密钥派生函数
    	 * 
    	 * @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;
    	}
    
    	/**
    	 * 传输实体类
    	 * 
    	 * @author Potato
    	 *
    	 */
    	private static class TransportEntity implements Serializable {
    		final byte[] R; //R点
    		final byte[] S; //验证S
    		final byte[] Z; //用户标识
    		final byte[] K; //公钥
    
    		public TransportEntity(byte[] r, byte[] s,byte[] z,ECPoint pKey) {
    			R = r;
    			S = s;
    			Z=z;
    			K=pKey.getEncoded(false);
    		}
    	}
    
    	/**
    	 * 密钥协商辅助类
    	 * 
    	 * @author Potato
    	 *
    	 */
    	public static class KeyExchange {
    		BigInteger rA;
    		ECPoint RA;
    		ECPoint V;
    		byte[] Z;
    		byte[] key;
    		
    		String ID;
    		SM2KeyPair keyPair;
    
    		public KeyExchange(String ID,SM2KeyPair keyPair) {
    			this.ID=ID;
    			this.keyPair = keyPair;
    			this.Z=ZA(ID, keyPair.getPublicKey());
    		}
    
    		/**
    		 * 密钥协商发起第一步
    		 * 
    		 * @return
    		 */
    		public TransportEntity keyExchange_1() {
    			rA = random(n);
    			// rA=new BigInteger("83A2C9C8 B96E5AF7 0BD480B4 72409A9A 327257F1
    			// EBB73F5B 073354B2 48668563".replace(" ", ""),16);
    			RA = G.multiply(rA).normalize();
    			return new TransportEntity(RA.getEncoded(false), null,Z,keyPair.getPublicKey());
    		}
    
    		/**
    		 * 密钥协商响应方
    		 * 
    		 * @param entity 传输实体
    		 * @return
    		 */
    		public TransportEntity keyExchange_2(TransportEntity entity) {
    			BigInteger rB = random(n);
    			// BigInteger rB=new BigInteger("33FE2194 0342161C 55619C4A 0C060293
    			// D543C80A F19748CE 176D8347 7DE71C80".replace(" ", ""),16);
    			ECPoint RB = G.multiply(rB).normalize();
    			
    			this.rA=rB;
    			this.RA=RB;
    
    			BigInteger x2 = RB.getXCoord().toBigInteger();
    			x2 = _2w.add(x2.and(_2w.subtract(BigInteger.ONE)));
    
    			BigInteger tB = keyPair.getPrivateKey().add(x2.multiply(rB)).mod(n);
    			ECPoint RA = curve.decodePoint(entity.R).normalize();
    			
    			BigInteger x1 = RA.getXCoord().toBigInteger();
    			x1 = _2w.add(x1.and(_2w.subtract(BigInteger.ONE)));
    
    			ECPoint aPublicKey=curve.decodePoint(entity.K).normalize();
    			ECPoint temp = aPublicKey.add(RA.multiply(x1).normalize()).normalize();
    			ECPoint V = temp.multiply(ecc_bc_spec.getH().multiply(tB)).normalize();
    			if (V.isInfinity())
    				throw new IllegalStateException();
    			this.V=V;
    			
    			byte[] xV = V.getXCoord().toBigInteger().toByteArray();
    			byte[] yV = V.getYCoord().toBigInteger().toByteArray();
    			byte[] KB = KDF(join(xV, yV, entity.Z, this.Z), 16);
    			key = KB;
    			System.out.print("协商得B密钥:");
    			printHexString(KB);
    			byte[] sB = sm3hash(new byte[] { 0x02 }, yV,
    					sm3hash(xV, entity.Z, this.Z, RA.getXCoord().toBigInteger().toByteArray(),
    							RA.getYCoord().toBigInteger().toByteArray(), RB.getXCoord().toBigInteger().toByteArray(),
    							RB.getYCoord().toBigInteger().toByteArray()));
    			return new TransportEntity(RB.getEncoded(false), sB,this.Z,keyPair.getPublicKey());
    		}
    
    		/**
    		 * 密钥协商发起方第二步
    		 * 
    		 * @param entity 传输实体
    		 */
    		public TransportEntity keyExchange_3(TransportEntity entity) {
    			BigInteger x1 = RA.getXCoord().toBigInteger();
    			x1 = _2w.add(x1.and(_2w.subtract(BigInteger.ONE)));
    
    			BigInteger tA = keyPair.getPrivateKey().add(x1.multiply(rA)).mod(n);
    			ECPoint RB = curve.decodePoint(entity.R).normalize();
    			
    			BigInteger x2 = RB.getXCoord().toBigInteger();
    			x2 = _2w.add(x2.and(_2w.subtract(BigInteger.ONE)));
    
    			ECPoint bPublicKey=curve.decodePoint(entity.K).normalize();
    			ECPoint temp = bPublicKey.add(RB.multiply(x2).normalize()).normalize();
    			ECPoint U = temp.multiply(ecc_bc_spec.getH().multiply(tA)).normalize();
    			if (U.isInfinity())
    				throw new IllegalStateException();
    			this.V=U;
    			
    			byte[] xU = U.getXCoord().toBigInteger().toByteArray();
    			byte[] yU = U.getYCoord().toBigInteger().toByteArray();
    			byte[] KA = KDF(join(xU, yU,
    					this.Z, entity.Z), 16);
    			key = KA;
    			System.out.print("协商得A密钥:");
    			printHexString(KA);
    			byte[] s1= sm3hash(new byte[] { 0x02 }, yU,
    					sm3hash(xU, this.Z, entity.Z, RA.getXCoord().toBigInteger().toByteArray(),
    							RA.getYCoord().toBigInteger().toByteArray(), RB.getXCoord().toBigInteger().toByteArray(),
    							RB.getYCoord().toBigInteger().toByteArray()));
    			if(Arrays.equals(entity.S, s1))
    				System.out.println("B->A 密钥确认成功");
    			else
    				System.out.println("B->A 密钥确认失败");
    			byte[] sA= sm3hash(new byte[] { 0x03 }, yU,
    					sm3hash(xU, this.Z, entity.Z, RA.getXCoord().toBigInteger().toByteArray(),
    							RA.getYCoord().toBigInteger().toByteArray(), RB.getXCoord().toBigInteger().toByteArray(),
    							RB.getYCoord().toBigInteger().toByteArray()));
    			
    			return new TransportEntity(RA.getEncoded(false), sA,this.Z,keyPair.getPublicKey());
    		}
    		
    		/**
    		 * 密钥确认最后一步
    		 * 
    		 * @param entity 传输实体
    		 */
    		public void keyExchange_4(TransportEntity entity) {
    			byte[] xV = V.getXCoord().toBigInteger().toByteArray();
    			byte[] yV = V.getYCoord().toBigInteger().toByteArray();
    			ECPoint RA = curve.decodePoint(entity.R).normalize();
    			byte[] s2= sm3hash(new byte[] { 0x03 }, yV,
    					sm3hash(xV, entity.Z, this.Z, RA.getXCoord().toBigInteger().toByteArray(),
    							RA.getYCoord().toBigInteger().toByteArray(), this.RA.getXCoord().toBigInteger().toByteArray(),
    							this.RA.getYCoord().toBigInteger().toByteArray()));
    			if(Arrays.equals(entity.S, s2))
    				System.out.println("A->B 密钥确认成功");
    			else
    				System.out.println("A->B 密钥确认失败");
    		}
    	}
    
    	public static void main(String[] args) throws UnsupportedEncodingException {
    
    		SM2 sm02 = new SM2();
    
    		System.out.println("-----------------公钥加密与解密-----------------");
    		ECPoint publicKey = sm02.importPublicKey("E:/publickey.pem");
    		BigInteger privateKey = sm02.importPrivateKey("E:/privatekey.pem");
    		byte[] data = sm02.encrypt("测试加密aaaaaaaaaaa123aabb", publicKey);
    		System.out.print("密文:");
    		SM2.printHexString(data);
    		System.out.println("解密后明文:" + sm02.decrypt(data, privateKey));
    
    		System.out.println("-----------------签名与验签-----------------");
    		String IDA = "Heartbeats";
    		String M = "要签名的信息";
    		Signature signature = sm02.sign(M, IDA, new SM2KeyPair(publicKey, privateKey));
    		System.out.println("用户标识:" + IDA);
    		System.out.println("签名信息:" + M);
    		System.out.println("数字签名:" + signature);
    		System.out.println("验证签名:" + sm02.verify(M, signature, IDA, publicKey));
    
    		System.out.println("-----------------密钥协商-----------------");
    		String aID = "AAAAAAAAAAAAA";
    		SM2KeyPair aKeyPair = sm02.generateKeyPair();
    		KeyExchange aKeyExchange = new KeyExchange(aID,aKeyPair);
    
    		String bID = "BBBBBBBBBBBBB";
    		SM2KeyPair bKeyPair = sm02.generateKeyPair();
    		KeyExchange bKeyExchange = new KeyExchange(bID,bKeyPair);
    		TransportEntity entity1 = aKeyExchange.keyExchange_1();
    		TransportEntity entity2 = bKeyExchange.keyExchange_2(entity1);
    		TransportEntity entity3 = aKeyExchange.keyExchange_3(entity2);
    		bKeyExchange.keyExchange_4(entity3);
    	}
    
    	public static class Signature {
    		BigInteger r;
    		BigInteger s;
    
    		public Signature(BigInteger r, BigInteger s) {
    			this.r = r;
    			this.s = s;
    		}
    
    		public String toString() {
    			return r.toString(16) + "," + s.toString(16);
    		}
    	}
    }
    

    sm3:

    public class SM3 {
    
        private static char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
                '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        private static final String ivHexStr = "7380166f 4914b2b9 172442d7 da8a0600 a96f30bc 163138aa e38dee4d b0fb0e4e";
        private static final BigInteger IV = new BigInteger(ivHexStr.replaceAll(" ",
                ""), 16);
        private static final Integer Tj15 = Integer.valueOf("79cc4519", 16);
        private static final Integer Tj63 = Integer.valueOf("7a879d8a", 16);
        private static final byte[] FirstPadding = {(byte) 0x80};
        private static final byte[] ZeroPadding = {(byte) 0x00};
    
        private static int T(int j) {
            if (j >= 0 && j <= 15) {
                return Tj15.intValue();
            } else if (j >= 16 && j <= 63) {
                return Tj63.intValue();
            } else {
                throw new RuntimeException("data invalid");
            }
        }
    
        private static Integer FF(Integer x, Integer y, Integer z, int j) {
            if (j >= 0 && j <= 15) {
                return Integer.valueOf(x.intValue() ^ y.intValue() ^ z.intValue());
            } else if (j >= 16 && j <= 63) {
                return Integer.valueOf((x.intValue() & y.intValue())
                        | (x.intValue() & z.intValue())
                        | (y.intValue() & z.intValue()));
            } else {
                throw new RuntimeException("data invalid");
            }
        }
    
        private static Integer GG(Integer x, Integer y, Integer z, int j) {
            if (j >= 0 && j <= 15) {
                return Integer.valueOf(x.intValue() ^ y.intValue() ^ z.intValue());
            } else if (j >= 16 && j <= 63) {
                return Integer.valueOf((x.intValue() & y.intValue())
                        | (~x.intValue() & z.intValue()));
            } else {
                throw new RuntimeException("data invalid");
            }
        }
    
        private static Integer P0(Integer x) {
            return Integer.valueOf(x.intValue()
                    ^ Integer.rotateLeft(x.intValue(), 9)
                    ^ Integer.rotateLeft(x.intValue(), 17));
        }
    
        private static Integer P1(Integer x) {
            return Integer.valueOf(x.intValue()
                    ^ Integer.rotateLeft(x.intValue(), 15)
                    ^ Integer.rotateLeft(x.intValue(), 23));
        }
    
        private static byte[] padding(byte[] source) throws IOException {
            if (source.length >= 0x2000000000000000l) {
                throw new RuntimeException("src data invalid.");
            }
            long l = source.length * 8;
            long k = 448 - (l + 1) % 512;
            if (k < 0) {
                k = k + 512;
            }
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            baos.write(source);
            baos.write(FirstPadding);
            long i = k - 7;
            while (i > 0) {
                baos.write(ZeroPadding);
                i -= 8;
            }
            baos.write(long2bytes(l));
            return baos.toByteArray();
        }
    
        private static byte[] long2bytes(long l) {
            byte[] bytes = new byte[8];
            for (int i = 0; i < 8; i++) {
                bytes[i] = (byte) (l >>> ((7 - i) * 8));
            }
            return bytes;
        }
    
        public static byte[] hash(byte[] source) throws IOException {
            byte[] m1 = padding(source);
            int n = m1.length / (512 / 8);
            byte[] b;
            byte[] vi = IV.toByteArray();
            byte[] vi1 = null;
            for (int i = 0; i < n; i++) {
                b = Arrays.copyOfRange(m1, i * 64, (i + 1) * 64);
                vi1 = CF(vi, b);
                vi = vi1;
            }
            return vi1;
        }
    
        private static byte[] CF(byte[] vi, byte[] bi) throws IOException {
            int a, b, c, d, e, f, g, h;
            a = toInteger(vi, 0);
            b = toInteger(vi, 1);
            c = toInteger(vi, 2);
            d = toInteger(vi, 3);
            e = toInteger(vi, 4);
            f = toInteger(vi, 5);
            g = toInteger(vi, 6);
            h = toInteger(vi, 7);
    
            int[] w = new int[68];
            int[] w1 = new int[64];
            for (int i = 0; i < 16; i++) {
                w[i] = toInteger(bi, i);
            }
            for (int j = 16; j < 68; j++) {
                w[j] = P1(w[j - 16] ^ w[j - 9] ^ Integer.rotateLeft(w[j - 3], 15))
                        ^ Integer.rotateLeft(w[j - 13], 7) ^ w[j - 6];
            }
            for (int j = 0; j < 64; j++) {
                w1[j] = w[j] ^ w[j + 4];
            }
            int ss1, ss2, tt1, tt2;
            for (int j = 0; j < 64; j++) {
                ss1 = Integer
                        .rotateLeft(
                                Integer.rotateLeft(a, 12) + e
                                        + Integer.rotateLeft(T(j), j), 7);
                ss2 = ss1 ^ Integer.rotateLeft(a, 12);
                tt1 = FF(a, b, c, j) + d + ss2 + w1[j];
                tt2 = GG(e, f, g, j) + h + ss1 + w[j];
                d = c;
                c = Integer.rotateLeft(b, 9);
                b = a;
                a = tt1;
                h = g;
                g = Integer.rotateLeft(f, 19);
                f = e;
                e = P0(tt2);
            }
            byte[] v = toByteArray(a, b, c, d, e, f, g, h);
            for (int i = 0; i < v.length; i++) {
                v[i] = (byte) (v[i] ^ vi[i]);
            }
            return v;
        }
    
        private static int toInteger(byte[] source, int index) {
            StringBuilder valueStr = new StringBuilder("");
            for (int i = 0; i < 4; i++) {
                valueStr.append(hexDigits[(byte) ((source[index * 4 + i] & 0xF0) >> 4)]);
                valueStr.append(hexDigits[(byte) (source[index * 4 + i] & 0x0F)]);
            }
            return Long.valueOf(valueStr.toString(), 16).intValue();
    
        }
    
        private static byte[] toByteArray(int a, int b, int c, int d, int e, int f,
                                          int g, int h) throws IOException {
            ByteArrayOutputStream baos = new ByteArrayOutputStream(32);
            baos.write(toByteArray(a));
            baos.write(toByteArray(b));
            baos.write(toByteArray(c));
            baos.write(toByteArray(d));
            baos.write(toByteArray(e));
            baos.write(toByteArray(f));
            baos.write(toByteArray(g));
            baos.write(toByteArray(h));
            return baos.toByteArray();
        }
    
        public static byte[] toByteArray(int i) {
            byte[] byteArray = new byte[4];
            byteArray[0] = (byte) (i >>> 24);
            byteArray[1] = (byte) ((i & 0xFFFFFF) >>> 16);
            byteArray[2] = (byte) ((i & 0xFFFF) >>> 8);
            byteArray[3] = (byte) (i & 0xFF);
            return byteArray;
        }
        private static String byteToHexString(byte b) {
            int n = b;
            if (n < 0)
                n = 256 + n;
            int d1 = n / 16;
            int d2 = n % 16;
            return ""+hexDigits[d1] + hexDigits[d2];
        }
    
    	public static String byteArrayToHexString(byte[] b) {
            StringBuffer resultSb = new StringBuffer();
            for (int i = 0; i < b.length; i++) {
                resultSb.append(byteToHexString(b[i]));
            }
            return resultSb.toString();
        }
    
        public static void main(String[] args) throws IOException {
            System.out.println(SM3.byteArrayToHexString(SM3.hash("test".getBytes())));
        }
    }

    git源代码:

    https://github.com/PopezLotado/SM2Java

    展开全文
  • java使用国密sm算法

    2019-08-22 19:31:19
    https://www.cnblogs.com/alsodzy/p/9854521.html
    展开全文
  • PCIKeyPair.java /** * @Author: dzy * @Date: 2018/9/27 14:18 * @Describe: 公私钥对 */ @Data @AllArgsConstructor @NoArgsConstructor public class PCIKeyPair { private String pri...

    公用类算法:

    PCIKeyPair.java

    /**
     * @Author: dzy
     * @Date: 2018/9/27 14:18
     * @Describe: 公私钥对
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class PCIKeyPair {
    
        private String priKey;      //私钥
        private String pubKey;      //公钥
    
    }

    CommonUtils.java

    import org.apache.commons.lang3.StringUtils;
    
    import java.io.UnsupportedEncodingException;
    import java.nio.ByteBuffer;
    import java.nio.ByteOrder;
    import java.text.SimpleDateFormat;
    import java.util.Calendar;
    import java.util.Date;
    
    /**
     * @ClassName: CommonUtils
     * @Description: 通用工具类
     * @since: 0.0.1
     * @author: dzy
     * @date: 2017年2月22日 上午11:46:44
     */
    public class CommonUtils {
    
    
        /**
         * @param date    日期
         * @param pattern 模式 如:yyyyMMdd等
         * @return
         * @Title: formatDate
         * @Description: 格式化日期
         * @since: 0.0.1
         */
        public static String formatDate(Date date, String pattern) {
            SimpleDateFormat formatter = new SimpleDateFormat(pattern);
            return formatter.format(date);
        }
    
        /**
         * @param strDate String类型日期
         * @param pattern 日期显示模式
         * @return
         * @Title: parseDate
         * @Description: 将String日期转换为Date类型日期
         * @since: 0.0.1
         */
        public static Date parseDate(String strDate, String pattern) {
            SimpleDateFormat formatter = null;
            if (StringUtils.isBlank(strDate)) {
                return null;
            }
            formatter = new SimpleDateFormat(pattern);
            try {
                return formatter.parse(strDate);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
        /**
         * @param date   操作前的日期
         * @param field  日期的部分如:年,月,日
         * @param amount 增加或减少的值(负数表示减少)
         * @return
         * @Title: dateAdd
         * @Description: 日期的加减操作
         * @since: 0.0.1
         */
        public static Date dateAdd(Date date, int field, int amount) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(field, amount);
            return calendar.getTime();
        }
    
        /**
         * @param source 源字符串
         * @param offset 填充开始的位置, 0-在左边, source.getBytes().length 在右边, 如果有中文时需小心位置
         * @param c      用于填充的字符
         * @param length 最后字符串的字节长度
         * @return
         * @Title: fill
         * @Description: 填充字符串, 长度是按字节计算, 不是字符
         * @since: 0.0.1
         */
        public static String fill(String source, int offset, char c, int length) throws UnsupportedEncodingException {
            if (null == source) {
                source = "";
            }
            if (source.getBytes(CustomConstants.CHARSET_UTF8).length == length) {
                return source;
            }
            byte[] buf = new byte[length];
            byte[] src = source.getBytes(CustomConstants.CHARSET_UTF8);
            if (src.length > length) {
                System.arraycopy(src, src.length - length, buf, 0, length);
                return new String(buf, CustomConstants.CHARSET_UTF8);
            }
            if (offset > src.length) {
                offset = src.length;
            } else if (offset < 0) {
                offset = 0;
            }
            int n = length - src.length;
    
            System.arraycopy(src, 0, buf, 0, offset);
            for (int i = 0; i < n; i++) {
                buf[i + offset] = (byte) c;
            }
            System.arraycopy(src, offset, buf, offset + n, src.length - offset);
            return new String(buf, CustomConstants.CHARSET_UTF8);
        }
    
        /**
         * @param original 原字符串
         * @param offset   填充开始的位置, 0-在左边, original.getBytes().length 在右边, 如果有中文时需小心位置
         * @param length   替换的字节数
         * @param c        用于替换的字符
         * @return
         * @Title: replace
         * @Description: 替换字符串, 长度是按字节计算, 不是字符
         * @since: 0.0.1
         */
        public static String replace(String original, int offset, int length, char c) throws UnsupportedEncodingException {
            if (original == null) {
                original = "";
            }
            if (original.getBytes(CustomConstants.CHARSET_UTF8).length <= offset) {
                return original;
            }
            if (original.getBytes(CustomConstants.CHARSET_UTF8).length < offset + length) {
                length = original.getBytes(CustomConstants.CHARSET_UTF8).length - offset;
            }
            byte[] buf = new byte[original.length()];
            byte[] src = original.getBytes(CustomConstants.CHARSET_UTF8);
            System.arraycopy(src, 0, buf, 0, offset);
    
            for (int i = offset; i < offset + length; i++) {
                buf[i] = (byte) c;
            }
            System.arraycopy(src, offset + length, buf, offset + length, src.length - offset - length);
            return new String(buf, CustomConstants.CHARSET_UTF8);
        }
    
        /**
         * @param s 16进制字符串
         * @return
         * @Title: hexToByte
         * @Description: 16进制字符串转字节数组
         * @since: 0.0.1
         */
        public static byte[] hexToByte(String s) {
            byte[] result = null;
            try {
                int i = s.length();
    //            if (i % 2 == 1) {
    //                throw new Exception("字符串长度不是偶数.");
    //            }
                if (i % 2 != 0) {
                    throw new Exception("字符串长度不是偶数.");
                }
                result = new byte[i / 2];
                for (int j = 0; j < result.length; j++) {
                    result[j] = (byte) Integer.parseInt(s.substring(j * 2, j * 2 + 2), 16);
                }
            } catch (Exception e) {
                result = null;
                e.printStackTrace();
    //            log.error("16进制字符串转字节数组时出现异常:", e);
            }
            return result;
        }
    
        /**
         * @param bytes 字节数组
         * @return
         * @Title: byte2hexString
         * @Description: 字节数组转换为16进制字符串    //0x33 0xD2 0x00 0x46 转换为 "33d20046" 转换和打印报文用
         * @since: 0.0.1
         */
        public static String byte2hexString(byte[] bytes) {
            StringBuffer buf = new StringBuffer(bytes.length * 2);
            for (int i = 0; i < bytes.length; i++) {
                if (((int) bytes[i] & 0xff) < 0x10) {
                    buf.append("0");
                }
                buf.append(Long.toString((int) bytes[i] & 0xff, 16));
            }
            return buf.toString().toUpperCase();
        }
    
        /**
         * @param hexString 16进制字符串    如:"33d20046" 转换为 0x33 0xD2 0x00 0x46
         * @return
         * @Title: hexString2byte
         * @Description: 16进制字符串转字节数组
         * @since: 0.0.1
         */
        public static byte[] hexString2byte(String hexString) {
            if (null == hexString || hexString.length() % 2 != 0 || hexString.contains("null")) {
                return null;
            }
            byte[] bytes = new byte[hexString.length() / 2];
            for (int i = 0; i < hexString.length(); i += 2) {
                bytes[i / 2] = (byte) (Integer.parseInt(hexString.substring(i, i + 2), 16) & 0xff);
            }
            return bytes;
        }
    
        /**
         * @param i 需要转的int类型数字
         * @return
         * @Title: byte1ToBcd2
         * @Description: int类型转BCD码
         * @since: 0.0.1
         */
        public static String byte1ToBcd2(int i) {
    //        return (new Integer(i / 16).toString() + (new Integer(i % 16)).toString());
            return Integer.toString(i / 16) + Integer.toString(i % 16);
        }
    
        /**
         * @param b 字节数组
         * @return
         * @Title: byteToHex2
         * @Description: 字节数组转换为16进制字符串        For example, byte[] {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF} will be changed to String "0123456789ABCDEF"
         * @since: 0.0.1
         */
        public static String byteToHex2(byte[] b) {
            StringBuffer result = new StringBuffer();
            String tmp = "";
    
            for (int i = 0; i < b.length; i++) {
                tmp = Integer.toHexString(b[i] & 0xff);
                if (tmp.length() == 1) {
                    result.append("0" + tmp);
                } else {
                    result.append(tmp);
                }
            }
            return result.toString().toUpperCase();
        }
    
        /**
         * @param num 数字
         * @param len 字节数组长度
         * @return
         * @Title: intToHexBytes
         * @Description: int类型转16进制字节数组
         */
        public static byte[] intToHexBytes(int num, int len) {
            byte[] bytes = null;
            String hexString = Integer.toHexString(num);
            if (len > 0) {
                int length = len * 2;
                hexString = CustomStringUtils.leftFill(hexString, '0', length);
                bytes = CommonUtils.hexString2byte(hexString);
            }
            return bytes;
        }
    
        /*public static String byteToHex3(byte[] b) {
            String result = "";
            String tmp = "";
    
            for (int n = 0; n < b.length; n++) {
                tmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
                if (tmp.length() == 1) {
                    result = result + "0" + tmp;
                } else {
                    result = result + tmp;
                }
                if (n < b.length - 1) {
                    result = result + "";
                }
            }
            return result.toUpperCase();
        }*/
    
        /**
         * @param str 需要转换编码的字符串
         * @return
         * @Title: iso2Gbk
         * @Description: 将ISO-8859-1编码的字符串转成GBK编码的字符串
         * @since: 0.0.1
         */
        public static String iso2Gbk(String str) {
            if (null == str) {
                return str;
            }
            try {
                return new String(str.getBytes("ISO-8859-1"), "GBK");
            } catch (UnsupportedEncodingException e) {
    //            log.error("不支持的编码异常:", e);
                e.printStackTrace();
                return str;
            }
        }
    
    //    /**
    //     * @param message
    //     * @return
    //     * @Title: getSubElement
    //     * @Description: 分解各子域到HashMap
    //     * @since: 0.0.1
    //     */
    //    public static Map<String, String> getSubElement(byte[] message) {
    //        Map<String, String> map = new HashMap<String, String>();
    //        String key = null;
    //        String value = null;
    //        int len = 0;
    //        int idx = 0;
    //        while (idx < message.length) {
    //            key = new String(message, idx, 2);
    //            idx += 2;    //取了SE id 移2位
    //            len = Integer.parseInt(new String(message, idx, 2));
    //            idx += 2;    //取了SE id的内容长度  移2位
    //            value = new String(message, idx, len);
    //            map.put(key, value);
    //            idx += len;
    //        }
    //        return map;
    //    }
    
        //byte数组转成long
    
        /**
         * @param b 将字节数组转long类型 位置为小端
         * @return
         */
        public static long byteToLong(byte[] b) {
            long s = 0;
            long s0 = b[0] & 0xff;// 最低位
            long s1 = b[1] & 0xff;
            long s2 = b[2] & 0xff;
            long s3 = b[3] & 0xff;
            long s4 = b[4] & 0xff;// 最低位
            long s5 = b[5] & 0xff;
            long s6 = b[6] & 0xff;
            long s7 = b[7] & 0xff;
    
            // s0不变
            s1 <<= 8;
            s2 <<= 16;
            s3 <<= 24;
            s4 <<= 8 * 4;
            s5 <<= 8 * 5;
            s6 <<= 8 * 6;
            s7 <<= 8 * 7;
            s = s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7;
            return s;
        }
    
        /**
         * @param b 将字节数组转int类型     位置为小端
         * @return
         */
        public static int byteToInt(byte[] b) {
            int s = 0;
            int s0 = b[0] & 0xff;// 最低位
            int s1 = b[1] & 0xff;
            int s2 = b[2] & 0xff;
            int s3 = b[3] & 0xff;
    
            // s0不变
            s1 <<= 8;
            s2 <<= 16;
            s3 <<= 24;
    
            s = s0 | s1 | s2 | s3;
            return s;
        }
    
        /**
         * int类型转换小端的byte数组
         * @param i
         * @return
         */
        public static byte[] intToLittleBytes(int i) {
            ByteBuffer byteBuffer = ByteBuffer.allocate(4);
            byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
            byteBuffer.asIntBuffer().put(i);
            byte[] littleBytes = byteBuffer.array();
            return littleBytes;
        }
    
        /**
         * 将一个字节转成10进制
         * @param b
         * @return
         */
        public static int byteToInt(byte b) {
            int value = b & 0xff;
            return value;
        }
    
        /**
         *  字节数组合并
         * @param bt1   字节数组bt1
         * @param bt2   字节数组bt2
         * @return
         */
        public static byte[] byteMerger(byte[] bt1, byte[] bt2){
            byte[] bt3 = new byte[bt1.length+bt2.length];
            System.arraycopy(bt1, 0, bt3, 0, bt1.length);
            System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
            return bt3;
        }
    
    }

    SM2算法:

     

    package com.pcidata.common.tools.encrypt;
    
    import com.pcidata.common.tools.CommonUtils;
    import com.pcidata.common.tools.CustomStringUtils;
    import com.pcidata.modules.key.modelvo.response.PCIKeyPair;
    import lombok.extern.slf4j.Slf4j;
    import org.bouncycastle.asn1.gm.GMNamedCurves;
    import org.bouncycastle.asn1.x9.X9ECParameters;
    import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
    import org.bouncycastle.crypto.engines.SM2Engine;
    import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
    import org.bouncycastle.crypto.params.*;
    import org.bouncycastle.crypto.signers.SM2Signer;
    import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
    import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
    import org.bouncycastle.jce.spec.ECParameterSpec;
    import org.bouncycastle.math.ec.ECPoint;
    import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
    import org.bouncycastle.util.Strings;
    import org.bouncycastle.util.encoders.Hex;
    
    import java.math.BigInteger;
    import java.security.NoSuchAlgorithmException;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.security.SecureRandom;
    
    /**
     * @Author: dzy
     * @Date: 2018/9/28 15:53
     * @Describe: SM2工具类
     */
    @Slf4j
    public class SM2Util {
    
        /**
         * 生成SM2公私钥对
         * @return
         */
        private static AsymmetricCipherKeyPair genKeyPair0() {
            //获取一条SM2曲线参数
            X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
    
            //构造domain参数
            ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                    sm2ECParameters.getG(), sm2ECParameters.getN());
    
            //1.创建密钥生成器
            ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
    
            //2.初始化生成器,带上随机数
            try {
                keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
            } catch (NoSuchAlgorithmException e) {
                log.error("生成公私钥对时出现异常:", e);
    //            e.printStackTrace();
            }
    
            //3.生成密钥对
            AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
            return asymmetricCipherKeyPair;
        }
    
        /**
         * 生成公私钥对(默认压缩公钥)
         * @return
         */
        public static PCIKeyPair genKeyPair() {
            return genKeyPair(true);
        }
    
        /**
         * 生成公私钥对
         * @param compressedPubKey  是否压缩公钥
         * @return
         */
        public static PCIKeyPair genKeyPair(boolean compressedPubKey) {
            AsymmetricCipherKeyPair asymmetricCipherKeyPair = genKeyPair0();
    
            //提取公钥点
            ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
            //公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥,04的时候,可以去掉前面的04
            String pubKey = Hex.toHexString(ecPoint.getEncoded(compressedPubKey));
    
            BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
            String priKey = privatekey.toString(16);
    
            PCIKeyPair keyPair = new PCIKeyPair(priKey, pubKey);
            return keyPair;
        }
    
        /**
         * 私钥签名
         * @param privateKey    私钥
         * @param content       待签名内容
         * @return
         */
        public static String sign(String privateKey, String content) {
            //待签名内容转为字节数组
            byte[] message = Hex.decode(content);
    
            //获取一条SM2曲线参数
            X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
            //构造domain参数
            ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                    sm2ECParameters.getG(), sm2ECParameters.getN());
    
            BigInteger privateKeyD = new BigInteger(privateKey, 16);
            ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);
    
            //创建签名实例
            SM2Signer sm2Signer = new SM2Signer();
    
            //初始化签名实例,带上ID,国密的要求,ID默认值:1234567812345678
            try {
                sm2Signer.init(true, new ParametersWithID(new ParametersWithRandom(privateKeyParameters, SecureRandom.getInstance("SHA1PRNG")), Strings.toByteArray("1234567812345678")));
            } catch (NoSuchAlgorithmException e) {
                log.error("签名时出现异常:", e);
            }
    
            //生成签名,签名分为两部分r和s,分别对应索引0和1的数组
            BigInteger[] bigIntegers = sm2Signer.generateSignature(message);
    
            byte[] rBytes = modifyRSFixedBytes(bigIntegers[0].toByteArray());
            byte[] sBytes = modifyRSFixedBytes(bigIntegers[1].toByteArray());
    
            byte[] signBytes = ByteUtils.concatenate(rBytes, sBytes);
            String sign = Hex.toHexString(signBytes);
    
            return sign;
        }
    
        /**
         * 将R或者S修正为固定字节数
         * @param rs
         * @return
         */
        private static byte[] modifyRSFixedBytes(byte[] rs) {
            int length = rs.length;
            int fixedLength = 32;
            byte[] result = new byte[fixedLength];
            if (length < 32) {
                System.arraycopy(rs, 0, result, fixedLength - length, length);
            } else {
                System.arraycopy(rs, length - fixedLength, result, 0, fixedLength);
            }
            return result;
        }
    
        /**
         * 验证签名
         * @param publicKey     公钥
         * @param content       待签名内容
         * @param sign          签名值
         * @return
         */
        public static boolean verify(String publicKey, String content, String sign) {
            //待签名内容
            byte[] message = Hex.decode(content);
            byte[] signData = Hex.decode(sign);
    
            // 获取一条SM2曲线参数
            X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
            // 构造domain参数
            ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                    sm2ECParameters.getG(),
                    sm2ECParameters.getN());
            //提取公钥点
            ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(CommonUtils.hexString2byte(publicKey));
            // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
            ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
    
            //获取签名
            BigInteger R = null;
            BigInteger S = null;
            byte[] rBy = new byte[33];
            System.arraycopy(signData, 0, rBy, 1, 32);
            rBy[0] = 0x00;
            byte[] sBy = new byte[33];
            System.arraycopy(signData, 32, sBy, 1, 32);
            sBy[0] = 0x00;
            R = new BigInteger(rBy);
            S = new BigInteger(sBy);
    
            //创建签名实例
            SM2Signer sm2Signer = new SM2Signer();
            ParametersWithID parametersWithID = new ParametersWithID(publicKeyParameters, Strings.toByteArray("1234567812345678"));
            sm2Signer.init(false, parametersWithID);
    
            //验证签名结果
            boolean verify = sm2Signer.verifySignature(message, R, S);
            return verify;
        }
    
        /**
         * SM2加密算法
         * @param publicKey     公钥
         * @param data          数据
         * @return
         */
        public static String encrypt(String publicKey, String data){
            // 获取一条SM2曲线参数
            X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
            // 构造domain参数
            ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                    sm2ECParameters.getG(),
                    sm2ECParameters.getN());
            //提取公钥点
            ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(CommonUtils.hexString2byte(publicKey));
            // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
            ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
    
            SM2Engine sm2Engine = new SM2Engine();
            sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));
    
            byte[] arrayOfBytes = null;
            try {
                byte[] in = data.getBytes("utf-8");
                arrayOfBytes = sm2Engine.processBlock(in, 0, in.length);
            } catch (Exception e) {
                log.error("SM2加密时出现异常:", e);
            }
            return Hex.toHexString(arrayOfBytes);
        }
    
        /**
         * SM2加密算法
         * @param publicKey     公钥
         * @param data          明文数据
         * @return
         */
        public static String encrypt(PublicKey publicKey, String data) {
    
            ECPublicKeyParameters ecPublicKeyParameters = null;
            if (publicKey instanceof BCECPublicKey) {
                BCECPublicKey bcecPublicKey = (BCECPublicKey) publicKey;
                ECParameterSpec ecParameterSpec = bcecPublicKey.getParameters();
                ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                        ecParameterSpec.getG(), ecParameterSpec.getN());
                ecPublicKeyParameters = new ECPublicKeyParameters(bcecPublicKey.getQ(), ecDomainParameters);
            }
    
            SM2Engine sm2Engine = new SM2Engine();
            sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));
    
            byte[] arrayOfBytes = null;
            try {
                byte[] in = data.getBytes("utf-8");
                arrayOfBytes = sm2Engine.processBlock(in,0, in.length);
            } catch (Exception e) {
                log.error("SM2加密时出现异常:", e);
            }
            return Hex.toHexString(arrayOfBytes);
        }
    
        /**
         * SM2解密算法
         * @param privateKey    私钥
         * @param cipherData    密文数据
         * @return
         */
        public static String decrypt(String privateKey, String cipherData) {
            byte[] cipherDataByte = Hex.decode(cipherData);
    
            //获取一条SM2曲线参数
            X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
            //构造domain参数
            ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                    sm2ECParameters.getG(), sm2ECParameters.getN());
    
            BigInteger privateKeyD = new BigInteger(privateKey, 16);
            ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);
    
            SM2Engine sm2Engine = new SM2Engine();
            sm2Engine.init(false, privateKeyParameters);
    
            String result = null;
            try {
                byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
                return new String(arrayOfBytes, "utf-8");
            } catch (Exception e) {
                log.error("SM2解密时出现异常:", e);
            }
            return result;
    
        }
    
        /**
         * SM2解密算法
         * @param privateKey        私钥
         * @param cipherData        密文数据
         * @return
         */
        public static String decrypt(PrivateKey privateKey, String cipherData) {
            byte[] cipherDataByte = Hex.decode(cipherData);
    
            BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) privateKey;
            ECParameterSpec ecParameterSpec = bcecPrivateKey.getParameters();
    
            ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                    ecParameterSpec.getG(), ecParameterSpec.getN());
    
            ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(bcecPrivateKey.getD(),
                    ecDomainParameters);
    
            SM2Engine sm2Engine = new SM2Engine();
            sm2Engine.init(false, ecPrivateKeyParameters);
    
            String result = null;
            try {
                byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
                return new String(arrayOfBytes, "utf-8");
            } catch (Exception e) {
                log.error("SM2解密时出现异常:", e);
            }
            return result;
        }
    
        /**
         * 将未压缩公钥压缩成压缩公钥
         * @param pubKey    未压缩公钥(16进制,不要带头部04)
         * @return
         */
        public static String compressPubKey(String pubKey) {
            pubKey = CustomStringUtils.append("04", pubKey);    //将未压缩公钥加上未压缩标识.
            // 获取一条SM2曲线参数
            X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
            // 构造domain参数
            ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                    sm2ECParameters.getG(),
                    sm2ECParameters.getN());
            //提取公钥点
            ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(CommonUtils.hexString2byte(pubKey));
            // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
    //        ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
    
            String compressPubKey = Hex.toHexString(pukPoint.getEncoded(Boolean.TRUE));
    
            return compressPubKey;
        }
    
        /**
         * 将压缩的公钥解压为非压缩公钥
         * @param compressKey   压缩公钥
         * @return
         */
        public static String unCompressPubKey(String compressKey) {
            // 获取一条SM2曲线参数
            X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
            // 构造domain参数
            ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                    sm2ECParameters.getG(),
                    sm2ECParameters.getN());
            //提取公钥点
            ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(CommonUtils.hexString2byte(compressKey));
            // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
    //        ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
    
            String pubKey = Hex.toHexString(pukPoint.getEncoded(Boolean.FALSE));
            pubKey = pubKey.substring(2);       //去掉前面的04   (04的时候,可以去掉前面的04)
    
            return pubKey;
        }
    
    }

     

     

    SM3算法:

    import lombok.extern.slf4j.Slf4j;
    import org.bouncycastle.crypto.digests.SM3Digest;
    import org.bouncycastle.crypto.macs.HMac;
    import org.bouncycastle.crypto.params.KeyParameter;
    import org.bouncycastle.util.encoders.Hex;
    
    import java.security.MessageDigest;
    
    /**
     * @Author: dzy
     * @Date: 2018/10/19 16:36
     * @Describe: SM3工具类(杂凑算法-hash算法)
     */
    @Slf4j
    public class SM3Util {
    
        /**
         * 16进制字符串SM3生成HASH签名值算法
         * @param hexString     16进制字符串
         * @return
         */
        public static String hexEncrypt(String hexString) {
            byte[] srcData = Hex.decode(hexString);
            byte[] encrypt = encrypt(srcData);
            String cipherStr  = Hex.toHexString(encrypt);
            return cipherStr;
        }
    
        /**
         * 16进制字符串SM3生成HASH签名值算法
         * @param hexKey        16进制密钥
         * @param hexString     16进制字符串
         * @return
         */
        public static String hexEncrypt(String hexKey, String hexString) {
            byte[] key = Hex.decode(hexKey);
            byte[] srcData = Hex.decode(hexString);
            byte[] encrypt = encrypt(key, srcData);
            String cipherStr  = Hex.toHexString(encrypt);
            return cipherStr;
        }
    
        /**
         * 普通文本SM3生成HASH签名算法
         * @param plain     待签名数据
         * @return
         */
        public static String plainEncrypt(String plain) {
            // 将返回的hash值转换成16进制字符串
            String cipherStr = null;
            try {
                //将字符串转换成byte数组
                byte[] srcData = plain.getBytes(CustomConstants.CHARSET_UTF8);
                //调用encrypt计算hash
                byte[] encrypt = encrypt(srcData);
                //将返回的hash值转换成16进制字符串
                cipherStr = Hex.toHexString(encrypt);
            } catch (Exception e) {
                log.error("将字符串转换为字节时出现异常:", e);
            }
            return cipherStr;
        }
    
        /**
         * 普通文本SM3生成HASH签名算法
         * @param hexKey        密钥
         * @param plain         待签名数据
         * @return
         */
        public static String plainEncrypt(String hexKey, String plain) {
            // 将返回的hash值转换成16进制字符串
            String cipherStr = null;
            try {
                //将字符串转换成byte数组
                byte[] srcData = plain.getBytes(CustomConstants.CHARSET_UTF8);
                //密钥
                byte[] key = Hex.decode(hexKey);
                //调用encrypt计算hash
                byte[] encrypt = encrypt(key, srcData);
                //将返回的hash值转换成16进制字符串
                cipherStr = Hex.toHexString(encrypt);
            } catch (Exception e) {
                log.error("将字符串转换为字节时出现异常:", e);
            }
            return cipherStr;
        }
    
        /**
         * SM3计算hashCode
         * @param srcData   待计算数据
         * @return
         */
        public static byte[] encrypt(byte[] srcData) {
            SM3Digest sm3Digest = new SM3Digest();
            sm3Digest.update(srcData, 0, srcData.length);
            byte[] encrypt = new byte[sm3Digest.getDigestSize()];
            sm3Digest.doFinal(encrypt, 0);
            return encrypt;
        }
    
        /**
         * 通过密钥进行加密
         * @param key       密钥byte数组
         * @param srcData   被加密的byte数组
         * @return
         */
        public static byte[] encrypt(byte[] key, byte[] srcData) {
            KeyParameter keyParameter = new KeyParameter(key);
            SM3Digest digest = new SM3Digest();
            HMac mac = new HMac(digest);
            mac.init(keyParameter);
            mac.update(srcData, 0, srcData.length);
            byte[] result = new byte[mac.getMacSize()];
            mac.doFinal(result, 0);
            return result;
        }
    
        /**
         * SM3计算hashCode
         * @param srcData   待计算数据
         * @return
         * @throws Exception
         */
        public static byte[] encrypt_0(byte[] srcData) throws Exception {
            MessageDigest messageDigest = MessageDigest.getInstance("SM3", "BC");
            byte[] digest = messageDigest.digest(srcData);
            return digest;
        }
    
    }

    SM4算法:

    import org.bouncycastle.crypto.engines.SM4Engine;
    import org.bouncycastle.crypto.params.KeyParameter;
    import org.bouncycastle.util.encoders.Hex;
    
    /**
     * @Author: dzy
     * @Date: 2018/10/9 16:41
     * @Describe: SM4算法
     */
    public class SM4Util {
    
        //加解密的字节快大小
        public static final int BLOCK_SIZE = 16;
    
        /**
         * SM4ECB加密算法
         * @param in            待加密内容
         * @param keyBytes      密钥
         * @return
         */
        public static byte[] encryptByEcb0(byte[] in, byte[] keyBytes) {
            SM4Engine sm4Engine = new SM4Engine();
            sm4Engine.init(true, new KeyParameter(keyBytes));
            int inLen = in.length;
            byte[] out = new byte[inLen];
    
            int times = inLen / BLOCK_SIZE;
    
            for (int i = 0; i < times; i++) {
                sm4Engine.processBlock(in, i * BLOCK_SIZE, out, i * BLOCK_SIZE);
            }
    
            return out;
        }
    
        /**
         * SM4ECB加密算法
         * @param in            待加密内容
         * @param keyBytes      密钥
         * @return
         */
        public static String encryptByEcb(byte[] in, byte[] keyBytes) {
            byte[] out = encryptByEcb0(in, keyBytes);
            String cipher = Hex.toHexString(out);
            return cipher;
        }
    
        /**
         * SM4的ECB加密算法
         * @param content   待加密内容
         * @param key       密钥
         * @return
         */
        public static String encryptByEcb(String content, String key) {
            byte[] in = Hex.decode(content);
            byte[] keyBytes = Hex.decode(key);
    
            String cipher = encryptByEcb(in, keyBytes);
            return cipher;
        }
    
        /**
         * SM4的ECB解密算法
         * @param in        密文内容
         * @param keyBytes  密钥
         * @return
         */
        public static byte[] decryptByEcb0(byte[] in, byte[] keyBytes) {
            SM4Engine sm4Engine = new SM4Engine();
            sm4Engine.init(false, new KeyParameter(keyBytes));
            int inLen = in.length;
            byte[] out = new byte[inLen];
    
            int times = inLen / BLOCK_SIZE;
    
            for (int i = 0; i < times; i++) {
                sm4Engine.processBlock(in, i * BLOCK_SIZE, out, i * BLOCK_SIZE);
            }
    
            return out;
        }
    
        /**
         * SM4的ECB解密算法
         * @param in        密文内容
         * @param keyBytes  密钥
         * @return
         */
        public static String decryptByEcb(byte[] in, byte[] keyBytes) {
            byte[] out = decryptByEcb0(in, keyBytes);
            String plain = Hex.toHexString(out);
            return plain;
        }
    
        /**
         * SM4的ECB解密算法
         * @param cipher    密文内容
         * @param key       密钥
         * @return
         */
        public static String decryptByEcb(String cipher, String key) {
            byte[] in = Hex.decode(cipher);
            byte[] keyBytes = Hex.decode(key);
    
            String plain = decryptByEcb(in, keyBytes);
            return plain;
        }
    
    }

     

    转载于:https://www.cnblogs.com/alsodzy/p/9854521.html

    展开全文
  • java sm2国密工具类

    2021-11-02 17:32:36
    https://download.csdn.net/download/qq_16504067/36484497 如果大家没有积分下不了,请参考(我也是参考这个大佬的,这个大佬也是参考别人的,大家都愿意分享,才能进步,哈哈): SM2加密解密工具_adaadadsa的...
  • 使用方法见:https://blog.csdn.net/upset_ming/article/details/96491058 1. 修改了前一版本中证书验证的bug,支持JDK8的高版本 2. 支持国密SSL双向认证 3. 将过期的国密证书替换为新证书
  • JAVA-国密算法SM3和SM4应用Example

    千次阅读 2020-10-24 10:09:54
    参考资料: https://baijiahao.baidu.com/s?id=1629915330021466224&...-- 国密算法 --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-
  • 因此,在服务端实现基于国密算法的SSL认证和HTTPS加密,需要网站运营者向工信部许可的权威电子认证机构(如: 沃通CA ),申请符合国密标准的国密SSL证书(如: 沃通国密SSL证书 ),将证书部署在服务器上,并在...
  • SMS4(java国密算法的加密与解密)

    千次阅读 2019-02-21 14:32:05
    Convert与SMS4均为sms4的算法实现方法,sms4类里面有Encryption加密方法Decrypt为解密方法 建议直接拷贝Convert和SMS4类(因为里面的方法比较长),可以直接运行...import java.math.BigInteger; public class Conver...
  • iOS 国密SM4 OC

    2018-11-01 14:09:27
    扩展NSString, 新增国密SM4加密、解密算法。网上关于这个算法的iOS代码很少,在本人查找资料并使用后,将此资源公开。方便广大iOS开发的新人朋友们使用。不过使用时,要注意加密解密过程中的字符填充,否则可能会...
  • 国密SM2加密示例(java)

    万次阅读 2020-06-11 17:52:11
    国密SM2加密示例原始文档定义参数SM2创建生成私钥生成公钥公私钥导入导出代码调用示例 原始文档 定义参数 public static BigInteger n = new BigInteger( "FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + ...
  • Java版比较好办,较新版本的bouncycastle就支持了SM2/SM3/SM4,麻烦在于JS版,找了很多都有问题,直到遇到了这个项目:https://github.com/Saberization/SM2,感谢作者。分别整理下前端后端的实现过程: 后端首先...
  • java sm3国密算法加密、验证工具类

    千次阅读 2021-02-25 15:01:47
    java sm3国密算法加密、验证工具类说明maven依赖完整代码测试 说明 由于本人并不专于算法和密码学,所以如果发现工具类存在问题或者可优化地方,欢迎评论处提出。 maven依赖 <!-- ...
  • java sm4国密算法 CBC模式 加解密工具类说明maven依赖生成密钥加密解密测试完整代码最后 说明 工具类最开始是参考这篇博客java sm4国密算法加密、解密,但是该篇博客使用的是EBC模式,所以参考其他文章改成了CBC模式...
  • java sm4国密算法加密、解密

    千次阅读 2018-07-06 11:44:00
    java sm4国密算法加密、解密 CreationTime--2018年7月5日09点20分 Author:Marydon 1.准备工作  所需jar包:  bcprov-jdk15on-1.59.jar  commons-lang3-3.1.jar import java.security.Key; import java....
  • 【原】国密SM3的java实现

    万次阅读 2018-06-12 10:12:33
    国密SM3的java实现 0. 写在最前面 国密算法资料比较少,最近在学习国密算法,所以准备把几个国密算法总结一下。这个是第一篇SM3的java实现。 1. SM3概述[1] 对长度为L (L&amp;amp;amp;lt;2^64)比特的...
  • 国密Sm2 Java+js配合使用

    千次阅读 2021-04-13 22:35:05
    Java端工具类: import java.math.BigInteger; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Base64; import org.bouncycastle.asn1.gm.GMNamedCurves...
  • 开箱即用 首先引入包 <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.6.8... } } 参考: https://blog.csdn.net/RisenMyth/article/details/107212156
  • 国密SM4 - Java.zip

    2019-09-17 18:23:38
    JAVA实现国密SM4加解密,达到前端JS加密,后台Java解密的效果。 JS版见: https://download.csdn.net/download/qq_36917130/11296303
  • 单向认证,客户端不需要国密证书和密钥 接收并显示服务器端国密数字证书 忽略服务端域名与国密证书不一致的警告 忽略不信任服务端国密根证书的警告 使用PP软件授权平台获取授权数据的简要说明 核心代码 /** *...
  • 国密算法 java源码 莱卡 卫星图像数据的注释和实验。 概要 这个 repo 的目标是研究卫星图像数据的潜在来源,并实现各种卫星图像分割算法。 目录 运行代码 以下步骤描述了当前正在进行的工作的端到端流程。 该实现...
  • 编写本文的同时借鉴了多位同学写的demo, 最后发现这位同学写的最详细, 放上该作者的链接, 原版链接:https://download.csdn.net/download/ererfei/9474502 结合公司的业务需求, 我自己编写测试了SM2的demo并增加了...
  • sm2、sm4国密加密算法java实现加密后内容 加密后内容 可自行验证是否是你需要的sm2加密算法 私钥:BF1F907B4E0487F798DC80AFD7BC2A6201E8514233002272EA3BE2FC6F797843 公钥:前缀04+x坐标+y坐标 042DBA45E7B03394...
  • java实现读取证书访问https接口java实现读取证书访问https接口

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 646
精华内容 258
关键字:

httpsjava国密

java 订阅