package com.whyc.encryption;
|
|
import org.bouncycastle.crypto.params.ECDomainParameters;
|
import org.bouncycastle.math.ec.ECCurve;
|
import org.bouncycastle.math.ec.ECPoint;
|
import org.springframework.core.io.ClassPathResource;
|
|
import java.io.*;
|
import java.math.BigInteger;
|
import java.security.SecureRandom;
|
import java.util.Arrays;
|
|
/**
|
* 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;
|
|
static {
|
curve = new ECCurve.Fp(p, // q
|
a, // a
|
b); // b
|
G = curve.createPoint(gx, gy);
|
ecc_bc_spec = new ECDomainParameters(curve, G, n);
|
}
|
|
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);
|
FileOutputStream fos=null;
|
try {
|
if (!file.exists())
|
file.createNewFile();
|
byte buffer[] = publicKey.getEncoded(false);
|
fos = new FileOutputStream(file);
|
fos.write(buffer);
|
} catch (IOException e) {
|
e.printStackTrace();
|
}finally {
|
if(fos!=null){
|
try {
|
fos.close();
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
}
|
}
|
}
|
|
/**
|
* 从本地导入公�?
|
*
|
* @param path
|
* @return
|
*/
|
public ECPoint importPublicKey(String path) {
|
File file = new File(path);
|
FileInputStream fis =null;
|
ECPoint ec=null;
|
try {
|
if (!file.exists())
|
return null;
|
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);
|
}
|
ec=curve.decodePoint(baos.toByteArray());
|
} catch (IOException e) {
|
e.printStackTrace();
|
}finally {
|
if(fis!=null){
|
try {
|
fis.close();
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
}
|
}
|
return ec;
|
}
|
|
/**
|
* 导出私钥到本�?
|
*
|
* @param privateKey
|
* @param path
|
*/
|
public void exportPrivateKey(BigInteger privateKey, String path) {
|
File file = new File(path);
|
ObjectOutputStream oos =null;
|
try {
|
if (!file.exists())
|
file.createNewFile();
|
oos = new ObjectOutputStream(new FileOutputStream(file));
|
oos.writeObject(privateKey);
|
|
} catch (IOException e) {
|
e.printStackTrace();
|
}finally {
|
if(oos!=null){
|
try {
|
oos.close();
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
}
|
}
|
}
|
|
/**
|
* 从本地导入私�?
|
*
|
* @param path
|
* @return
|
*/
|
public BigInteger importPrivateKey(String path) {
|
File file = new File(path);
|
FileInputStream fis =null;
|
ObjectInputStream ois =null;
|
BigInteger res =null;
|
try {
|
if (!file.exists()) {
|
return null;
|
}
|
fis = new FileInputStream(file);
|
ois = new ObjectInputStream(fis);
|
res = (BigInteger) (ois.readObject());
|
} catch (Exception e) {
|
e.printStackTrace();
|
}finally {
|
if(fis!=null){
|
try {
|
fis.close();
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
}
|
if(ois!=null){
|
try {
|
ois.close();
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
}
|
}
|
return res;
|
}
|
|
/**
|
* 字节数组拼接
|
*
|
* @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 密钥确认失败");
|
}
|
}
|
|
/**
|
* 获取私钥
|
* @return
|
*/
|
public static BigInteger getPrivateKey(){
|
ClassPathResource classPathResource = new ClassPathResource("/config/pri_key.ksm");
|
InputStream inputStream = null;
|
BigInteger res=null;
|
ObjectInputStream ois=null;
|
try {
|
inputStream = classPathResource.getInputStream();
|
ois = new ObjectInputStream(inputStream);
|
res = (BigInteger) (ois.readObject());
|
} catch (IOException | ClassNotFoundException e) {
|
e.printStackTrace();
|
}finally {
|
if(inputStream!=null){
|
try {
|
inputStream.close();
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
}
|
if(ois!=null){
|
try {
|
ois.close();
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
}
|
}
|
return res;
|
}
|
|
/**
|
* 获取公钥
|
* @return
|
*/
|
public static ECPoint getPublicKey(){
|
try {
|
ClassPathResource classPathResource = new ClassPathResource("/config/pub_key.ksm");
|
InputStream inputStream = classPathResource.getInputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
byte buffer[] = new byte[16];
|
int size;
|
while ((size = inputStream.read(buffer)) != -1) {
|
baos.write(buffer, 0, size);
|
}
|
inputStream.close();
|
return curve.decodePoint(baos.toByteArray());
|
}catch (IOException e) {
|
e.printStackTrace();
|
return null;
|
}
|
}
|
|
public static void main(String[] args) throws UnsupportedEncodingException {
|
|
SM2 sm02 = new SM2();
|
//BigInteger privateKey = sm02.importPrivateKey(ClassUtils.getDefaultClassLoader().getResource("").getPath() + "config/pri_key.ksm");
|
//ECPoint publicKey = sm02.importPublicKey(ClassUtils.getDefaultClassLoader().getResource("").getPath() + "config/pri_key.ksm");
|
|
BigInteger privateKey2 = sm02.getPrivateKey();
|
privateKey2 = privateKey2.add(new BigInteger("1"));
|
ECPoint publicKey2 = sm02.getPublicKey();
|
|
byte[] encrypt = sm02.encrypt("123456", publicKey2);
|
String decrypt = sm02.decrypt(encrypt, privateKey2);
|
System.out.println(decrypt);
|
//System.out.println(privateKey);
|
//System.out.println(publicKey);
|
|
//System.out.println(privateKey2);
|
//System.out.println(publicKey2);
|
/*
|
BigInteger px = new BigInteger(
|
"0AE4C779 8AA0F119 471BEE11 825BE462 02BB79E2 A5844495 E97C04FF 4DF2548A".replace(" ", ""), 16);
|
BigInteger py = new BigInteger(
|
"7C0240F8 8F1CD4E1 6352A73C 17B7F16F 07353E53 A176D684 A9FE0C6B B798E857".replace(" ", ""), 16);
|
ECPoint publicKey = sm02.curve.createPoint(px, py);
|
BigInteger privateKey = new BigInteger(
|
"128B2FA8 BD433C6C 068C8D80 3DFF7979 2A519A55 171B1B65 0C23661D 15897263".replace(" ", ""), 16);
|
*/
|
/*SM2KeyPair keyPair = sm02.generateKeyPair();
|
ECPoint publicKey=keyPair.getPublicKey();
|
BigInteger privateKey=keyPair.getPrivateKey();
|
sm02.exportPublicKey(publicKey, "E:/publickey.pem");
|
sm02.exportPrivateKey(privateKey, "E:/privatekey.pem");
|
|
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);
|
}
|
}
|
}
|