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
} }
SM2的非对称加解密java工具类的更多相关文章
- 对Java配置文件中敏感信息进行加解密的工具类
在 JavaEE 配置文件中,例如 XML 或者 properties 文件,由于某些敏感信息不希望普通人员看见,则可以采用加密的方式存储,程序读取后进行解密. 常见的如: 数据库用户密码,短信平台用 ...
- Rsa加解密Java、C#、php通用代码 密钥转换工具
之前发了一篇"TripleDes的加解密Java.C#.php通用代码",后面又有项目用到了Rsa加解密,还是在不同系统之间进行交互,Rsa在不同语言的密钥格式不一样,所以过程中主 ...
- php rsa 非对称加解密类
<?php header("Content-Type: text/html;charset=utf-8"); /* 生成公钥.私钥对,私钥加密的内容能通过公钥解密(反过来亦可 ...
- Java工具类—包装类
Java工具类--包装类 我们都知道,JDK 其实给我们提供了很多很多 Java 开发者已经写好的现成的类,他们其实都可以理解成工具类,比如我们常见的集合类,日期相关的类,数学相关的类等等,有了这些工 ...
- Java工具类——数学相关的类
Java工具类--数学相关的类 在上一篇文章中,我们系统学习了 Java 里面的包装类,那么这篇文章,我们就来学习一下Java提供好的类--数学相关的类. 一.数学类介绍 在最早期学习 Java 基础 ...
- Java工具类之:包装类
Java工具类--包装类 我们都知道,JDK 其实给我们提供了很多很多 Java 开发者已经写好的现成的类,他们其实都可以理解成工具类,比如我们常见的集合类,日期相关的类,数学相关的类等等,有了这些工 ...
- 非对称加解密 Asymmetric encryption 对称加密和非对称加密的区别
考虑这样一个问题:一切的装备文件都存储在 Git 长途库房,RAR密码破解装备文件中的一些信息又是比较灵敏的.所以,我们需求对这些灵敏信息进行加密处理.首要的加密方法分为两种:一种是同享密钥加 密(对 ...
- java工具类系列 (四.SerializationUtils)
java工具类系列 (四.SerializationUtils) SerializationUtils该类为序列化工具类,也是lang包下的工具,主要用于序列化操作 import java.io.Se ...
- Java工具类——通过配置XML验证Map
Java工具类--通过配置XML验证Map 背景 在JavaWeb项目中,接收前端过来的参数时通常是使用我们的实体类进行接收的.但是呢,我们不能去决定已经搭建好的框架是怎么样的,在我接触的框架中有一种 ...
随机推荐
- SEO笔记:构建URL的15个SEO最佳实践
By: Rand Fishkin 原文链接:https://moz.com/blog/15-seo-best-practices-for-structuring-urls #1: Whenever p ...
- 妙用Excel数据透视表和透视图向导,将二维数据转换为一维数据
项目中,每年都会有各种经销商的各种产品目标数据导入,经销商和产品过多,手工操作过于单调和复杂.那有没有一种方式可以将复杂的二维数据转换为一维数据呢? 有,强大的Excel就支持此功能. 常用Excel ...
- 分布式session的管理
在分布式架构或微服务架构下,必须保证一个应用服务器上保存Session后,其它应用服务器可以同步或共享这个Session,可能会出现在A1系统登录后创建并保存Session,再次发起请求,请求被转发到 ...
- Vue学习笔记之Nodejs中的NPM使用
0x00 NPM是什么 简单的说,npm就是JavaScript的包管理工具.类似Java语法中的maven,gradle,python中的pip. 0x01 NPM安装 傻瓜式的安装. 第一步:打开 ...
- linux内核分析第三周-跟踪分析Linux内核的启动过程
一.实验流程 1.打开环境 执行命令:cd LinuxKernel/ 执行命令:qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd root ...
- Spring Data JPA 关系映射(一对一,一对多,多对多 )
CascadeType.REMOVE 级联删除操作,删除当前实体时,与它有映射关系的实体也会跟着被删除.CascadeType.MERGE 级联更新(合并)操作,当Student中的数据改变,会相应地 ...
- 一些常用的JavaScript正则表达式
1.正数,最多n位小数 /^(([1-9]\d*(\.\d{1,n})?)|(0\.\d{1,n}))$/ 2.手机号码 /^1[34578]\d{9}$/
- Linux中重定向--转载
转:http://blog.csdn.net/songyang516/article/details/6758256 1重定向 1.1 重定向符号 > 输出 ...
- shell 交互式选择(select)
新建文件 sudo vi test.sh 写入如下内容: #!/bin/bash echo "What is your favourite OS?" select var in & ...
- python 生成zip压缩包
import zipfile file_name="a.txt" f = zipfile.ZipFile('test.zip','w',zipfile.ZIP_STORED) f. ...