package com.lysj.property.core.util.sm;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Arrays;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
/**
* SM2公钥加密算法实现 包括 -签名,验签 -密钥交换 -公钥加密,私钥解密
*
* @author Potato
*
*/
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
评论4