代码
package com.example.demo.MIMAXUE.SM;
import java.io.*;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Arrays;
import org.apache.commons.io.FileUtils;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
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;
}
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();
}
private static BigInteger random(BigInteger max) {
BigInteger r = new BigInteger(256, random);
while (r.compareTo(max) >= 0) {
r = new BigInteger(128, random);
}
return r;
}
private boolean allZero(byte[] buffer) {
for (int i = 0; i < buffer.length; i++) {
if (buffer[i] != 0)
return false;
}
return true;
}
public byte[] encryptFile(ECPoint publicKey) throws IOException {
StringBuffer fileData = new StringBuffer();
BufferedReader reader = new BufferedReader(new FileReader("G:\\jjDown\\350.mp4"));
char[] buf = new char[1024];
int numRead=0;
while((numRead=reader.read(buf)) != -1){
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
}
reader.close();
byte[] result = encrypt(fileData.toString(), publicKey);
return result;
}
public byte[] encryptFile2(ECPoint publicKey) throws IOException {
StringBuffer fileData = new StringBuffer();
BufferedReader reader = new BufferedReader(new FileReader("G:\\jjDown\\0989.mp4"));
char[] buf = new char[1024];
int numRead=0;
while((numRead=reader.read(buf)) != -1){
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
}
reader.close();
byte[] result = encrypt(fileData.toString(), publicKey);
return result;
}
public byte[] encrypt(String input, ECPoint publicKey) {
byte[] inputBuffer = input.getBytes();
if (debug)
printHexString(inputBuffer);
byte[] C1Buffer;
ECPoint kpb;
byte[] t;
do {
BigInteger k = random(n);
if (debug) {
System.out.print("k: ");
printHexString(k.toByteArray());
}
ECPoint C1 = G.multiply(k);
C1Buffer = C1.getEncoded(false);
if (debug) {
System.out.print("C1: ");
printHexString(C1Buffer);
}
BigInteger h = ecc_bc_spec.getH();
if (h != null) {
ECPoint S = publicKey.multiply(h);
if (S.isInfinity())
throw new IllegalStateException();
}
kpb = publicKey.multiply(k).normalize();
byte[] kpbBytes = kpb.getEncoded(false);
t = KDF(kpbBytes, inputBuffer.length);
} while (allZero(t));
byte[] C2 = new byte[inputBuffer.length];
for (int i = 0; i < inputBuffer.length; i++) {
C2[i] = (byte) (inputBuffer[i] ^ t[i]);
}
byte[] C3 = sm3hash(kpb.getXCoord().toBigInteger().toByteArray(), inputBuffer,
kpb.getYCoord().toBigInteger().toByteArray());
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;
}
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();
BigInteger h = ecc_bc_spec.getH();
if (h != null) {
ECPoint S = C1.multiply(h);
if (S.isInfinity())
throw new IllegalStateException();
}
ECPoint dBC1 = C1.multiply(privateKey).normalize();
byte[] dBC1Bytes = dBC1.getEncoded(false);
int klen = encryptData.length - 65 - DIGEST_LENGTH;
byte[] t = KDF(dBC1Bytes, klen);
if (allZero(t)) {
System.err.println("all zero");
throw new IllegalStateException();
}
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);
byte[] C3 = new byte[DIGEST_LENGTH];
if (debug)
try {
System.out.println("M = " + new String(M, "UTF8"));
} catch (UnsupportedEncodingException e1) {
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;
}
}
private boolean between(BigInteger param, BigInteger min, BigInteger max) {
if (param.compareTo(min) >= 0 && param.compareTo(max) < 0) {
return true;
} else {
return 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);
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;
}
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,
a,
b);
G = curve.createPoint(gx, gy);
ecc_bc_spec = new ECDomainParameters(curve, G, n);
}
public SM2(boolean debug) {
this();
this.debug = debug;
}
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();
}
}
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;
}
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();
}
}
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;
}
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;
}
private static byte[] sm3hash(byte[]... params) {
byte[] res = null;
try {
res = SM3.hash(join(params));
} catch (IOException e) {
e.printStackTrace();
}
return res;
}
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;
}
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;
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);
}
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;
}
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;
}
private static class TransportEntity implements Serializable {
final byte[] R;
final byte[] 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);
}
}
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());
}
public TransportEntity keyExchange_1() {
rA = random(n);
RA = G.multiply(rA).normalize();
return new TransportEntity(RA.getEncoded(false), null,Z,keyPair.getPublicKey());
}
public TransportEntity keyExchange_2(TransportEntity entity) {
BigInteger rB = random(n);
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());
}
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());
}
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);
}
}
}
package com.example.demo.MIMAXUE.SM;
import java.math.BigInteger;
import org.bouncycastle.math.ec.ECPoint;
public class SM2KeyPair {
private final ECPoint publicKey;
private final BigInteger privateKey;
SM2KeyPair(ECPoint publicKey, BigInteger privateKey) {
this.publicKey = publicKey;
this.privateKey = privateKey;
}
public ECPoint getPublicKey() {
return publicKey;
}
public BigInteger getPrivateKey() {
return privateKey;
}
}
package com.example.demo.MIMAXUE.SM;
import org.bouncycastle.math.ec.ECPoint;
import java.io.IOException;
import java.math.BigInteger;
public class SM2Test {
public static void main(String[] args) throws IOException {
Long avgENCTime = 0L;
Long avgDecTime = 0L;
for(int i =0;i<10;i++){
SM2 sm2 = new SM2();
SM2KeyPair keys = sm2.generateKeyPair();
BigInteger privateKey = keys.getPrivateKey();
ECPoint publicKey = keys.getPublicKey();
Long startTime = System.currentTimeMillis();
byte[] encryptMessage = sm2.encryptFile(publicKey);
Long endTime = System.currentTimeMillis();
System.out.println("sm2加密花费时间" + (endTime - startTime) + "ms");
Long startTime1 = System.currentTimeMillis();
String decryptMessage = sm2.decrypt(encryptMessage, privateKey);
Long endTime1 = System.currentTimeMillis();
System.out.println("sm2解密花费时间" + (endTime1 - startTime1) + "ms");
avgENCTime+=(endTime-startTime);
avgDecTime+=(endTime1-startTime1);
}
System.out.println("********************************************************************************");
System.out.println("aes平均加密花费时间" + avgENCTime/10 + "ms");
System.out.println("aes平均加密花费时间" + avgDecTime/10 + "ms");
}
}