sm2
Version:
sm2,sm3,cryptojs,crypto,base64,rsa,aes crypt
791 lines (689 loc) • 31.5 kB
JavaScript
/**
* <p>SM2加密器</p>
*
* <p>注意:由于对象内存在buffer, 请勿多线程同时操作一个实例, 每次new一个Cipher使用, 或使用ThreadLocal保持每个线程一个Cipher实例.</p>
*
* Created by S.Violet on 2016/8/22.
*/
funciton SM2Cipher () {
/**
* SM2的ECC椭圆曲线参数
*/
// private static final BigInteger SM2_ECC_P = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16);
// private static final BigInteger SM2_ECC_A = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16);
// private static final BigInteger SM2_ECC_B = new BigInteger("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16);
// private static final BigInteger SM2_ECC_N = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16);
// private static final BigInteger SM2_ECC_GX = new BigInteger("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16);
// private static final BigInteger SM2_ECC_GY = new BigInteger("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16);
private static final BigInteger SM2_ECC_P = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16);
private static final BigInteger SM2_ECC_A = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16);
private static final BigInteger SM2_ECC_B = new BigInteger("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16);
private static final BigInteger SM2_ECC_N = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16);
private static final BigInteger SM2_ECC_GX = new BigInteger("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16);
private static final BigInteger SM2_ECC_GY = new BigInteger("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16);
//测试曲线
// private static final BigInteger SM2_ECC_P = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", 16);
// private static final BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16);
// private static final BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16);
// private static final BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16);
// private static final BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16);
// private static final BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16);
//默认用户ID(签名用)
private static final byte[] DEFAULT_USER_ID = "1234567812345678".getBytes();
private ECCurve.Fp curve;//ECC曲线
private ECPoint.Fp pointG;//基点
private ECKeyPairGenerator keyPairGenerator;//密钥对生成器
private Type type;//密文格式
private ECPoint alternateKeyPoint;
private SM3Digest alternateKeyDigest;
private SM3Digest c3Digest;
private int alternateKeyCount;
private byte alternateKey[];
private byte alternateKeyOff;
public SM2Cipher(){
this(Type.C1C3C2);
}
/**
* 默认椭圆曲线参数的SM2加密器
*
* @param type 密文格式
*/
public SM2Cipher(Type type) {
this(
new SecureRandom(),
type
);
}
/**
* 默认椭圆曲线参数的SM2加密器
*
* @param secureRandom 秘钥生成随机数
* @param type 密文格式
*/
public SM2Cipher(SecureRandom secureRandom, Type type) {
this(
secureRandom,
type,
SM2_ECC_P,
SM2_ECC_A,
SM2_ECC_B,
SM2_ECC_N,
SM2_ECC_GX,
SM2_ECC_GY
);
}
/**
* 默认椭圆曲线参数的SM2加密器
*
* @param secureRandom 秘钥生成随机数
* @param type 密文格式
* @param eccP p
* @param eccA a
* @param eccB b
* @param eccN n
* @param eccGx gx
* @param eccGy gy
*/
public SM2Cipher(SecureRandom secureRandom, Type type, BigInteger eccP, BigInteger eccA, BigInteger eccB, BigInteger eccN, BigInteger eccGx, BigInteger eccGy) {
if (type == null) {
throw new InvalidCryptoParamsException("[SM2]type of the SM2Cipher is null");
}
if (eccP == null || eccA == null || eccB == null || eccN == null || eccGx == null || eccGy == null) {
throw new InvalidCryptoParamsException("[SM2]ecc params of the SM2Cipher is null");
}
if (secureRandom == null) {
secureRandom = new SecureRandom();
}
this.type = type;
//曲线
ECFieldElement.Fp gxFieldElement = new ECFieldElement.Fp(eccP, eccGx);
ECFieldElement.Fp gyFieldElement = new ECFieldElement.Fp(eccP, eccGy);
this.curve = new ECCurve.Fp(eccP, eccA, eccB);
//密钥对生成器
this.pointG = new ECPoint.Fp(curve, gxFieldElement, gyFieldElement);
ECDomainParameters domainParams = new ECDomainParameters(curve, pointG, eccN);
ECKeyGenerationParameters keyGenerationParams = new ECKeyGenerationParameters(domainParams, secureRandom);
this.keyPairGenerator = new ECKeyPairGenerator();
this.keyPairGenerator.init(keyGenerationParams);
}
/**
* @return 产生SM2公私钥对(随机)
*/
public KeyPair generateKeyPair() {
AsymmetricCipherKeyPair keyPair = keyPairGenerator.generateKeyPair();
ECPrivateKeyParameters privateKeyParams = (ECPrivateKeyParameters) keyPair.getPrivate();
ECPublicKeyParameters publicKeyParams = (ECPublicKeyParameters) keyPair.getPublic();
BigInteger privateKey = privateKeyParams.getD();
ECPoint publicKey = publicKeyParams.getQ();
return new KeyPair(privateKey.toByteArray(), publicKey.getEncoded());
}
/**
* SM2加密
*
* @param publicKey 公钥
* @param data 数据
*/
public byte[] encrypt(byte[] publicKey, byte[] data) throws InvalidKeyDataException {
EncryptedData encryptedData = encryptInner(publicKey, data);
if (encryptedData == null) {
return null;
}
byte[] c1 = encryptedData.c1.getEncoded();
byte[] c2 = encryptedData.c2;
byte[] c3 = encryptedData.c3;
//拼凑结果
byte[] result = new byte[97 + c2.length];
switch (type) {
case C1C2C3:
System.arraycopy(c1, 0, result, 0, 65);//C1:Point, 标志位1byte, 数据64byte
System.arraycopy(c2, 0, result, 65, c2.length);//C2:加密数据
System.arraycopy(c3, 0, result, 65 + c2.length, 32);//C3:摘要 32byte
break;
case C1C3C2:
System.arraycopy(c1, 0, result, 0, 65);//C1:Point, 标志位1byte, 数据64byte
System.arraycopy(c3, 0, result, 65, 32);//C3:摘要 32byte
System.arraycopy(c2, 0, result, 97, c2.length);//C2:加密数据
break;
default:
throw new InvalidCryptoParamsException("[SM2:Encrypt]invalid type(" + String.valueOf(type) + ")");
}
return result;
}
/**
* SM2加密, ASN.1编码
*
* @param publicKey 公钥
* @param data 数据
*/
public byte[] encryptToASN1(byte[] publicKey, byte[] data) throws InvalidCryptoDataException, InvalidKeyDataException {
EncryptedData encryptedData = encryptInner(publicKey, data);
if (encryptedData == null) {
return null;
}
ECPoint c1 = encryptedData.c1;
byte[] c2 = encryptedData.c2;
byte[] c3 = encryptedData.c3;
DERInteger x = new DERInteger(c1.getX().toBigInteger());
DERInteger y = new DERInteger(c1.getY().toBigInteger());
DEROctetString derC2 = new DEROctetString(c2);
DEROctetString derC3 = new DEROctetString(c3);
ASN1EncodableVector vector = new ASN1EncodableVector();
vector.add(x);
vector.add(y);
switch (type) {
case C1C2C3:
vector.add(derC2);
vector.add(derC3);
break;
case C1C3C2:
vector.add(derC3);
vector.add(derC2);
break;
default:
throw new InvalidCryptoParamsException("[SM2:EncryptASN1]invalid type(" + String.valueOf(type) + ")");
}
DERSequence seq = new DERSequence(vector);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
DEROutputStream derOutputStream = new DEROutputStream(byteArrayOutputStream);
try {
derOutputStream.writeObject(seq);
} catch (IOException e) {
throw new InvalidCryptoDataException("[SM2:encrypt:ASN1]error while parse encrypted data to ASN.1", e);
}
return byteArrayOutputStream.toByteArray();
}
private EncryptedData encryptInner(byte[] publicKey, byte[] data) throws InvalidKeyDataException {
if (publicKey == null || publicKey.length == 0) {
throw new InvalidCryptoParamsException("[SM2:Encrypt]key is null");
}
if (data == null || data.length == 0) {
return null;
}
//C2位数据域
byte[] c2 = new byte[data.length];
System.arraycopy(data, 0, c2, 0, data.length);
ECPoint keyPoint;
try {
keyPoint = curve.decodePoint(publicKey);
} catch (Exception e) {
throw new InvalidKeyDataException("[SM2:Encrypt]invalid key data(format)", e);
}
AsymmetricCipherKeyPair generatedKey = keyPairGenerator.generateKeyPair();
ECPrivateKeyParameters privateKeyParams = (ECPrivateKeyParameters) generatedKey.getPrivate();
ECPublicKeyParameters publicKeyParams = (ECPublicKeyParameters) generatedKey.getPublic();
BigInteger privateKey = privateKeyParams.getD();
ECPoint c1 = publicKeyParams.getQ();
this.alternateKeyPoint = keyPoint.multiply(privateKey);
reset();
this.c3Digest.update(c2);
for (int i = 0; i < c2.length; i++) {
if (alternateKeyOff >= alternateKey.length) {
nextKey();
}
c2[i] ^= alternateKey[alternateKeyOff++];
}
byte p[] = CommonUtils.byteConvert32Bytes(alternateKeyPoint.getY().toBigInteger());
this.c3Digest.update(p);
byte[] c3 = this.c3Digest.doFinal();
reset();
return new EncryptedData(c1, c2, c3);
}
/**
* SM2解密
*
* @param privateKey 私钥
* @param data 数据
*/
public byte[] decrypt(byte[] privateKey, byte[] data) throws InvalidKeyException, InvalidCryptoDataException {
if (data == null || data.length == 0) {
return null;
}
if (data.length <= 97) {
throw new InvalidCryptoDataException("[SM2:Decrypt]invalid encrypt data, length <= 97 bytes");
}
byte[] c1 = new byte[65];
byte[] c2 = new byte[data.length - 97];
byte[] c3 = new byte[32];
switch (type) {
case C1C2C3:
System.arraycopy(data, 0, c1, 0, c1.length);//C1:Point, 标志位1byte, 数据64byte
System.arraycopy(data, c1.length, c2, 0, c2.length);//C2:加密数据
System.arraycopy(data, c1.length + c2.length, c3, 0, c3.length);//C3:摘要 32byte
break;
case C1C3C2:
System.arraycopy(data, 0, c1, 0, c1.length);//C1:Point, 标志位1byte, 数据64byte
System.arraycopy(data, c1.length, c3, 0, c3.length);//C3:摘要 32byte
System.arraycopy(data, c1.length + c3.length, c2, 0, c2.length);//C2:加密数据
break;
default:
throw new InvalidCryptoParamsException("[SM2:Decrypt]invalid type(" + String.valueOf(type) + ")");
}
return decryptInner(privateKey, c1, c2, c3);
}
/**
* SM2解密, ASN.1编码
*
* @param privateKey 私钥
* @param data 数据
*/
public byte[] decryptFromASN1(byte[] privateKey, byte[] data) throws InvalidKeyException, InvalidCryptoDataException {
if (data == null || data.length == 0) {
return null;
}
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data);
ASN1InputStream asn1InputStream = new ASN1InputStream(byteArrayInputStream);
DERObject derObj;
try {
derObj = asn1InputStream.readObject();
} catch (IOException e) {
throw new InvalidCryptoDataException("[SM2:decrypt:ASN1]invalid encrypted data", e);
}
ASN1Sequence asn1 = (ASN1Sequence) derObj;
DERInteger x = (DERInteger) asn1.getObjectAt(0);
DERInteger y = (DERInteger) asn1.getObjectAt(1);
ECPoint c1;
try {
c1 = curve.createPoint(x.getValue(), y.getValue(), true);
} catch (Exception e) {
throw new InvalidCryptoDataException("[SM2:decrypt:ASN1]invalid encrypted data, c1", e);
}
byte[] c2;
byte[] c3;
switch (type) {
case C1C2C3:
c2 = ((DEROctetString) asn1.getObjectAt(2)).getOctets();
c3 = ((DEROctetString) asn1.getObjectAt(3)).getOctets();
break;
case C1C3C2:
c3 = ((DEROctetString) asn1.getObjectAt(2)).getOctets();
c2 = ((DEROctetString) asn1.getObjectAt(3)).getOctets();
break;
default:
throw new InvalidCryptoParamsException("[SM2:Decrypt:ASN1]invalid type(" + String.valueOf(type) + ")");
}
return decryptInner(privateKey, c1.getEncoded(), c2, c3);
}
private byte[] decryptInner(byte[] privateKey, byte[] c1, byte[] c2, byte[] c3) throws InvalidKeyException, InvalidCryptoDataException {
if (privateKey == null || privateKey.length == 0) {
throw new InvalidCryptoParamsException("[SM2:Decrypt]key is null");
}
if (c1 == null || c1.length <= 0 || c2 == null || c2.length <= 0 || c3 == null || c3.length <= 0) {
throw new InvalidCryptoDataException("[SM2:Decrypt]invalid encrypt data, c1 / c2 / c3 is null or empty");
}
BigInteger decryptKey = new BigInteger(1, privateKey);
ECPoint c1Point;
try {
c1Point = curve.decodePoint(c1);
} catch (Exception e) {
throw new InvalidCryptoDataException("[SM2:Decrypt]invalid encrypt data, c1 invalid", e);
}
this.alternateKeyPoint = c1Point.multiply(decryptKey);
reset();
for (int i = 0; i < c2.length; i++) {
if (alternateKeyOff >= alternateKey.length) {
nextKey();
}
c2[i] ^= alternateKey[alternateKeyOff++];
}
this.c3Digest.update(c2, 0, c2.length);
byte p[] = CommonUtils.byteConvert32Bytes(alternateKeyPoint.getY().toBigInteger());
this.c3Digest.update(p, 0, p.length);
byte[] verifyC3 = this.c3Digest.doFinal();
// if (!Arrays.equals(verifyC3, c3)) {
// throw new InvalidKeyException("[SM2:Decrypt]invalid key, c3 is not match");
// }
reset();
//返回解密结果
return c2;
}
private void reset() {
this.alternateKeyDigest = new SM3Digest();
this.c3Digest = new SM3Digest();
byte p[] = CommonUtils.byteConvert32Bytes(alternateKeyPoint.getX().toBigInteger());
this.alternateKeyDigest.update(p);
this.c3Digest.update(p, 0, p.length);
p = CommonUtils.byteConvert32Bytes(alternateKeyPoint.getY().toBigInteger());
this.alternateKeyDigest.update(p);
this.alternateKeyCount = 1;
nextKey();
}
private void nextKey() {
SM3Digest digest = new SM3Digest(this.alternateKeyDigest);
digest.update((byte) (alternateKeyCount >> 24 & 0xff));
digest.update((byte) (alternateKeyCount >> 16 & 0xff));
digest.update((byte) (alternateKeyCount >> 8 & 0xff));
digest.update((byte) (alternateKeyCount & 0xff));
alternateKey = digest.doFinal();
this.alternateKeyOff = 0;
this.alternateKeyCount++;
}
/**
* 签名
*
* @param userId 用户ID
* @param privateKey 私钥
* @param sourceData 数据
* @return 签名数据{r, s}
*/
public BigInteger[] sign(byte[] userId, byte[] privateKey, byte[] sourceData) {
if (privateKey == null || privateKey.length == 0) {
throw new InvalidCryptoParamsException("[SM2:sign]key is null");
}
if (sourceData == null || sourceData.length == 0) {
return null;
}
//私钥, 私钥和基点生成秘钥点
BigInteger key = new BigInteger(privateKey);
ECPoint keyPoint = pointG.multiply(key);
//Z
SM3Digest digest = new SM3Digest();
byte[] z = getZ(userId, keyPoint);
//对数据做摘要
digest.update(z, 0, z.length);
digest.update(sourceData);
byte[] digestData = digest.doFinal();
//签名数据{r, s}
return signInner(digestData, key, keyPoint);
}
/**
* 签名, 输出(r + s)格式的标准签名
*
* @param userId 用户ID
* @param privateKey 私钥
* @param sourceData 数据
* @return 签名数据{r, s}
*/
public byte[] signToBytes(byte[] userId, byte[] privateKey, byte[] sourceData) {
BigInteger[] rs = sign(userId, privateKey, sourceData);
byte[] signData = new byte[64];//32bytes r, 32bytes s
byte[] rBytes = rs[0].toByteArray();//出来不一定是32byte, 而且可能前面带0x00
byte[] sBytes = rs[1].toByteArray();//出来不一定是32byte, 而且可能前面带0x00
System.arraycopy(
rBytes,
rBytes.length > 32 ? rBytes.length - 32 : 0,
signData,
rBytes.length >= 32 ? 0 : 32 - rBytes.length,
rBytes.length >= 32 ? 32 : rBytes.length);
System.arraycopy(
sBytes,
sBytes.length > 32 ? sBytes.length - 32 : 0,
signData,
sBytes.length >= 32 ? 32 : 32 + (32 - sBytes.length),
sBytes.length >= 32 ? 32 : sBytes.length);
return signData;
}
/**
* 签名(ASN.1编码)
*
* @param userId 用户ID
* @param privateKey 私钥
* @param sourceData 数据
* @return 签名数据 byte[] ASN.1编码
*/
public byte[] signToASN1(byte[] userId, byte[] privateKey, byte[] sourceData) {
BigInteger[] signData = sign(userId, privateKey, sourceData);
//签名数据序列化
DERInteger derR = new DERInteger(signData[0]);//r
DERInteger derS = new DERInteger(signData[1]);//s
ASN1EncodableVector vector = new ASN1EncodableVector();
vector.add(derR);
vector.add(derS);
DERObject sign = new DERSequence(vector);
return sign.getDEREncoded();
}
/**
* 验签
*
* @param userId 用户ID
* @param publicKey 公钥
* @param sourceData 数据
* @param signR 签名数据r
* @param signS 签名数据s
* @return true:签名有效
*/
public boolean verifySign(byte[] userId, byte[] publicKey, byte[] sourceData, BigInteger signR, BigInteger signS) throws InvalidKeyDataException {
if (publicKey == null || publicKey.length == 0) {
throw new InvalidCryptoParamsException("[SM2:verifySign]key is null");
}
if (sourceData == null || sourceData.length == 0 || signR == null || signS == null) {
return false;
}
//公钥
ECPoint key;
try {
key = curve.decodePoint(publicKey);
} catch (Exception e) {
throw new InvalidKeyDataException("[SM2:verifySign]invalid public key (format)", e);
}
//Z
SM3Digest digest = new SM3Digest();
byte[] z = getZ(userId, key);
//对数据摘要
digest.update(z, 0, z.length);
digest.update(sourceData, 0, sourceData.length);
byte[] digestData = digest.doFinal();
//验签
return signR.equals(verifyInner(digestData, key, signR, signS));
}
/**
* 验签, (r + s)格式的标准签名
*
* @param userId 用户ID
* @param publicKey 公钥
* @param sourceData 数据
* @param signData 签名数据, r + s格式的标准签名
* @return true 签名有效
* @throws InvalidSignDataException ASN.1编码无效
*/
public boolean verifySignByBytes(byte[] userId, byte[] publicKey, byte[] sourceData, byte[] signData) throws InvalidSignDataException, InvalidKeyDataException {
if (signData == null || signData.length != 64) {
throw new InvalidSignDataException("[SM2:verifySignByBytes]invalid sign data, length is not 64 bytes (r + s)");
}
byte[] rBytes = new byte[32];
byte[] sBytes = new byte[32];
System.arraycopy(signData, 0, rBytes, 0, 32);
System.arraycopy(signData, 32, sBytes, 0, 32);
BigInteger r;
BigInteger s;
try {
r = new BigInteger(1, rBytes);
s = new BigInteger(1, sBytes);
} catch (Exception e) {
throw new InvalidSignDataException("[SM2:verifySignByBytes]invalid sign data, can not parse to r and s (BigInteger)");
}
return verifySign(userId, publicKey, sourceData, r, s);
}
/**
* 验签(ASN.1编码签名)
*
* @param userId 用户ID
* @param publicKey 公钥
* @param sourceData 数据
* @param signData 签名数据(ASN.1编码)
* @return true 签名有效
* @throws InvalidSignDataException ASN.1编码无效
*/
public boolean verifySignByASN1(byte[] userId, byte[] publicKey, byte[] sourceData, byte[] signData) throws InvalidSignDataException, InvalidKeyDataException {
byte[] _signData = signData;
//过滤头部的0x00
int startIndex = 0;
for (int i = 0 ; i < signData.length ; i++){
if (signData[i] != 0x00){
break;
}
startIndex++;
}
if (startIndex > 0){
_signData = new byte[signData.length - startIndex];
System.arraycopy(signData, startIndex, _signData, 0, _signData.length);
}
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(_signData);
ASN1InputStream asn1InputStream = new ASN1InputStream(byteArrayInputStream);
Enumeration<DERInteger> signObj;
try {
DERObject derObj = asn1InputStream.readObject();
signObj = ((ASN1Sequence) derObj).getObjects();
} catch (IOException e) {
throw new InvalidSignDataException("[SM2:verifySign]invalid sign data (ASN.1)", e);
}
BigInteger r = signObj.nextElement().getValue();
BigInteger s = signObj.nextElement().getValue();
//验签
return verifySign(userId, publicKey, sourceData, r, s);
}
/**
* <p>使用X509证书中的主体公钥进行验签</p>
* <p>
* <p>注意:本方法不验证证书本身的合法性, 需要自行验证; 本方法不验证证书实体公钥的算法标识;</p>
*
* @param certData X509证书数据(ASN.1, 非Base64)
* @param sourceData 数据
* @param signData 签名(r + s)
* @return true:签名合法
*/
public boolean verifySignByX509Cert(byte[] certData, byte[] sourceData, byte[] signData) throws InvalidCertificateException, InvalidSignDataException, InvalidKeyDataException {
byte[] publicKey = null;
try {
X509CertificateStructure cert = CertificateUtils.parseX509(certData);
SubjectPublicKeyInfo publicInfo = cert.getSubjectPublicKeyInfo();
publicKey = publicInfo.getPublicKeyData().getBytes();
} catch (Exception e) {
throw new InvalidCertificateException("[SM2:verifySignByX509Cert]illegal cert", e);
}
if (publicKey == null) {
throw new InvalidCertificateException("[SM2:verifySignByX509Cert]null public key in cert");
}
if (publicKey.length != 65) {
throw new InvalidCertificateException("[SM2:verifySignByX509Cert]illegal public key in cert, length is not 65 bytes (0x04 + x + y)");
}
return verifySignByBytes(null, publicKey, sourceData, signData);
}
/**
* 根据公钥验证证书的合法性
* @param certData X509证书数据(ASN.1, 非Base64, TLV数据格式)
* @param publicKey 公钥
* @return true:合法
*/
public boolean verifyCertByPublicKey(byte[] certData, byte[] publicKey) throws IOException, IllegalPbocTlvFormatException, InvalidSignDataException, InvalidKeyDataException {
PbocTlvElement root = PbocTlvParser.parse(certData);
List<PbocTlvElement> elements = root.getSubElements();
if (elements == null || elements.size() != 3){
throw new IOException("illegal cert, it must have 3 tags, cert info / flag / sign");
}
//被签名数据
PbocTlvElement certContentElement = elements.get(0);
byte[] certContentTag = certContentElement.getTag();//tag
byte[] certContentLength = certContentElement.getLength();//length
byte[] certContentValue = certContentElement.getValue();//value
if (certContentValue == null){
throw new IOException("illegal cert, tag 1 (cert info) has no value");
}
byte[] certContent = new byte[certContentTag.length + certContentLength.length + certContentValue.length];//被签名数据
System.arraycopy(certContentTag, 0, certContent, 0, certContentTag.length);
System.arraycopy(certContentLength, 0, certContent, certContentTag.length, certContentLength.length);
System.arraycopy(certContentValue, 0, certContent, certContentTag.length + certContentLength.length, certContentValue.length);
byte[] certSign = elements.get(2).getValue();
if (certSign == null){
throw new IOException("illegal cert, tag 3 (cert sign) has no value");
}
return verifySignByASN1(null, publicKey, certContent, certSign);
}
private byte[] getZ(byte[] userId, ECPoint userKey) {
SM3Digest digest = new SM3Digest();
if (userId == null) {
userId = DEFAULT_USER_ID;
}
int len = userId.length * 8;
digest.update((byte) (len >> 8 & 0xFF));
digest.update((byte) (len & 0xFF));
digest.update(userId);
byte[] p = CommonUtils.byteConvert32Bytes(SM2_ECC_A);
digest.update(p);
p = CommonUtils.byteConvert32Bytes(SM2_ECC_B);
digest.update(p);
p = CommonUtils.byteConvert32Bytes(SM2_ECC_GX);
digest.update(p);
p = CommonUtils.byteConvert32Bytes(SM2_ECC_GY);
digest.update(p);
p = CommonUtils.byteConvert32Bytes(userKey.getX().toBigInteger());
digest.update(p);
p = CommonUtils.byteConvert32Bytes(userKey.getY().toBigInteger());
digest.update(p);
return digest.doFinal();
}
/**
* @return {r, s}
*/
private BigInteger[] signInner(byte[] digestData, BigInteger key, ECPoint keyPoint) {
BigInteger e = new BigInteger(1, digestData);
BigInteger k;
ECPoint kp;
BigInteger r;
BigInteger s;
do {
do {
//正式环境
AsymmetricCipherKeyPair keypair = keyPairGenerator.generateKeyPair();
ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keypair.getPrivate();
ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keypair.getPublic();
k = privateKey.getD();
kp = publicKey.getQ();
//国密规范测试 随机数k
// String kS = "6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F";
// k = new BigInteger(kS, 16);
// kp = this.pointG.multiply(k);
//r
r = e.add(kp.getX().toBigInteger());
r = r.mod(SM2_ECC_N);
} while (r.equals(BigInteger.ZERO) || r.add(k).equals(SM2_ECC_N));
//(1 + dA)~-1
BigInteger da_1 = key.add(BigInteger.ONE);
da_1 = da_1.modInverse(SM2_ECC_N);
//s
s = r.multiply(key);
s = k.subtract(s).mod(SM2_ECC_N);
s = da_1.multiply(s).mod(SM2_ECC_N);
} while (s.equals(BigInteger.ZERO));
return new BigInteger[]{r, s};
}
private BigInteger verifyInner(byte digestData[], ECPoint userKey, BigInteger r, BigInteger s) {
BigInteger e = new BigInteger(1, digestData);
BigInteger t = r.add(s).mod(SM2_ECC_N);
if (t.equals(BigInteger.ZERO)) {
return null;
} else {
ECPoint x1y1 = pointG.multiply(s);
x1y1 = x1y1.add(userKey.multiply(t));
return e.add(x1y1.getX().toBigInteger()).mod(SM2_ECC_N);
}
}
public static class KeyPair {
private byte[] privateKey;
private byte[] publicKey;
private KeyPair(byte[] privateKey, byte[] publicKey) {
this.privateKey = privateKey;
this.publicKey = publicKey;
}
public byte[] getPrivateKey() {
return privateKey;
}
public byte[] getPublicKey() {
return publicKey;
}
}
public enum Type {
C1C2C3,
C1C3C2
}
private static class EncryptedData {
private ECPoint c1;
private byte[] c2;
private byte[] c3;
private EncryptedData(ECPoint c1, byte[] c2, byte[] c3) {
this.c1 = c1;
this.c2 = c2;
this.c3 = c3;
}
}
}