• SM2的非对称加解密java工具类


    maven依赖

    <dependency>
        <groupId>org.bouncycastle</groupId>
    	<artifactId>bcprov-jdk15on</artifactId>
    	<version>1.54</version>
    </dependency>
    

    java实现如下

    import java.math.BigInteger;
    import java.security.SecureRandom;
    import java.util.Arrays;
     
    import org.bouncycastle.crypto.DerivationFunction;
    import org.bouncycastle.crypto.digests.SHA256Digest;
    import org.bouncycastle.crypto.digests.ShortenedDigest;
    import org.bouncycastle.crypto.generators.KDF1BytesGenerator;
    import org.bouncycastle.crypto.params.ISO18033KDFParameters;
    import org.bouncycastle.math.ec.ECCurve;
    import org.bouncycastle.math.ec.ECPoint;
     
    /**
     * 	 <B>说	明<B/>:SM2的非对称加解密工具类,椭圆曲线方程为:y^2=x^3+ax+b 使用Fp-256
     */
    public class SM2Util {
     
    	/** 素数p */
    	private static final BigInteger p = new BigInteger("FFFFFFFE" + "FFFFFFFF"
    		+ "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "00000000" + "FFFFFFFF"
    		+ "FFFFFFFF", 16);
    	
    	/** 系数a */
    	private static final BigInteger a = new BigInteger("FFFFFFFE" + "FFFFFFFF"
    		+ "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "00000000" + "FFFFFFFF"
    		+ "FFFFFFFC", 16);
    	
    	/** 系数b */
    	private static final BigInteger b = new BigInteger("28E9FA9E" + "9D9F5E34"
    		+ "4D5A9E4B" + "CF6509A7" + "F39789F5" + "15AB8F92" + "DDBCBD41"
    		+ "4D940E93", 16);
    	
    	/** 坐标x */
    	private static final BigInteger xg = new BigInteger("32C4AE2C" + "1F198119"
    		+ "5F990446" + "6A39C994" + "8FE30BBF" + "F2660BE1" + "715A4589"
    		+ "334C74C7", 16);
    	
    	/** 坐标y */
    	private static final BigInteger yg = new BigInteger("BC3736A2" + "F4F6779C"
    		+ "59BDCEE3" + "6B692153" + "D0A9877C" + "C62A4740" + "02DF32E5"
    		+ "2139F0A0", 16);
    	
    	/** 基点G, G=(xg,yg),其介记为n */
    	private static final BigInteger n = new BigInteger("FFFFFFFE" + "FFFFFFFF"
    			+ "FFFFFFFF" + "FFFFFFFF" + "7203DF6B" + "21C6052B" + "53BBF409"
    			+ "39D54123", 16);
    	
    	private static SecureRandom random = new SecureRandom();
    	private ECCurve.Fp curve;
    	private ECPoint G;
     
    	public static String printHexString(byte[] b) {
    		StringBuilder builder = new StringBuilder();
    		for (int i = 0; i < b.length; i++) {
    			String hex = Integer.toHexString(b[i] & 0xFF);
    			if (hex.length() == 1) {
    				builder.append('0'+hex);
    			hex = '0' + hex;
    		}
    	//			System.out.print(hex.toUpperCase());
    			System.out.print(hex.toUpperCase());
    			builder.append(hex);
    		}
    		System.out.println();
    		return builder.toString();
    	}
     
    	public 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;
    	}
     
    	private boolean allZero(byte[] buffer) {
    		for (int i = 0; i < buffer.length; i++) {
    			if (buffer[i] != 0)
    			return false;
    		}
    		return true;
    	}
     
    	/**
    	 * 加密
    	 * @param input 待加密消息M
    	 * @param publicKey 公钥
    	 * @return byte[] 加密后的字节数组
    	 */
    	public byte[] encrypt(String input, ECPoint publicKey) {
    		
    		System.out.println("publicKey is: "+publicKey);
    	
    		byte[] inputBuffer = input.getBytes();
    		printHexString(inputBuffer);
    	
    		/* 1 产生随机数k,k属于[1, n-1] */
    		BigInteger k = random(n);
    		System.out.print("k: ");
    		printHexString(k.toByteArray());
    	
    		/* 2 计算椭圆曲线点C1 = [k]G = (x1, y1) */
    		ECPoint C1 = G.multiply(k);
    		byte[] C1Buffer = C1.getEncoded(false);
    		System.out.print("C1: ");
    		printHexString(C1Buffer);
    		
    		// 3 计算椭圆曲线点 S = [h]Pb * curve没有指定余因子,h为空
    		 
    	//			 BigInteger h = curve.getCofactor(); System.out.print("h: ");
    	//			 printHexString(h.toByteArray()); if (publicKey != null) { ECPoint
    	//			 result = publicKey.multiply(h); if (!result.isInfinity()) {
    	//			 System.out.println("pass"); } else {
    	//			System.err.println("计算椭圆曲线点 S = [h]Pb失败"); return null; } }
    	
    		/* 4 计算 [k]PB = (x2, y2) */
    		ECPoint kpb = publicKey.multiply(k).normalize();
    	
    		/* 5 计算 t = KDF(x2||y2, klen) */
    		byte[] kpbBytes = kpb.getEncoded(false);
    		DerivationFunction kdf = new KDF1BytesGenerator(new ShortenedDigest(
    		new SHA256Digest(), 20));
    		byte[] t = new byte[inputBuffer.length];
    		kdf.init(new ISO18033KDFParameters(kpbBytes));
    		kdf.generateBytes(t, 0, t.length);
    	
    		if (allZero(t)) {
    		System.err.println("all zero");
    		}
    	
    		/* 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 = calculateHash(kpb.getXCoord().toBigInteger(), inputBuffer,
    		kpb.getYCoord().toBigInteger());
    	
    		/* 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);
    	
    		System.out.print("密文: ");
    		printHexString(encryptResult);
     
    		return encryptResult;
    	}
     
    	public void decrypt(byte[] encryptData, BigInteger privateKey) {
    		System.out.println("privateKey is: "+privateKey);
    		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();
    	
    		/* 计算[dB]C1 = (x2, y2) */
    		ECPoint dBC1 = C1.multiply(privateKey).normalize();
    	
    		/* 计算t = KDF(x2 || y2, klen) */
    		byte[] dBC1Bytes = dBC1.getEncoded(false);
    		DerivationFunction kdf = new KDF1BytesGenerator(new ShortenedDigest(
    		new SHA256Digest(), 20));
    	
    		int klen = encryptData.length - 65 - 20;
    		System.out.println("klen = " + klen);
    	
    		byte[] t = new byte[klen];
    		kdf.init(new ISO18033KDFParameters(dBC1Bytes));
    		kdf.generateBytes(t, 0, t.length);
    	
    		if (allZero(t)) {
    			System.err.println("all zero");
    		}
    	
    		/* 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]);
    		}
    	
    		/* 6 计算 u = Hash(x2 || M' || y2) 判断 u == C3是否成立 */
    		byte[] C3 = new byte[20];
    		System.arraycopy(encryptData, encryptData.length - 20, C3, 0, 20);
    		byte[] u = calculateHash(dBC1.getXCoord().toBigInteger(), M, dBC1
    		.getYCoord().toBigInteger());
    		if (Arrays.equals(u, C3)) {
    			System.out.println("解密成功");
    			System.out.println("M' = " + new String(M));
    		} else {
    			System.out.print("u = ");
    			printHexString(u);
    			System.out.print("C3 = ");
    			printHexString(C3);
    			System.err.println("解密验证失败");
    		}
    	}
     
    	private byte[] calculateHash(BigInteger x2, byte[] M, BigInteger y2) {
    		ShortenedDigest digest = new ShortenedDigest(new SHA256Digest(), 20);
    		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[20];
    		digest.doFinal(buf, 0);
    		return buf;
    	}
     
    	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 boolean true或false
    	 */
    	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);
    				System.out.println("xResult: " + xResult.toString());
    				BigInteger yResult = y.pow(2).mod(p);
    				System.out.println("yResult: " + yResult.toString());
    				if (yResult.equals(xResult) && publicKey.multiply(n).isInfinity()) {
    					return true;
    				}
    			}
    			return false;
    		} else {
    			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())) {
    			System.out.println("generate key successfully");
    			return keyPair;
    		} else {
    			System.err.println("generate key failed");
    			return null;
    		}
    	}
     
    	public SM2Util() {
    		curve = new ECCurve.Fp(p, // q
    		a, // a
    		b); // b
    		G = curve.createPoint(xg, yg);
    	}
    	
    }
    

      

     
    import java.math.BigInteger;
     
    import org.bouncycastle.math.ec.ECPoint;
     
    /**
     * 	 <B>说	明<B/>:SM2公私钥实体类
     */
    public class SM2KeyPair {
    	
    	/** 公钥 */
    	private  ECPoint publicKey;
    	
    	/** 私钥 */
    	private BigInteger privateKey;
     
    	SM2KeyPair(ECPoint publicKey, BigInteger privateKey) {
    		this.publicKey = publicKey;
    		this.privateKey = privateKey;
    	}
     
    	public ECPoint getPublicKey() {
    		return publicKey;
    	}
     
    	public BigInteger getPrivateKey() {
    		return privateKey;
    	}
    	
    }
    

      

     
    import java.util.Arrays;
     
    /**
     * 	 <B>说	明<B/>:SM2非对称加解密工具类测试
     */
    public class SM2UtilTest {
     
    	/** 元消息串 */
    	private static String M = "哈哈哈,&*&…………&、、//\!@#$%^&*()物品woyebuzhidaowozijiqiaodesha!@#$%^&*())))))ooooooooppppppppppppppppppplllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkffffffffffffffffffffffffffffffffffffff";
    	
    	public static void main(String[] args) {
    		SM2Util sm2 = new SM2Util();
    		SM2KeyPair keyPair = sm2.generateKeyPair();
    		byte[] data = sm2.encrypt(M,keyPair.getPublicKey());
    		System.out.println("data is:"+Arrays.toString(data));
    		sm2.decrypt(data, keyPair.getPrivateKey());//71017045908707391874054405929626258767106914144911649587813342322113806533034
    	}
    	
    }
    

      

  • 相关阅读:
    editplus 支持lua语言语法高亮显示
    云服务器使用: 域名备案
    2-使用git管理一个单片机程序
    1-git的安装和基本使用
    编译lua固件NodeMcu 8266
    linux 安装Apache服务器
    2-STM32物联网开发WIFI(ESP8266)+GPRS(Air202)系统方案安全篇(监听Wi-Fi和APP的数据)
    Spring源码学习之:ClassLoader学习(3)
    Spring源码学习之:ClassLoader学习(2)
    Spring源码学习之:ClassLoader学习(1)
  • 原文地址:https://www.cnblogs.com/wangjintao-0623/p/10457596.html
Copyright © 2020-2023  润新知