build: config spotless plugin and reformat code

This commit is contained in:
Frank.R.Wu 2023-06-15 11:08:05 +08:00
parent 4d620b64f3
commit b9ac471185
19 changed files with 618 additions and 638 deletions

View File

@ -4,6 +4,9 @@ plugins {
id 'maven-publish' id 'maven-publish'
id 'signing' id 'signing'
} }
apply from: '../spotless.gradle'
group 'org.bdware.bdcontract' group 'org.bdware.bdcontract'
version '0.2.0' version '0.2.0'
sourceCompatibility = 1.8 sourceCompatibility = 1.8

View File

@ -57,15 +57,12 @@ public class BCECUtil {
} }
public static KeyPair generateKeyPair(ECDomainParameters domainParameters, SecureRandom random) public static KeyPair generateKeyPair(ECDomainParameters domainParameters, SecureRandom random)
throws NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { throws NoSuchProviderException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException {
KeyPairGenerator kpg = KeyPairGenerator kpg =
KeyPairGenerator.getInstance(ALGO_NAME_EC, BouncyCastleProvider.PROVIDER_NAME); KeyPairGenerator.getInstance(ALGO_NAME_EC, BouncyCastleProvider.PROVIDER_NAME);
ECParameterSpec parameterSpec = ECParameterSpec parameterSpec = new ECParameterSpec(domainParameters.getCurve(),
new ECParameterSpec( domainParameters.getG(), domainParameters.getN(), domainParameters.getH());
domainParameters.getCurve(),
domainParameters.getG(),
domainParameters.getN(),
domainParameters.getH());
kpg.initialize(parameterSpec, (null == random ? new SecureRandom() : random)); kpg.initialize(parameterSpec, (null == random ? new SecureRandom() : random));
return kpg.generateKeyPair(); return kpg.generateKeyPair();
} }
@ -93,32 +90,32 @@ public class BCECUtil {
} }
/** /**
* @param dHex 十六进制字符串形式的私钥d值如果是SM2算法Hex字符串长度应该是64即32字节 * @param dHex 十六进制字符串形式的私钥d值如果是SM2算法Hex字符串长度应该是64即32字节
* @param domainParameters EC Domain参数一般是固定的如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS} * @param domainParameters EC Domain参数一般是固定的如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
* @return * @return
*/ */
public static ECPrivateKeyParameters createECPrivateKeyParameters( public static ECPrivateKeyParameters createECPrivateKeyParameters(String dHex,
String dHex, ECDomainParameters domainParameters) { ECDomainParameters domainParameters) {
return createECPrivateKeyParameters(ByteUtils.fromHexString(dHex), domainParameters); return createECPrivateKeyParameters(ByteUtils.fromHexString(dHex), domainParameters);
} }
/** /**
* @param dBytes 字节数组形式的私钥d值如果是SM2算法应该是32字节 * @param dBytes 字节数组形式的私钥d值如果是SM2算法应该是32字节
* @param domainParameters EC Domain参数一般是固定的如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS} * @param domainParameters EC Domain参数一般是固定的如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
* @return * @return
*/ */
public static ECPrivateKeyParameters createECPrivateKeyParameters( public static ECPrivateKeyParameters createECPrivateKeyParameters(byte[] dBytes,
byte[] dBytes, ECDomainParameters domainParameters) { ECDomainParameters domainParameters) {
return createECPrivateKeyParameters(new BigInteger(1, dBytes), domainParameters); return createECPrivateKeyParameters(new BigInteger(1, dBytes), domainParameters);
} }
/** /**
* @param d 大数形式的私钥d值 * @param d 大数形式的私钥d值
* @param domainParameters EC Domain参数一般是固定的如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS} * @param domainParameters EC Domain参数一般是固定的如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
* @return * @return
*/ */
public static ECPrivateKeyParameters createECPrivateKeyParameters( public static ECPrivateKeyParameters createECPrivateKeyParameters(BigInteger d,
BigInteger d, ECDomainParameters domainParameters) { ECDomainParameters domainParameters) {
return new ECPrivateKeyParameters(d, domainParameters); return new ECPrivateKeyParameters(d, domainParameters);
} }
@ -128,46 +125,48 @@ public class BCECUtil {
* @param priKey ECC私钥参数对象 * @param priKey ECC私钥参数对象
* @return * @return
*/ */
public static ECPublicKeyParameters buildECPublicKeyByPrivateKey(ECPrivateKeyParameters priKey) { public static ECPublicKeyParameters buildECPublicKeyByPrivateKey(
ECPrivateKeyParameters priKey) {
ECDomainParameters domainParameters = priKey.getParameters(); ECDomainParameters domainParameters = priKey.getParameters();
ECPoint q = new FixedPointCombMultiplier().multiply(domainParameters.getG(), priKey.getD()); ECPoint q = new FixedPointCombMultiplier().multiply(domainParameters.getG(), priKey.getD());
return new ECPublicKeyParameters(q, domainParameters); return new ECPublicKeyParameters(q, domainParameters);
} }
/** /**
* @param x 大数形式的公钥x分量 * @param x 大数形式的公钥x分量
* @param y 大数形式的公钥y分量 * @param y 大数形式的公钥y分量
* @param curve EC曲线参数一般是固定的如果是SM2算法的可参考{@link SM2Util#CURVE} * @param curve EC曲线参数一般是固定的如果是SM2算法的可参考{@link SM2Util#CURVE}
* @param domainParameters EC Domain参数一般是固定的如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS} * @param domainParameters EC Domain参数一般是固定的如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
* @return * @return
*/ */
public static ECPublicKeyParameters createECPublicKeyParameters( public static ECPublicKeyParameters createECPublicKeyParameters(BigInteger x, BigInteger y,
BigInteger x, BigInteger y, ECCurve curve, ECDomainParameters domainParameters) { ECCurve curve, ECDomainParameters domainParameters) {
return createECPublicKeyParameters(x.toByteArray(), y.toByteArray(), curve, domainParameters); return createECPublicKeyParameters(x.toByteArray(), y.toByteArray(), curve,
domainParameters);
} }
/** /**
* @param xHex 十六进制形式的公钥x分量如果是SM2算法Hex字符串长度应该是64即32字节 * @param xHex 十六进制形式的公钥x分量如果是SM2算法Hex字符串长度应该是64即32字节
* @param yHex 十六进制形式的公钥y分量如果是SM2算法Hex字符串长度应该是64即32字节 * @param yHex 十六进制形式的公钥y分量如果是SM2算法Hex字符串长度应该是64即32字节
* @param curve EC曲线参数一般是固定的如果是SM2算法的可参考{@link SM2Util#CURVE} * @param curve EC曲线参数一般是固定的如果是SM2算法的可参考{@link SM2Util#CURVE}
* @param domainParameters EC Domain参数一般是固定的如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS} * @param domainParameters EC Domain参数一般是固定的如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
* @return * @return
*/ */
public static ECPublicKeyParameters createECPublicKeyParameters( public static ECPublicKeyParameters createECPublicKeyParameters(String xHex, String yHex,
String xHex, String yHex, ECCurve curve, ECDomainParameters domainParameters) { ECCurve curve, ECDomainParameters domainParameters) {
return createECPublicKeyParameters( return createECPublicKeyParameters(ByteUtils.fromHexString(xHex),
ByteUtils.fromHexString(xHex), ByteUtils.fromHexString(yHex), curve, domainParameters); ByteUtils.fromHexString(yHex), curve, domainParameters);
} }
/** /**
* @param xBytes 十六进制形式的公钥x分量如果是SM2算法应该是32字节 * @param xBytes 十六进制形式的公钥x分量如果是SM2算法应该是32字节
* @param yBytes 十六进制形式的公钥y分量如果是SM2算法应该是32字节 * @param yBytes 十六进制形式的公钥y分量如果是SM2算法应该是32字节
* @param curve EC曲线参数一般是固定的如果是SM2算法的可参考{@link SM2Util#CURVE} * @param curve EC曲线参数一般是固定的如果是SM2算法的可参考{@link SM2Util#CURVE}
* @param domainParameters EC Domain参数一般是固定的如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS} * @param domainParameters EC Domain参数一般是固定的如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
* @return * @return
*/ */
public static ECPublicKeyParameters createECPublicKeyParameters( public static ECPublicKeyParameters createECPublicKeyParameters(byte[] xBytes, byte[] yBytes,
byte[] xBytes, byte[] yBytes, ECCurve curve, ECDomainParameters domainParameters) { ECCurve curve, ECDomainParameters domainParameters) {
final byte uncompressedFlag = 0x04; final byte uncompressedFlag = 0x04;
int curveLength = getCurveLength(domainParameters); int curveLength = getCurveLength(domainParameters);
xBytes = fixToCurveLengthBytes(curveLength, xBytes); xBytes = fixToCurveLengthBytes(curveLength, xBytes);
@ -180,44 +179,35 @@ public class BCECUtil {
} }
/** /**
* @param str 十六进制形式的公钥x分量如果是SM2算法应该是32字节 * @param str 十六进制形式的公钥x分量如果是SM2算法应该是32字节
* @param curve EC曲线参数一般是固定的如果是SM2算法的可参考{@link SM2Util#CURVE} * @param curve EC曲线参数一般是固定的如果是SM2算法的可参考{@link SM2Util#CURVE}
* @param domainParameters EC Domain参数一般是固定的如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS} * @param domainParameters EC Domain参数一般是固定的如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
* @return * @return
*/ */
public static ECPublicKeyParameters createECPublicKeyFromStrParameters( public static ECPublicKeyParameters createECPublicKeyFromStrParameters(String str,
String str, ECCurve curve, ECDomainParameters domainParameters) { ECCurve curve, ECDomainParameters domainParameters) {
return new ECPublicKeyParameters( return new ECPublicKeyParameters(curve.decodePoint(ByteUtils.fromHexString(str)),
curve.decodePoint(ByteUtils.fromHexString(str)), domainParameters); domainParameters);
} }
public static ECPrivateKeyParameters convertPrivateKeyToParameters(BCECPrivateKey ecPriKey) { public static ECPrivateKeyParameters convertPrivateKeyToParameters(BCECPrivateKey ecPriKey) {
ECParameterSpec parameterSpec = ecPriKey.getParameters(); ECParameterSpec parameterSpec = ecPriKey.getParameters();
ECDomainParameters domainParameters = ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(),
new ECDomainParameters( parameterSpec.getG(), parameterSpec.getN(), parameterSpec.getH());
parameterSpec.getCurve(),
parameterSpec.getG(),
parameterSpec.getN(),
parameterSpec.getH());
return new ECPrivateKeyParameters(ecPriKey.getD(), domainParameters); return new ECPrivateKeyParameters(ecPriKey.getD(), domainParameters);
} }
public static ECPublicKeyParameters convertPublicKeyToParameters(BCECPublicKey ecPubKey) { public static ECPublicKeyParameters convertPublicKeyToParameters(BCECPublicKey ecPubKey) {
ECParameterSpec parameterSpec = ecPubKey.getParameters(); ECParameterSpec parameterSpec = ecPubKey.getParameters();
ECDomainParameters domainParameters = ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(),
new ECDomainParameters( parameterSpec.getG(), parameterSpec.getN(), parameterSpec.getH());
parameterSpec.getCurve(),
parameterSpec.getG(),
parameterSpec.getN(),
parameterSpec.getH());
return new ECPublicKeyParameters(ecPubKey.getQ(), domainParameters); return new ECPublicKeyParameters(ecPubKey.getQ(), domainParameters);
} }
public static BCECPublicKey createPublicKeyFromSubjectPublicKeyInfo( public static BCECPublicKey createPublicKeyFromSubjectPublicKeyInfo(
SubjectPublicKeyInfo subPubInfo) SubjectPublicKeyInfo subPubInfo) throws NoSuchProviderException,
throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchAlgorithmException, InvalidKeySpecException, IOException {
IOException {
return BCECUtil.convertX509ToECPublicKey( return BCECUtil.convertX509ToECPublicKey(
subPubInfo.toASN1Primitive().getEncoded(ASN1Encoding.DER)); subPubInfo.toASN1Primitive().getEncoded(ASN1Encoding.DER));
} }
@ -229,19 +219,18 @@ public class BCECUtil {
* @param pubKey 可以为空但是如果为空的话得到的结果OpenSSL可能解析不了 * @param pubKey 可以为空但是如果为空的话得到的结果OpenSSL可能解析不了
* @return * @return
*/ */
public static byte[] convertECPrivateKeyToPKCS8( public static byte[] convertECPrivateKeyToPKCS8(ECPrivateKeyParameters priKey,
ECPrivateKeyParameters priKey, ECPublicKeyParameters pubKey) { ECPublicKeyParameters pubKey) {
ECDomainParameters domainParams = priKey.getParameters(); ECDomainParameters domainParams = priKey.getParameters();
ECParameterSpec spec = ECParameterSpec spec = new ECParameterSpec(domainParams.getCurve(), domainParams.getG(),
new ECParameterSpec( domainParams.getN(), domainParams.getH());
domainParams.getCurve(), domainParams.getG(), domainParams.getN(), domainParams.getH());
BCECPublicKey publicKey = null; BCECPublicKey publicKey = null;
if (pubKey != null) { if (pubKey != null) {
publicKey = new BCECPublicKey(ALGO_NAME_EC, pubKey, spec, BouncyCastleProvider.CONFIGURATION); publicKey = new BCECPublicKey(ALGO_NAME_EC, pubKey, spec,
BouncyCastleProvider.CONFIGURATION);
} }
BCECPrivateKey privateKey = BCECPrivateKey privateKey = new BCECPrivateKey(ALGO_NAME_EC, priKey, publicKey, spec,
new BCECPrivateKey( BouncyCastleProvider.CONFIGURATION);
ALGO_NAME_EC, priKey, publicKey, spec, BouncyCastleProvider.CONFIGURATION);
return privateKey.getEncoded(); return privateKey.getEncoded();
} }
@ -292,8 +281,8 @@ public class BCECUtil {
* @return * @return
* @throws IOException * @throws IOException
*/ */
public static byte[] convertECPrivateKeyToSEC1( public static byte[] convertECPrivateKeyToSEC1(ECPrivateKeyParameters priKey,
ECPrivateKeyParameters priKey, ECPublicKeyParameters pubKey) throws IOException { ECPublicKeyParameters pubKey) throws IOException {
byte[] pkcs8Bytes = convertECPrivateKeyToPKCS8(priKey, pubKey); byte[] pkcs8Bytes = convertECPrivateKeyToPKCS8(priKey, pubKey);
PrivateKeyInfo pki = PrivateKeyInfo.getInstance(pkcs8Bytes); PrivateKeyInfo pki = PrivateKeyInfo.getInstance(pkcs8Bytes);
ASN1Encodable encodable = pki.parsePrivateKey(); ASN1Encodable encodable = pki.parsePrivateKey();
@ -368,9 +357,8 @@ public class BCECUtil {
*/ */
public static byte[] convertECPublicKeyToX509(ECPublicKeyParameters pubKey) { public static byte[] convertECPublicKeyToX509(ECPublicKeyParameters pubKey) {
ECDomainParameters domainParams = pubKey.getParameters(); ECDomainParameters domainParams = pubKey.getParameters();
ECParameterSpec spec = ECParameterSpec spec = new ECParameterSpec(domainParams.getCurve(), domainParams.getG(),
new ECParameterSpec( domainParams.getN(), domainParams.getH());
domainParams.getCurve(), domainParams.getG(), domainParams.getN(), domainParams.getH());
BCECPublicKey publicKey = BCECPublicKey publicKey =
new BCECPublicKey(ALGO_NAME_EC, pubKey, spec, BouncyCastleProvider.CONFIGURATION); new BCECPublicKey(ALGO_NAME_EC, pubKey, spec, BouncyCastleProvider.CONFIGURATION);
return publicKey.getEncoded(); return publicKey.getEncoded();
@ -473,23 +461,18 @@ public class BCECUtil {
} else { } else {
ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve()); ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
X9ECParameters ecP = X9ECParameters ecP = new X9ECParameters(curve,
new X9ECParameters( new X9ECPoint(EC5Util.convertPoint(curve, ecSpec.getGenerator()),
curve, withCompression),
new X9ECPoint(EC5Util.convertPoint(curve, ecSpec.getGenerator()), withCompression), ecSpec.getOrder(), BigInteger.valueOf(ecSpec.getCofactor()),
ecSpec.getOrder(), ecSpec.getCurve().getSeed());
BigInteger.valueOf(ecSpec.getCofactor()),
ecSpec.getCurve().getSeed());
//// 如果是1.62或更低版本的bcprov-jdk15on应该使用以下这段代码因为高版本的EC5Util.convertPoint没有向下兼容 //// 如果是1.62或更低版本的bcprov-jdk15on应该使用以下这段代码因为高版本的EC5Util.convertPoint没有向下兼容
/* /*
X9ECParameters ecP = new X9ECParameters( * X9ECParameters ecP = new X9ECParameters( curve, EC5Util.convertPoint(curve,
curve, * ecSpec.getGenerator(), withCompression), ecSpec.getOrder(),
EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), * BigInteger.valueOf(ecSpec.getCofactor()), ecSpec.getCurve().getSeed());
ecSpec.getOrder(), */
BigInteger.valueOf(ecSpec.getCofactor()),
ecSpec.getCurve().getSeed());
*/
params = new X962Parameters(ecP); params = new X962Parameters(ecP);
} }

View File

@ -7,51 +7,53 @@ import java.util.Arrays;
public class SM2KeyExchangeUtil { public class SM2KeyExchangeUtil {
/** /**
* @param initiator true表示发起方false表示响应方 * @param initiator true表示发起方false表示响应方
* @param keyBits 生成的密钥长度 * @param keyBits 生成的密钥长度
* @param selfStaticPriv 己方固定私钥 * @param selfStaticPriv 己方固定私钥
* @param selfEphemeralPriv 己方临时私钥 * @param selfEphemeralPriv 己方临时私钥
* @param selfId 己方ID * @param selfId 己方ID
* @param otherStaticPub 对方固定公钥 * @param otherStaticPub 对方固定公钥
* @param otherEphemeralPub 对方临时公钥 * @param otherEphemeralPub 对方临时公钥
* @param otherId 对方ID * @param otherId 对方ID
* @return 返回协商出的密钥但是这个密钥是没有经过确认的 * @return 返回协商出的密钥但是这个密钥是没有经过确认的
*/ */
public static byte[] calculateKey(boolean initiator, int keyBits, public static byte[] calculateKey(boolean initiator, int keyBits,
ECPrivateKeyParameters selfStaticPriv, ECPrivateKeyParameters selfEphemeralPriv, byte[] selfId, ECPrivateKeyParameters selfStaticPriv, ECPrivateKeyParameters selfEphemeralPriv,
ECPublicKeyParameters otherStaticPub, ECPublicKeyParameters otherEphemeralPub, byte[] otherId) { byte[] selfId, ECPublicKeyParameters otherStaticPub,
ECPublicKeyParameters otherEphemeralPub, byte[] otherId) {
SM2KeyExchange exch = new SM2KeyExchange(); SM2KeyExchange exch = new SM2KeyExchange();
exch.init(new ParametersWithID( exch.init(new ParametersWithID(
new SM2KeyExchangePrivateParameters(initiator, selfStaticPriv, selfEphemeralPriv), new SM2KeyExchangePrivateParameters(initiator, selfStaticPriv, selfEphemeralPriv),
selfId)); selfId));
return exch.calculateKey( return exch.calculateKey(keyBits, new ParametersWithID(
keyBits, new SM2KeyExchangePublicParameters(otherStaticPub, otherEphemeralPub), otherId));
new ParametersWithID(new SM2KeyExchangePublicParameters(otherStaticPub, otherEphemeralPub), otherId));
} }
/** /**
* @param initiator true表示发起方false表示响应方 * @param initiator true表示发起方false表示响应方
* @param keyBits 生成的密钥长度 * @param keyBits 生成的密钥长度
* @param confirmationTag 确认信息如果是响应方可以为null如果是发起方则应为响应方的s1 * @param confirmationTag 确认信息如果是响应方可以为null如果是发起方则应为响应方的s1
* @param selfStaticPriv 己方固定私钥 * @param selfStaticPriv 己方固定私钥
* @param selfEphemeralPriv 己方临时私钥 * @param selfEphemeralPriv 己方临时私钥
* @param selfId 己方ID * @param selfId 己方ID
* @param otherStaticPub 对方固定公钥 * @param otherStaticPub 对方固定公钥
* @param otherEphemeralPub 对方临时公钥 * @param otherEphemeralPub 对方临时公钥
* @param otherId 对方ID * @param otherId 对方ID
* @return * @return
*/ */
public static ExchangeResult calculateKeyWithConfirmation(boolean initiator, int keyBits, byte[] confirmationTag, public static ExchangeResult calculateKeyWithConfirmation(boolean initiator, int keyBits,
ECPrivateKeyParameters selfStaticPriv, ECPrivateKeyParameters selfEphemeralPriv, byte[] selfId, byte[] confirmationTag, ECPrivateKeyParameters selfStaticPriv,
ECPublicKeyParameters otherStaticPub, ECPublicKeyParameters otherEphemeralPub, byte[] otherId) { ECPrivateKeyParameters selfEphemeralPriv, byte[] selfId,
ECPublicKeyParameters otherStaticPub, ECPublicKeyParameters otherEphemeralPub,
byte[] otherId) {
SM2KeyExchange exch = new SM2KeyExchange(); SM2KeyExchange exch = new SM2KeyExchange();
exch.init(new ParametersWithID( exch.init(new ParametersWithID(
new SM2KeyExchangePrivateParameters(initiator, selfStaticPriv, selfEphemeralPriv), new SM2KeyExchangePrivateParameters(initiator, selfStaticPriv, selfEphemeralPriv),
selfId)); selfId));
byte[][] result = exch.calculateKeyWithConfirmation( byte[][] result = exch.calculateKeyWithConfirmation(keyBits, confirmationTag,
keyBits, new ParametersWithID(
confirmationTag, new SM2KeyExchangePublicParameters(otherStaticPub, otherEphemeralPub),
new ParametersWithID(new SM2KeyExchangePublicParameters(otherStaticPub, otherEphemeralPub), otherId)); otherId));
ExchangeResult confirmResult = new ExchangeResult(); ExchangeResult confirmResult = new ExchangeResult();
confirmResult.setKey(result[0]); confirmResult.setKey(result[0]);
if (initiator) { if (initiator) {

View File

@ -32,15 +32,14 @@ public class SM2KeyPair {
JsonObject jo = JsonParser.parseString(jsonStr).getAsJsonObject(); JsonObject jo = JsonParser.parseString(jsonStr).getAsJsonObject();
String publicKeyStr = jo.get("publicKey").getAsString(); String publicKeyStr = jo.get("publicKey").getAsString();
String privateKeyStr = jo.get("privateKey").getAsString(); String privateKeyStr = jo.get("privateKey").getAsString();
ECPublicKeyParameters point = ECPublicKeyParameters point = BCECUtil.createECPublicKeyFromStrParameters(publicKeyStr,
BCECUtil.createECPublicKeyFromStrParameters( SM2Util.CURVE, SM2Util.DOMAIN_PARAMS);
publicKeyStr, SM2Util.CURVE, SM2Util.DOMAIN_PARAMS);
return new SM2KeyPair(point, new BigInteger(privateKeyStr, 16)); return new SM2KeyPair(point, new BigInteger(privateKeyStr, 16));
} }
public static ECPublicKeyParameters publicKeyStr2ECPoint(String pubKey) { public static ECPublicKeyParameters publicKeyStr2ECPoint(String pubKey) {
return BCECUtil.createECPublicKeyFromStrParameters( return BCECUtil.createECPublicKeyFromStrParameters(pubKey, SM2Util.CURVE,
pubKey, SM2Util.CURVE, SM2Util.DOMAIN_PARAMS); SM2Util.DOMAIN_PARAMS);
} }
public ECPublicKeyParameters getPublicKey() { public ECPublicKeyParameters getPublicKey() {
@ -74,29 +73,16 @@ public class SM2KeyPair {
public KeyPair toJavaSecurity() { public KeyPair toJavaSecurity() {
ECDomainParameters domainParams = privateKey.getParameters(); ECDomainParameters domainParams = privateKey.getParameters();
ECParameterSpec spec = ECParameterSpec spec = new ECParameterSpec(domainParams.getCurve(), domainParams.getG(),
new ECParameterSpec( domainParams.getN(), domainParams.getH());
domainParams.getCurve(),
domainParams.getG(),
domainParams.getN(),
domainParams.getH());
BCECPublicKey bcPublicKey = null; BCECPublicKey bcPublicKey = null;
BCECPrivateKey bcPrivateKey; BCECPrivateKey bcPrivateKey;
if (null != publicKey) { if (null != publicKey) {
bcPublicKey = bcPublicKey = new BCECPublicKey(BCECUtil.ALGO_NAME_EC, publicKey, spec,
new BCECPublicKey( BouncyCastleProvider.CONFIGURATION);
BCECUtil.ALGO_NAME_EC,
publicKey,
spec,
BouncyCastleProvider.CONFIGURATION);
} }
bcPrivateKey = bcPrivateKey = new BCECPrivateKey(BCECUtil.ALGO_NAME_EC, privateKey, bcPublicKey, spec,
new BCECPrivateKey( BouncyCastleProvider.CONFIGURATION);
BCECUtil.ALGO_NAME_EC,
privateKey,
bcPublicKey,
spec,
BouncyCastleProvider.CONFIGURATION);
return new KeyPair(bcPublicKey, bcPrivateKey); return new KeyPair(bcPublicKey, bcPrivateKey);
} }

View File

@ -20,7 +20,7 @@ import java.math.BigInteger;
* 有的国密需求是用户可以自己做预处理签名验签只是对预处理的结果进行签名和验签 * 有的国密需求是用户可以自己做预处理签名验签只是对预处理的结果进行签名和验签
*/ */
public class SM2PreprocessSigner implements ECConstants { public class SM2PreprocessSigner implements ECConstants {
private static final int DIGEST_LENGTH = 32; // bytes private static final int DIGEST_LENGTH = 32; // bytes
private final DSAKCalculator kCalculator = new RandomDSAKCalculator(); private final DSAKCalculator kCalculator = new RandomDSAKCalculator();
private Digest digest = null; private Digest digest = null;
@ -44,11 +44,12 @@ public class SM2PreprocessSigner implements ECConstants {
* 初始化 * 初始化
* *
* @param forSigning true表示用于签名false表示用于验签 * @param forSigning true表示用于签名false表示用于验签
* @param digest SM2算法的话一般是采用SM3摘要算法 * @param digest SM2算法的话一般是采用SM3摘要算法
* @param param * @param param
* @throws RuntimeException * @throws RuntimeException
*/ */
public void init(boolean forSigning, Digest digest, CipherParameters param) throws RuntimeException { public void init(boolean forSigning, Digest digest, CipherParameters param)
throws RuntimeException {
CipherParameters baseParam; CipherParameters baseParam;
if (digest.getDigestSize() != DIGEST_LENGTH) { if (digest.getDigestSize() != DIGEST_LENGTH) {
@ -76,7 +77,8 @@ public class SM2PreprocessSigner implements ECConstants {
ecParams = ecKey.getParameters(); ecParams = ecKey.getParameters();
kCalculator.init(ecParams.getN(), CryptoServicesRegistrar.getSecureRandom()); kCalculator.init(ecParams.getN(), CryptoServicesRegistrar.getSecureRandom());
} }
pubPoint = createBasePointMultiplier().multiply(ecParams.getG(), ((ECPrivateKeyParameters) ecKey).getD()).normalize(); pubPoint = createBasePointMultiplier()
.multiply(ecParams.getG(), ((ECPrivateKeyParameters) ecKey).getD()).normalize();
} else { } else {
ecKey = (ECKeyParameters) baseParam; ecKey = (ECKeyParameters) baseParam;
ecParams = ecKey.getParameters(); ecParams = ecKey.getParameters();
@ -85,10 +87,7 @@ public class SM2PreprocessSigner implements ECConstants {
} }
/** /**
* 预处理辅助方法 * 预处理辅助方法 ZA=H256(ENT LA IDA a b xG yG xA yA) M=ZA M e = Hv(M)
* ZA=H256(ENT LA IDA a b xG yG xA yA)
* M=ZA M
* e = Hv(M)
* *
* @return * @return
*/ */
@ -126,7 +125,7 @@ public class SM2PreprocessSigner implements ECConstants {
ECMultiplier basePointMultiplier = createBasePointMultiplier(); ECMultiplier basePointMultiplier = createBasePointMultiplier();
// 5.2.1 Draft RFC: SM2 Public Key Algorithms // 5.2.1 Draft RFC: SM2 Public Key Algorithms
do // generate s do // generate s
{ {
BigInteger k; BigInteger k;
@ -140,16 +139,14 @@ public class SM2PreprocessSigner implements ECConstants {
// A5 // A5
r = e.add(p.getAffineXCoord().toBigInteger()).mod(n); r = e.add(p.getAffineXCoord().toBigInteger()).mod(n);
} } while (r.equals(ZERO) || r.add(k).equals(n));
while (r.equals(ZERO) || r.add(k).equals(n));
// A6 // A6
BigInteger dPlus1ModN = d.add(ONE).modInverse(n); BigInteger dPlus1ModN = d.add(ONE).modInverse(n);
s = k.subtract(r.multiply(d)).mod(n); s = k.subtract(r.multiply(d)).mod(n);
s = dPlus1ModN.multiply(s).mod(n); s = dPlus1ModN.multiply(s).mod(n);
} } while (s.equals(ZERO));
while (s.equals(ZERO));
// A7 // A7
try { try {
@ -162,7 +159,7 @@ public class SM2PreprocessSigner implements ECConstants {
private boolean verifySignature(byte[] eHash, BigInteger r, BigInteger s) { private boolean verifySignature(byte[] eHash, BigInteger r, BigInteger s) {
BigInteger n = ecParams.getN(); BigInteger n = ecParams.getN();
// 5.3.1 Draft RFC: SM2 Public Key Algorithms // 5.3.1 Draft RFC: SM2 Public Key Algorithms
// B1 // B1
if (r.compareTo(ONE) < 0 || r.compareTo(n) >= 0) { if (r.compareTo(ONE) < 0 || r.compareTo(n) >= 0) {
return false; return false;
@ -245,8 +242,7 @@ public class SM2PreprocessSigner implements ECConstants {
return new BigInteger(1, message); return new BigInteger(1, message);
} }
protected BigInteger[] derDecode(byte[] encoding) protected BigInteger[] derDecode(byte[] encoding) throws IOException {
throws IOException {
ASN1Sequence seq = ASN1Sequence.getInstance(ASN1Primitive.fromByteArray(encoding)); ASN1Sequence seq = ASN1Sequence.getInstance(ASN1Primitive.fromByteArray(encoding));
if (seq.size() != 2) { if (seq.size() != 2) {
return null; return null;
@ -260,11 +256,10 @@ public class SM2PreprocessSigner implements ECConstants {
return null; return null;
} }
return new BigInteger[]{r, s}; return new BigInteger[] {r, s};
} }
protected byte[] derEncode(BigInteger r, BigInteger s) protected byte[] derEncode(BigInteger r, BigInteger s) throws IOException {
throws IOException {
ASN1EncodableVector v = new ASN1EncodableVector(); ASN1EncodableVector v = new ASN1EncodableVector();
v.add(new ASN1Integer(r)); v.add(new ASN1Integer(r));

View File

@ -19,195 +19,196 @@ import org.bouncycastle.util.encoders.Hex;
import java.math.BigInteger; import java.math.BigInteger;
public class SM2Signer implements Signer, ECConstants { public class SM2Signer implements Signer, ECConstants {
private final DSAKCalculator kCalculator; private final DSAKCalculator kCalculator;
private final Digest digest; private final Digest digest;
private final DSAEncoding encoding; private final DSAEncoding encoding;
private ECDomainParameters ecParams; private ECDomainParameters ecParams;
private ECPoint pubPoint; private ECPoint pubPoint;
private ECKeyParameters ecKey; private ECKeyParameters ecKey;
private byte[] z; private byte[] z;
public SM2Signer() { public SM2Signer() {
this(StandardDSAEncoding.INSTANCE, new SM3Digest()); this(StandardDSAEncoding.INSTANCE, new SM3Digest());
}
public SM2Signer(Digest var1) {
this(StandardDSAEncoding.INSTANCE, var1);
}
public SM2Signer(DSAEncoding var1) {
this.kCalculator = new RandomDSAKCalculator();
this.encoding = var1;
this.digest = new SM3Digest();
}
public SM2Signer(DSAEncoding var1, Digest var2) {
this.kCalculator = new RandomDSAKCalculator();
this.encoding = var1;
this.digest = var2;
}
public void init(boolean var1, CipherParameters var2) {
CipherParameters var3;
byte[] var4;
if (var2 instanceof ParametersWithID) {
var3 = ((ParametersWithID) var2).getParameters();
var4 = ((ParametersWithID) var2).getID();
if (var4.length >= 8192) {
throw new IllegalArgumentException("SM2 user ID must be less than 2^16 bits long");
}
} else {
var3 = var2;
var4 = Hex.decodeStrict("31323334353637383132333435363738");
} }
if (var1) { public SM2Signer(Digest var1) {
if (var3 instanceof ParametersWithRandom) { this(StandardDSAEncoding.INSTANCE, var1);
ParametersWithRandom var5 = (ParametersWithRandom) var3;
this.ecKey = (ECKeyParameters) var5.getParameters();
this.ecParams = this.ecKey.getParameters();
this.kCalculator.init(this.ecParams.getN(), var5.getRandom());
} else {
this.ecKey = (ECKeyParameters) var3;
this.ecParams = this.ecKey.getParameters();
this.kCalculator.init(this.ecParams.getN(), CryptoServicesRegistrar.getSecureRandom());
}
this.pubPoint =
this.createBasePointMultiplier()
.multiply(this.ecParams.getG(), ((ECPrivateKeyParameters) this.ecKey).getD())
.normalize();
} else {
this.ecKey = (ECKeyParameters) var3;
this.ecParams = this.ecKey.getParameters();
this.pubPoint = ((ECPublicKeyParameters) this.ecKey).getQ();
} }
this.z = this.getZ(var4); public SM2Signer(DSAEncoding var1) {
this.digest.update(this.z, 0, this.z.length); this.kCalculator = new RandomDSAKCalculator();
} this.encoding = var1;
this.digest = new SM3Digest();
public void update(byte var1) {
this.digest.update(var1);
}
public void update(byte[] var1, int var2, int var3) {
this.digest.update(var1, var2, var3);
}
public boolean verifySignature(byte[] var1) {
try {
BigInteger[] var2 = this.encoding.decode(this.ecParams.getN(), var1);
return this.verifySignature(var2[0], var2[1]);
} catch (Exception var3) {
return false;
} }
}
public void reset() { public SM2Signer(DSAEncoding var1, Digest var2) {
this.digest.reset(); this.kCalculator = new RandomDSAKCalculator();
if (this.z != null) { this.encoding = var1;
this.digest.update(this.z, 0, this.z.length); this.digest = var2;
} }
}
public byte[] generateSignature() throws CryptoException { public void init(boolean var1, CipherParameters var2) {
byte[] var1 = this.digestDoFinal(); CipherParameters var3;
BigInteger n = this.ecParams.getN(); byte[] var4;
BigInteger var3 = this.calculateE(n , var1); if (var2 instanceof ParametersWithID) {
BigInteger var4 = ((ECPrivateKeyParameters) this.ecKey).getD(); var3 = ((ParametersWithID) var2).getParameters();
ECMultiplier var7 = this.createBasePointMultiplier(); var4 = ((ParametersWithID) var2).getID();
if (var4.length >= 8192) {
while (true) { throw new IllegalArgumentException("SM2 user ID must be less than 2^16 bits long");
BigInteger var5; }
BigInteger k;
do {
k = this.kCalculator.nextK();
ECPoint var9 = var7.multiply(this.ecParams.getG(), k).normalize();
var5 = var3.add(var9.getAffineXCoord().toBigInteger()).mod(n);
} while (var5.equals(ZERO));
if (!var5.add(k).equals(n )) {
BigInteger var11 = BigIntegers.modOddInverse(n, var4.add(ONE));
BigInteger var6 = k.subtract(var5.multiply(var4)).mod(n);
var6 = var11.multiply(var6).mod(n);
if (!var6.equals(ZERO)) {
try {
return this.encoding.encode(this.ecParams.getN(), var5, var6);
} catch (Exception var10) {
throw new CryptoException("unable to encode signature: " + var10.getMessage(), var10);
}
}
}
}
}
private boolean verifySignature(BigInteger var1, BigInteger var2) {
BigInteger var3 = this.ecParams.getN();
if (var1.compareTo(ONE) >= 0 && var1.compareTo(var3) < 0) {
if (var2.compareTo(ONE) >= 0 && var2.compareTo(var3) < 0) {
byte[] var4 = this.digestDoFinal();
BigInteger var5 = this.calculateE(var3, var4);
BigInteger var6 = var1.add(var2).mod(var3);
if (var6.equals(ZERO)) {
return false;
} else { } else {
ECPoint var7 = ((ECPublicKeyParameters) this.ecKey).getQ(); var3 = var2;
ECPoint var8 = var4 = Hex.decodeStrict("31323334353637383132333435363738");
ECAlgorithms.sumOfTwoMultiplies(this.ecParams.getG(), var2, var7, var6).normalize();
if (var8.isInfinity()) {
return false;
} else {
BigInteger var9 = var5.add(var8.getAffineXCoord().toBigInteger()).mod(var3);
return var9.equals(var1);
}
} }
} else {
return false; if (var1) {
} if (var3 instanceof ParametersWithRandom) {
} else { ParametersWithRandom var5 = (ParametersWithRandom) var3;
return false; this.ecKey = (ECKeyParameters) var5.getParameters();
this.ecParams = this.ecKey.getParameters();
this.kCalculator.init(this.ecParams.getN(), var5.getRandom());
} else {
this.ecKey = (ECKeyParameters) var3;
this.ecParams = this.ecKey.getParameters();
this.kCalculator.init(this.ecParams.getN(),
CryptoServicesRegistrar.getSecureRandom());
}
this.pubPoint = this.createBasePointMultiplier()
.multiply(this.ecParams.getG(), ((ECPrivateKeyParameters) this.ecKey).getD())
.normalize();
} else {
this.ecKey = (ECKeyParameters) var3;
this.ecParams = this.ecKey.getParameters();
this.pubPoint = ((ECPublicKeyParameters) this.ecKey).getQ();
}
this.z = this.getZ(var4);
this.digest.update(this.z, 0, this.z.length);
} }
}
private byte[] digestDoFinal() { public void update(byte var1) {
byte[] var1 = new byte[this.digest.getDigestSize()]; this.digest.update(var1);
this.digest.doFinal(var1, 0); }
this.reset();
return var1;
}
private byte[] getZ(byte[] var1) { public void update(byte[] var1, int var2, int var3) {
this.digest.reset(); this.digest.update(var1, var2, var3);
this.addUserID(this.digest, var1); }
this.addFieldElement(this.digest, this.ecParams.getCurve().getA());
this.addFieldElement(this.digest, this.ecParams.getCurve().getB());
this.addFieldElement(this.digest, this.ecParams.getG().getAffineXCoord());
this.addFieldElement(this.digest, this.ecParams.getG().getAffineYCoord());
this.addFieldElement(this.digest, this.pubPoint.getAffineXCoord());
this.addFieldElement(this.digest, this.pubPoint.getAffineYCoord());
byte[] var2 = new byte[this.digest.getDigestSize()];
this.digest.doFinal(var2, 0);
return var2;
}
private void addUserID(Digest var1, byte[] var2) { public boolean verifySignature(byte[] var1) {
int var3 = var2.length * 8; try {
var1.update((byte) (var3 >> 8 & 255)); BigInteger[] var2 = this.encoding.decode(this.ecParams.getN(), var1);
var1.update((byte) (var3 & 255)); return this.verifySignature(var2[0], var2[1]);
var1.update(var2, 0, var2.length); } catch (Exception var3) {
} return false;
}
}
private void addFieldElement(Digest var1, ECFieldElement var2) { public void reset() {
byte[] var3 = var2.getEncoded(); this.digest.reset();
var1.update(var3, 0, var3.length); if (this.z != null) {
} this.digest.update(this.z, 0, this.z.length);
}
}
protected ECMultiplier createBasePointMultiplier() { public byte[] generateSignature() throws CryptoException {
return new FixedPointCombMultiplier(); byte[] var1 = this.digestDoFinal();
} BigInteger n = this.ecParams.getN();
BigInteger var3 = this.calculateE(n, var1);
BigInteger var4 = ((ECPrivateKeyParameters) this.ecKey).getD();
ECMultiplier var7 = this.createBasePointMultiplier();
protected BigInteger calculateE(BigInteger var1, byte[] var2) { while (true) {
return new BigInteger(1, var2); BigInteger var5;
} BigInteger k;
do {
k = this.kCalculator.nextK();
ECPoint var9 = var7.multiply(this.ecParams.getG(), k).normalize();
var5 = var3.add(var9.getAffineXCoord().toBigInteger()).mod(n);
} while (var5.equals(ZERO));
if (!var5.add(k).equals(n)) {
BigInteger var11 = BigIntegers.modOddInverse(n, var4.add(ONE));
BigInteger var6 = k.subtract(var5.multiply(var4)).mod(n);
var6 = var11.multiply(var6).mod(n);
if (!var6.equals(ZERO)) {
try {
return this.encoding.encode(this.ecParams.getN(), var5, var6);
} catch (Exception var10) {
throw new CryptoException(
"unable to encode signature: " + var10.getMessage(), var10);
}
}
}
}
}
private boolean verifySignature(BigInteger var1, BigInteger var2) {
BigInteger var3 = this.ecParams.getN();
if (var1.compareTo(ONE) >= 0 && var1.compareTo(var3) < 0) {
if (var2.compareTo(ONE) >= 0 && var2.compareTo(var3) < 0) {
byte[] var4 = this.digestDoFinal();
BigInteger var5 = this.calculateE(var3, var4);
BigInteger var6 = var1.add(var2).mod(var3);
if (var6.equals(ZERO)) {
return false;
} else {
ECPoint var7 = ((ECPublicKeyParameters) this.ecKey).getQ();
ECPoint var8 = ECAlgorithms
.sumOfTwoMultiplies(this.ecParams.getG(), var2, var7, var6).normalize();
if (var8.isInfinity()) {
return false;
} else {
BigInteger var9 = var5.add(var8.getAffineXCoord().toBigInteger()).mod(var3);
return var9.equals(var1);
}
}
} else {
return false;
}
} else {
return false;
}
}
private byte[] digestDoFinal() {
byte[] var1 = new byte[this.digest.getDigestSize()];
this.digest.doFinal(var1, 0);
this.reset();
return var1;
}
private byte[] getZ(byte[] var1) {
this.digest.reset();
this.addUserID(this.digest, var1);
this.addFieldElement(this.digest, this.ecParams.getCurve().getA());
this.addFieldElement(this.digest, this.ecParams.getCurve().getB());
this.addFieldElement(this.digest, this.ecParams.getG().getAffineXCoord());
this.addFieldElement(this.digest, this.ecParams.getG().getAffineYCoord());
this.addFieldElement(this.digest, this.pubPoint.getAffineXCoord());
this.addFieldElement(this.digest, this.pubPoint.getAffineYCoord());
byte[] var2 = new byte[this.digest.getDigestSize()];
this.digest.doFinal(var2, 0);
return var2;
}
private void addUserID(Digest var1, byte[] var2) {
int var3 = var2.length * 8;
var1.update((byte) (var3 >> 8 & 255));
var1.update((byte) (var3 & 255));
var1.update(var2, 0, var2.length);
}
private void addFieldElement(Digest var1, ECFieldElement var2) {
byte[] var3 = var2.getEncoded();
var1.update(var3, 0, var3.length);
}
protected ECMultiplier createBasePointMultiplier() {
return new FixedPointCombMultiplier();
}
protected BigInteger calculateE(BigInteger var1, byte[] var2) {
return new BigInteger(1, var2);
}
} }

View File

@ -44,21 +44,17 @@ public class SM2Util extends GMBaseUtil {
////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////
public static final EllipticCurve JDK_CURVE = public static final EllipticCurve JDK_CURVE =
new EllipticCurve(new ECFieldFp(SM2_ECC_P), SM2_ECC_A, SM2_ECC_B); new EllipticCurve(new ECFieldFp(SM2_ECC_P), SM2_ECC_A, SM2_ECC_B);
public static final java.security.spec.ECPoint JDK_G_POINT = public static final java.security.spec.ECPoint JDK_G_POINT = new java.security.spec.ECPoint(
new java.security.spec.ECPoint( G_POINT.getAffineXCoord().toBigInteger(), G_POINT.getAffineYCoord().toBigInteger());
G_POINT.getAffineXCoord().toBigInteger(),
G_POINT.getAffineYCoord().toBigInteger());
public static final java.security.spec.ECParameterSpec JDK_EC_SPEC = public static final java.security.spec.ECParameterSpec JDK_EC_SPEC =
new java.security.spec.ECParameterSpec( new java.security.spec.ECParameterSpec(JDK_CURVE, JDK_G_POINT, SM2_ECC_N,
JDK_CURVE, JDK_G_POINT, SM2_ECC_N, SM2_ECC_H.intValue()); SM2_ECC_H.intValue());
public static final int SM3_DIGEST_LENGTH = 32; public static final int SM3_DIGEST_LENGTH = 32;
////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////
static ECCurve.Fp SM2_ECC_FP = static ECCurve.Fp SM2_ECC_FP = new ECCurve.Fp(SM2_ECC_P, // q
new ECCurve.Fp( SM2_ECC_A, // a
SM2_ECC_P, // q SM2_ECC_B); // b
SM2_ECC_A, // a
SM2_ECC_B); // b
/** /**
* 生成ECC密钥对 * 生成ECC密钥对
@ -79,9 +75,8 @@ public class SM2Util extends GMBaseUtil {
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException
* @throws InvalidAlgorithmParameterException * @throws InvalidAlgorithmParameterException
*/ */
public static KeyPair generateKeyPair(SecureRandom random) public static KeyPair generateKeyPair(SecureRandom random) throws NoSuchProviderException,
throws NoSuchProviderException, NoSuchAlgorithmException, NoSuchAlgorithmException, InvalidAlgorithmParameterException {
InvalidAlgorithmParameterException {
return BCECUtil.generateKeyPair(DOMAIN_PARAMS, random); return BCECUtil.generateKeyPair(DOMAIN_PARAMS, random);
} }
@ -95,9 +90,8 @@ public class SM2Util extends GMBaseUtil {
BCECPrivateKey privateKey = (BCECPrivateKey) key.getPrivate(); BCECPrivateKey privateKey = (BCECPrivateKey) key.getPrivate();
BCECPublicKey publicKey = (BCECPublicKey) key.getPublic(); BCECPublicKey publicKey = (BCECPublicKey) key.getPublic();
byte[] point = publicKey.getQ().getEncoded(false); byte[] point = publicKey.getQ().getEncoded(false);
ECPublicKeyParameters parameters = ECPublicKeyParameters parameters = BCECUtil.createECPublicKeyFromStrParameters(
BCECUtil.createECPublicKeyFromStrParameters( ByteUtils.toHexString(point), CURVE, DOMAIN_PARAMS);
ByteUtils.toHexString(point), CURVE, DOMAIN_PARAMS);
return new SM2KeyPair(parameters, privateKey.getD()); return new SM2KeyPair(parameters, privateKey.getD());
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@ -129,7 +123,7 @@ public class SM2Util extends GMBaseUtil {
} }
/** /**
* @param pubKey 公钥 * @param pubKey 公钥
* @param srcData 原文 * @param srcData 原文
* @return 默认输出C1C3C2顺序的密文C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致 * @return 默认输出C1C3C2顺序的密文C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致
* @throws InvalidCipherTextException * @throws InvalidCipherTextException
@ -141,8 +135,8 @@ public class SM2Util extends GMBaseUtil {
} }
/** /**
* @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2 * @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2
* @param pubKey 公钥 * @param pubKey 公钥
* @param srcData 原文 * @param srcData 原文
* @return 根据mode不同输出的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致 * @return 根据mode不同输出的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致
* @throws InvalidCipherTextException * @throws InvalidCipherTextException
@ -155,7 +149,7 @@ public class SM2Util extends GMBaseUtil {
/** /**
* @param pubKeyParameters 公钥 * @param pubKeyParameters 公钥
* @param srcData 原文 * @param srcData 原文
* @return 默认输出C1C3C2顺序的密文C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致 * @return 默认输出C1C3C2顺序的密文C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致
* @throws InvalidCipherTextException * @throws InvalidCipherTextException
*/ */
@ -165,9 +159,9 @@ public class SM2Util extends GMBaseUtil {
} }
/** /**
* @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2 * @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2
* @param pubKeyParameters 公钥 * @param pubKeyParameters 公钥
* @param srcData 原文 * @param srcData 原文
* @return 根据mode不同输出的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致 * @return 根据mode不同输出的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致
* @throws InvalidCipherTextException * @throws InvalidCipherTextException
*/ */
@ -180,8 +174,9 @@ public class SM2Util extends GMBaseUtil {
} }
/** /**
* @param priKey 私钥 * @param priKey 私钥
* @param sm2Cipher 默认输入C1C3C2顺序的密文C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致 * @param sm2Cipher
* 默认输入C1C3C2顺序的密文C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致
* @return 原文SM2解密返回了数据则一定是原文因为SM2自带校验如果密文被篡改或者密钥对不上都是会直接报异常的 * @return 原文SM2解密返回了数据则一定是原文因为SM2自带校验如果密文被篡改或者密钥对不上都是会直接报异常的
* @throws InvalidCipherTextException * @throws InvalidCipherTextException
*/ */
@ -192,9 +187,10 @@ public class SM2Util extends GMBaseUtil {
} }
/** /**
* @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2 * @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2
* @param priKey 私钥 * @param priKey 私钥
* @param sm2Cipher 根据mode不同需要输入的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致 * @param sm2Cipher
* 根据mode不同需要输入的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致
* @return 原文SM2解密返回了数据则一定是原文因为SM2自带校验如果密文被篡改或者密钥对不上都是会直接报异常的 * @return 原文SM2解密返回了数据则一定是原文因为SM2自带校验如果密文被篡改或者密钥对不上都是会直接报异常的
* @throws InvalidCipherTextException * @throws InvalidCipherTextException
*/ */
@ -206,7 +202,8 @@ public class SM2Util extends GMBaseUtil {
/** /**
* @param priKeyParameters 私钥 * @param priKeyParameters 私钥
* @param sm2Cipher 默认输入C1C3C2顺序的密文C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致 * @param sm2Cipher
* 默认输入C1C3C2顺序的密文C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致
* @return 原文SM2解密返回了数据则一定是原文因为SM2自带校验如果密文被篡改或者密钥对不上都是会直接报异常的 * @return 原文SM2解密返回了数据则一定是原文因为SM2自带校验如果密文被篡改或者密钥对不上都是会直接报异常的
* @throws InvalidCipherTextException * @throws InvalidCipherTextException
*/ */
@ -216,15 +213,15 @@ public class SM2Util extends GMBaseUtil {
} }
/** /**
* @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2 * @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2
* @param priKeyParameters 私钥 * @param priKeyParameters 私钥
* @param sm2Cipher 根据mode不同需要输入的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致 * @param sm2Cipher
* 根据mode不同需要输入的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致
* @return 原文SM2解密返回了数据则一定是原文因为SM2自带校验如果密文被篡改或者密钥对不上都是会直接报异常的 * @return 原文SM2解密返回了数据则一定是原文因为SM2自带校验如果密文被篡改或者密钥对不上都是会直接报异常的
* @throws InvalidCipherTextException * @throws InvalidCipherTextException
*/ */
public static byte[] decrypt( public static byte[] decrypt(Mode mode, ECPrivateKeyParameters priKeyParameters,
Mode mode, ECPrivateKeyParameters priKeyParameters, byte[] sm2Cipher) byte[] sm2Cipher) throws InvalidCipherTextException {
throws InvalidCipherTextException {
SM2Engine engine = new SM2Engine(mode); SM2Engine engine = new SM2Engine(mode);
engine.init(false, priKeyParameters); engine.init(false, priKeyParameters);
if (sm2Cipher[0] != 4) { if (sm2Cipher[0] != 4) {
@ -239,7 +236,8 @@ public class SM2Util extends GMBaseUtil {
/** /**
* 分解SM2密文 * 分解SM2密文
* *
* @param cipherText 默认输入C1C3C2顺序的密文C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致 * @param cipherText
* 默认输入C1C3C2顺序的密文C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致
* @return * @return
* @throws Exception * @throws Exception
*/ */
@ -251,8 +249,9 @@ public class SM2Util extends GMBaseUtil {
/** /**
* 分解SM2密文 * 分解SM2密文
* *
* @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2 * @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2
* @param cipherText 根据mode不同需要输入的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致 * @param cipherText
* 根据mode不同需要输入的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致
* @return * @return
*/ */
public static SM2Cipher parseSM2Cipher(Mode mode, byte[] cipherText) throws Exception { public static SM2Cipher parseSM2Cipher(Mode mode, byte[] cipherText) throws Exception {
@ -261,9 +260,10 @@ public class SM2Util extends GMBaseUtil {
} }
/** /**
* @param curveLength 曲线长度SM2的话就是256位 * @param curveLength 曲线长度SM2的话就是256位
* @param digestLength 摘要长度如果是SM2的话因为默认使用SM3摘要SM3摘要长度为32字节 * @param digestLength 摘要长度如果是SM2的话因为默认使用SM3摘要SM3摘要长度为32字节
* @param cipherText 默认输入C1C3C2顺序的密文C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致 * @param cipherText
* 默认输入C1C3C2顺序的密文C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致
* @return * @return
* @throws Exception * @throws Exception
*/ */
@ -275,14 +275,15 @@ public class SM2Util extends GMBaseUtil {
/** /**
* 分解SM2密文 * 分解SM2密文
* *
* @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2 * @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2
* @param curveLength 曲线长度SM2的话就是256位 * @param curveLength 曲线长度SM2的话就是256位
* @param digestLength 摘要长度如果是SM2的话因为默认使用SM3摘要SM3摘要长度为32字节 * @param digestLength 摘要长度如果是SM2的话因为默认使用SM3摘要SM3摘要长度为32字节
* @param cipherText 根据mode不同需要输入的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致 * @param cipherText
* 根据mode不同需要输入的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致
* @return * @return
*/ */
public static SM2Cipher parseSM2Cipher( public static SM2Cipher parseSM2Cipher(Mode mode, int curveLength, int digestLength,
Mode mode, int curveLength, int digestLength, byte[] cipherText) throws Exception { byte[] cipherText) throws Exception {
byte[] c1 = new byte[curveLength * 2 + 1]; byte[] c1 = new byte[curveLength * 2 + 1];
byte[] c2 = new byte[cipherText.length - c1.length - digestLength]; byte[] c2 = new byte[cipherText.length - c1.length - digestLength];
byte[] c3 = new byte[digestLength]; byte[] c3 = new byte[digestLength];
@ -321,8 +322,9 @@ public class SM2Util extends GMBaseUtil {
/** /**
* DER编码密文 * DER编码密文
* *
* @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2 * @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2
* @param cipher 根据mode不同需要输入的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致 * @param cipher
* 根据mode不同需要输入的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致
* @return 按指定mode DER编码后的密文 * @return 按指定mode DER编码后的密文
* @throws Exception * @throws Exception
*/ */
@ -334,9 +336,9 @@ public class SM2Util extends GMBaseUtil {
/** /**
* DER编码密文 * DER编码密文
* *
* @param curveLength 曲线长度SM2的话就是256位 * @param curveLength 曲线长度SM2的话就是256位
* @param digestLength 摘要长度如果是SM2的话因为默认使用SM3摘要SM3摘要长度为32字节 * @param digestLength 摘要长度如果是SM2的话因为默认使用SM3摘要SM3摘要长度为32字节
* @param cipher 默认输入C1C3C2顺序的密文C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致 * @param cipher 默认输入C1C3C2顺序的密文C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致
* @return 默认输出按C1C3C2编码的结果 * @return 默认输出按C1C3C2编码的结果
* @throws IOException * @throws IOException
*/ */
@ -346,15 +348,16 @@ public class SM2Util extends GMBaseUtil {
} }
/** /**
* @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2 * @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2
* @param curveLength 曲线长度SM2的话就是256位 * @param curveLength 曲线长度SM2的话就是256位
* @param digestLength 摘要长度如果是SM2的话因为默认使用SM3摘要SM3摘要长度为32字节 * @param digestLength 摘要长度如果是SM2的话因为默认使用SM3摘要SM3摘要长度为32字节
* @param cipher 根据mode不同需要输入的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致 * @param cipher
* 根据mode不同需要输入的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致
* @return 按指定mode DER编码后的密文 * @return 按指定mode DER编码后的密文
* @throws Exception * @throws Exception
*/ */
public static byte[] encodeSM2CipherToDER( public static byte[] encodeSM2CipherToDER(Mode mode, int curveLength, int digestLength,
Mode mode, int curveLength, int digestLength, byte[] cipher) throws Exception { byte[] cipher) throws Exception {
byte[] c1x = new byte[curveLength]; byte[] c1x = new byte[curveLength];
byte[] c1y = new byte[curveLength]; byte[] c1y = new byte[curveLength];
@ -379,8 +382,8 @@ public class SM2Util extends GMBaseUtil {
} }
ASN1Encodable[] arr = new ASN1Encodable[4]; ASN1Encodable[] arr = new ASN1Encodable[4];
arr[0] = new ASN1Integer(new BigInteger(1,c1x)); arr[0] = new ASN1Integer(new BigInteger(1, c1x));
arr[1] = new ASN1Integer(new BigInteger(1,c1y)); arr[1] = new ASN1Integer(new BigInteger(1, c1y));
if (mode == Mode.C1C2C3) { if (mode == Mode.C1C2C3) {
arr[2] = new DEROctetString(c2); arr[2] = new DEROctetString(c2);
arr[3] = new DEROctetString(c3); arr[3] = new DEROctetString(c3);
@ -403,7 +406,7 @@ public class SM2Util extends GMBaseUtil {
} }
/** /**
* @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2 * @param mode 指定密文结构旧标准的为C1C2C3新的[SM2密码算法使用规范 GM/T 0009-2012]标准为C1C3C2
* @param derCipher 根据mode输入C1C2C3或C1C3C2顺序DER编码后的密文 * @param derCipher 根据mode输入C1C2C3或C1C3C2顺序DER编码后的密文
* @return 根据mode不同输出的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致 * @return 根据mode不同输出的密文C1C2C3排列顺序不同C1为65字节第1字节为压缩标识这里固定为0x04后面64字节为xy分量各32字节C3为32字节C2长度与原文一致
* @throws Exception * @throws Exception
@ -450,7 +453,7 @@ public class SM2Util extends GMBaseUtil {
/** /**
* 签名 * 签名
* *
* @param priKey 私钥 * @param priKey 私钥
* @param srcData 原文 * @param srcData 原文
* @return DER编码后的签名值 * @return DER编码后的签名值
* @throws CryptoException * @throws CryptoException
@ -464,7 +467,7 @@ public class SM2Util extends GMBaseUtil {
* 签名 不指定withId则默认withId为字节数组:"1234567812345678".getBytes() * 签名 不指定withId则默认withId为字节数组:"1234567812345678".getBytes()
* *
* @param priKeyParameters 私钥 * @param priKeyParameters 私钥
* @param srcData 原文 * @param srcData 原文
* @return DER编码后的签名值 * @return DER编码后的签名值
* @throws CryptoException * @throws CryptoException
*/ */
@ -476,8 +479,8 @@ public class SM2Util extends GMBaseUtil {
/** /**
* 私钥签名 * 私钥签名
* *
* @param priKey 私钥 * @param priKey 私钥
* @param withId 可以为null若为null则默认withId为字节数组:"1234567812345678".getBytes() * @param withId 可以为null若为null则默认withId为字节数组:"1234567812345678".getBytes()
* @param srcData 原文 * @param srcData 原文
* @return DER编码后的签名值 * @return DER编码后的签名值
* @throws CryptoException * @throws CryptoException
@ -492,14 +495,13 @@ public class SM2Util extends GMBaseUtil {
* 签名 * 签名
* *
* @param priKeyParameters 私钥 * @param priKeyParameters 私钥
* @param withId 可以为null若为null则默认withId为字节数组:"1234567812345678".getBytes() * @param withId 可以为null若为null则默认withId为字节数组:"1234567812345678".getBytes()
* @param srcData 源数据 * @param srcData 源数据
* @return DER编码后的签名值 * @return DER编码后的签名值
* @throws CryptoException * @throws CryptoException
*/ */
public static byte[] sign( public static byte[] sign(ECPrivateKeyParameters priKeyParameters, byte[] withId,
ECPrivateKeyParameters priKeyParameters, byte[] withId, byte[] srcData) byte[] srcData) throws CryptoException {
throws CryptoException {
SM2Signer signer = new SM2Signer(); SM2Signer signer = new SM2Signer();
CipherParameters param = null; CipherParameters param = null;
ParametersWithRandom pwr = new ParametersWithRandom(priKeyParameters, new SecureRandom()); ParametersWithRandom pwr = new ParametersWithRandom(priKeyParameters, new SecureRandom());
@ -576,22 +578,22 @@ public class SM2Util extends GMBaseUtil {
* 验签 不指定withId则默认withId为字节数组:"1234567812345678".getBytes() * 验签 不指定withId则默认withId为字节数组:"1234567812345678".getBytes()
* *
* @param pubKeyParameters 公钥 * @param pubKeyParameters 公钥
* @param srcData 原文 * @param srcData 原文
* @param sign DER编码的签名值 * @param sign DER编码的签名值
* @return 验签成功返回true失败返回false * @return 验签成功返回true失败返回false
*/ */
public static boolean verify( public static boolean verify(ECPublicKeyParameters pubKeyParameters, byte[] srcData,
ECPublicKeyParameters pubKeyParameters, byte[] srcData, byte[] sign) { byte[] sign) {
return verify(pubKeyParameters, null, srcData, sign); return verify(pubKeyParameters, null, srcData, sign);
} }
/** /**
* 验签 * 验签
* *
* @param pubKey 公钥 * @param pubKey 公钥
* @param withId 可以为null若为null则默认withId为字节数组:"1234567812345678".getBytes() * @param withId 可以为null若为null则默认withId为字节数组:"1234567812345678".getBytes()
* @param srcData 原文 * @param srcData 原文
* @param sign DER编码的签名值 * @param sign DER编码的签名值
* @return * @return
*/ */
public static boolean verify(BCECPublicKey pubKey, byte[] withId, byte[] srcData, byte[] sign) { public static boolean verify(BCECPublicKey pubKey, byte[] withId, byte[] srcData, byte[] sign) {
@ -603,13 +605,13 @@ public class SM2Util extends GMBaseUtil {
* 验签 * 验签
* *
* @param pubKeyParameters 公钥 * @param pubKeyParameters 公钥
* @param withId 可以为null若为null则默认withId为字节数组:"1234567812345678".getBytes() * @param withId 可以为null若为null则默认withId为字节数组:"1234567812345678".getBytes()
* @param srcData 原文 * @param srcData 原文
* @param sign DER编码的签名值 * @param sign DER编码的签名值
* @return 验签成功返回true失败返回false * @return 验签成功返回true失败返回false
*/ */
public static boolean verify( public static boolean verify(ECPublicKeyParameters pubKeyParameters, byte[] withId,
ECPublicKeyParameters pubKeyParameters, byte[] withId, byte[] srcData, byte[] sign) { byte[] srcData, byte[] sign) {
SM2Signer signer = new SM2Signer(); SM2Signer signer = new SM2Signer();
CipherParameters param; CipherParameters param;
if (withId != null) { if (withId != null) {
@ -647,13 +649,12 @@ public class SM2Util extends GMBaseUtil {
byte[] sigByte = ByteUtils.fromHexString(signature); byte[] sigByte = ByteUtils.fromHexString(signature);
// TODO 是否需要der编码 // TODO 是否需要der编码
// try { // try {
// sigByte = SM2Util.encodeSM2SignToDER(sigByte); // sigByte = SM2Util.encodeSM2SignToDER(sigByte);
// } catch (Exception e) { // } catch (Exception e) {
// e.printStackTrace(); // e.printStackTrace();
// } // }
ECPublicKeyParameters pubkey = ECPublicKeyParameters pubkey = BCECUtil.createECPublicKeyFromStrParameters(publicKey,
BCECUtil.createECPublicKeyFromStrParameters( SM2Util.CURVE, SM2Util.DOMAIN_PARAMS);
publicKey, SM2Util.CURVE, SM2Util.DOMAIN_PARAMS);
boolean result = SM2Util.verify(pubkey, toVerify.getBytes(), sigByte); boolean result = SM2Util.verify(pubkey, toVerify.getBytes(), sigByte);
return result; return result;
} catch (Exception e) { } catch (Exception e) {

View File

@ -41,7 +41,7 @@ public class SM3Util extends GMBaseUtil {
/** /**
* 计算SM3 Mac值 * 计算SM3 Mac值
* *
* @param key key值可以是任意长度的字节数组 * @param key key值可以是任意长度的字节数组
* @param srcData 原文 * @param srcData 原文
* @return Mac值对于HMac-SM3来说是32字节 * @return Mac值对于HMac-SM3来说是32字节
*/ */

View File

@ -32,8 +32,10 @@ public class SM4Util extends GMBaseUtil {
return generateKey(DEFAULT_KEY_SIZE); return generateKey(DEFAULT_KEY_SIZE);
} }
public static byte[] generateKey(int keySize) throws NoSuchAlgorithmException, NoSuchProviderException { public static byte[] generateKey(int keySize)
KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME); throws NoSuchAlgorithmException, NoSuchProviderException {
KeyGenerator kg =
KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
kg.init(keySize, new SecureRandom()); kg.init(keySize, new SecureRandom());
return kg.generateKey().getEncoded(); return kg.generateKey().getEncoded();
} }
@ -86,7 +88,8 @@ public class SM4Util extends GMBaseUtil {
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException,
NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException,
InvalidAlgorithmParameterException { InvalidAlgorithmParameterException {
Cipher cipher = generateCBCCipher(ALGORITHM_NAME_CBC_NOPADDING, Cipher.ENCRYPT_MODE, key, iv); Cipher cipher =
generateCBCCipher(ALGORITHM_NAME_CBC_NOPADDING, Cipher.ENCRYPT_MODE, key, iv);
return cipher.doFinal(data); return cipher.doFinal(data);
} }
@ -94,18 +97,20 @@ public class SM4Util extends GMBaseUtil {
throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException,
NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
InvalidAlgorithmParameterException { InvalidAlgorithmParameterException {
Cipher cipher = generateCBCCipher(ALGORITHM_NAME_CBC_NOPADDING, Cipher.DECRYPT_MODE, key, iv); Cipher cipher =
generateCBCCipher(ALGORITHM_NAME_CBC_NOPADDING, Cipher.DECRYPT_MODE, key, iv);
return cipher.doFinal(cipherText); return cipher.doFinal(cipherText);
} }
public static byte[] doCMac(byte[] key, byte[] data) throws NoSuchProviderException, NoSuchAlgorithmException, public static byte[] doCMac(byte[] key, byte[] data)
InvalidKeyException { throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException {
Key keyObj = new SecretKeySpec(key, ALGORITHM_NAME); Key keyObj = new SecretKeySpec(key, ALGORITHM_NAME);
return doMac("SM4-CMAC", keyObj, data); return doMac("SM4-CMAC", keyObj, data);
} }
public static byte[] doGMac(byte[] key, byte[] iv, int tagLength, byte[] data) { public static byte[] doGMac(byte[] key, byte[] iv, int tagLength, byte[] data) {
org.bouncycastle.crypto.Mac mac = new GMac(new GCMBlockCipher(new SM4Engine()), tagLength * 8); org.bouncycastle.crypto.Mac mac =
new GMac(new GCMBlockCipher(new SM4Engine()), tagLength * 8);
return doMac(mac, key, iv, data); return doMac(mac, key, iv, data);
} }
@ -119,7 +124,8 @@ public class SM4Util extends GMBaseUtil {
*/ */
public static byte[] doCBCMac(byte[] key, byte[] iv, byte[] data) { public static byte[] doCBCMac(byte[] key, byte[] iv, byte[] data) {
SM4Engine engine = new SM4Engine(); SM4Engine engine = new SM4Engine();
org.bouncycastle.crypto.Mac mac = new CBCBlockCipherMac(engine, engine.getBlockSize() * 8, new PKCS7Padding()); org.bouncycastle.crypto.Mac mac =
new CBCBlockCipherMac(engine, engine.getBlockSize() * 8, new PKCS7Padding());
return doMac(mac, key, iv, data); return doMac(mac, key, iv, data);
} }
@ -131,19 +137,22 @@ public class SM4Util extends GMBaseUtil {
* @return * @return
* @throws Exception * @throws Exception
*/ */
public static byte[] doCBCMac(byte[] key, byte[] iv, BlockCipherPadding padding, byte[] data) throws Exception { public static byte[] doCBCMac(byte[] key, byte[] iv, BlockCipherPadding padding, byte[] data)
throws Exception {
SM4Engine engine = new SM4Engine(); SM4Engine engine = new SM4Engine();
if (padding == null) { if (padding == null) {
if (data.length % engine.getBlockSize() != 0) { if (data.length % engine.getBlockSize() != 0) {
throw new Exception("if no padding, data length must be multiple of SM4 BlockSize"); throw new Exception("if no padding, data length must be multiple of SM4 BlockSize");
} }
} }
org.bouncycastle.crypto.Mac mac = new CBCBlockCipherMac(engine, engine.getBlockSize() * 8, padding); org.bouncycastle.crypto.Mac mac =
new CBCBlockCipherMac(engine, engine.getBlockSize() * 8, padding);
return doMac(mac, key, iv, data); return doMac(mac, key, iv, data);
} }
private static byte[] doMac(org.bouncycastle.crypto.Mac mac, byte[] key, byte[] iv, byte[] data) { private static byte[] doMac(org.bouncycastle.crypto.Mac mac, byte[] key, byte[] iv,
byte[] data) {
CipherParameters cipherParameters = new KeyParameter(key); CipherParameters cipherParameters = new KeyParameter(key);
mac.init(new ParametersWithIV(cipherParameters, iv)); mac.init(new ParametersWithIV(cipherParameters, iv));
mac.update(data, 0, data.length); mac.update(data, 0, data.length);
@ -152,8 +161,8 @@ public class SM4Util extends GMBaseUtil {
return result; return result;
} }
private static byte[] doMac(String algorithmName, Key key, byte[] data) throws NoSuchProviderException, private static byte[] doMac(String algorithmName, Key key, byte[] data)
NoSuchAlgorithmException, InvalidKeyException { throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException {
Mac mac = Mac.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME); Mac mac = Mac.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
mac.init(key); mac.init(key);
mac.update(data); mac.update(data);
@ -170,8 +179,8 @@ public class SM4Util extends GMBaseUtil {
} }
private static Cipher generateCBCCipher(String algorithmName, int mode, byte[] key, byte[] iv) private static Cipher generateCBCCipher(String algorithmName, int mode, byte[] key, byte[] iv)
throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, throws InvalidKeyException, InvalidAlgorithmParameterException,
NoSuchProviderException, NoSuchPaddingException { NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException {
Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME); Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME); Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

View File

@ -29,7 +29,8 @@ public class CommonUtil {
* @return * @return
* @throws InvalidX500NameException * @throws InvalidX500NameException
*/ */
public static X500Name buildX500Name(Map<String, String> names) throws InvalidX500NameException { public static X500Name buildX500Name(Map<String, String> names)
throws InvalidX500NameException {
if (names == null || names.size() == 0) { if (names == null || names.size() == 0) {
throw new InvalidX500NameException("names can not be empty"); throw new InvalidX500NameException("names can not be empty");
} }
@ -49,21 +50,24 @@ public class CommonUtil {
} }
} }
public static PKCS10CertificationRequest createCSR(X500Name subject, SM2PublicKey pubKey, PrivateKey priKey, public static PKCS10CertificationRequest createCSR(X500Name subject, SM2PublicKey pubKey,
String signAlgo) throws OperatorCreationException { PrivateKey priKey, String signAlgo) throws OperatorCreationException {
PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(subject, pubKey); PKCS10CertificationRequestBuilder csrBuilder =
new JcaPKCS10CertificationRequestBuilder(subject, pubKey);
ContentSigner signerBuilder = new JcaContentSignerBuilder(signAlgo) ContentSigner signerBuilder = new JcaContentSignerBuilder(signAlgo)
.setProvider(BouncyCastleProvider.PROVIDER_NAME).build(priKey); .setProvider(BouncyCastleProvider.PROVIDER_NAME).build(priKey);
return csrBuilder.build(signerBuilder); return csrBuilder.build(signerBuilder);
} }
public static AlgorithmIdentifier findSignatureAlgorithmIdentifier(String algoName) { public static AlgorithmIdentifier findSignatureAlgorithmIdentifier(String algoName) {
DefaultSignatureAlgorithmIdentifierFinder sigFinder = new DefaultSignatureAlgorithmIdentifierFinder(); DefaultSignatureAlgorithmIdentifierFinder sigFinder =
new DefaultSignatureAlgorithmIdentifierFinder();
return sigFinder.find(algoName); return sigFinder.find(algoName);
} }
public static AlgorithmIdentifier findDigestAlgorithmIdentifier(String algoName) { public static AlgorithmIdentifier findDigestAlgorithmIdentifier(String algoName) {
DefaultDigestAlgorithmIdentifierFinder digFinder = new DefaultDigestAlgorithmIdentifierFinder(); DefaultDigestAlgorithmIdentifierFinder digFinder =
new DefaultDigestAlgorithmIdentifierFinder();
return digFinder.find(findSignatureAlgorithmIdentifier(algoName)); return digFinder.find(findSignatureAlgorithmIdentifier(algoName));
} }
} }

View File

@ -32,7 +32,7 @@ public class RandomSNAllocator implements CertSNAllocator {
private static int[] AND_MASKS = new int[] {0xFF, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F}; private static int[] AND_MASKS = new int[] {0xFF, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F};
private static int[] OR_MASKS = new int[] {0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40}; private static int[] OR_MASKS = new int[] {0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40};
private final SecureRandom random; private final SecureRandom random;
@ -47,14 +47,15 @@ public class RandomSNAllocator implements CertSNAllocator {
/** /**
* Constructor with the specification of bitLen. * Constructor with the specification of bitLen.
*
* @param bitLen bit length of the serial number. The highest bit is always set to 1, so the * @param bitLen bit length of the serial number. The highest bit is always set to 1, so the
* effective bit length is bitLen - 1. Valid value is [65, 159]. * effective bit length is bitLen - 1. Valid value is [65, 159].
*/ */
public RandomSNAllocator(int bitLen) { public RandomSNAllocator(int bitLen) {
if (bitLen < MIN_SERIALNUMBER_SIZE || bitLen > MAX_SERIALNUMBER_SIZE) { if (bitLen < MIN_SERIALNUMBER_SIZE || bitLen > MAX_SERIALNUMBER_SIZE) {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(
"%s may not be out of the range [%d, %d]: %d", String.format("%s may not be out of the range [%d, %d]: %d", "bitLen",
"bitLen", MIN_SERIALNUMBER_SIZE, MAX_SERIALNUMBER_SIZE, bitLen)); MIN_SERIALNUMBER_SIZE, MAX_SERIALNUMBER_SIZE, bitLen));
} }
this.random = new SecureRandom(); this.random = new SecureRandom();

View File

@ -33,17 +33,17 @@ public class SM2CertUtil {
ECPublicKey pubKey = (ECPublicKey) sm2Cert.getPublicKey(); ECPublicKey pubKey = (ECPublicKey) sm2Cert.getPublicKey();
ECPoint q = pubKey.getQ(); ECPoint q = pubKey.getQ();
ECParameterSpec parameterSpec = new ECParameterSpec(SM2Util.CURVE, SM2Util.G_POINT, ECParameterSpec parameterSpec = new ECParameterSpec(SM2Util.CURVE, SM2Util.G_POINT,
SM2Util.SM2_ECC_N, SM2Util.SM2_ECC_H); SM2Util.SM2_ECC_N, SM2Util.SM2_ECC_H);
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(q, parameterSpec); ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(q, parameterSpec);
return new BCECPublicKey(pubKey.getAlgorithm(), pubKeySpec, return new BCECPublicKey(pubKey.getAlgorithm(), pubKeySpec,
BouncyCastleProvider.CONFIGURATION); BouncyCastleProvider.CONFIGURATION);
} }
/** /**
* 校验证书 * 校验证书
* *
* @param issuerPubKey 从颁发者CA证书中提取出来的公钥 * @param issuerPubKey 从颁发者CA证书中提取出来的公钥
* @param cert 待校验的证书 * @param cert 待校验的证书
* @return * @return
*/ */
public static boolean verifyCertificate(BCECPublicKey issuerPubKey, X509Certificate cert) { public static boolean verifyCertificate(BCECPublicKey issuerPubKey, X509Certificate cert) {
@ -55,8 +55,8 @@ public class SM2CertUtil {
return true; return true;
} }
public static X509Certificate getX509Certificate(String certFilePath) throws IOException, CertificateException, public static X509Certificate getX509Certificate(String certFilePath)
NoSuchProviderException { throws IOException, CertificateException, NoSuchProviderException {
InputStream is = null; InputStream is = null;
try { try {
is = new FileInputStream(certFilePath); is = new FileInputStream(certFilePath);
@ -68,20 +68,21 @@ public class SM2CertUtil {
} }
} }
public static X509Certificate getX509Certificate(byte[] certBytes) throws CertificateException, public static X509Certificate getX509Certificate(byte[] certBytes)
NoSuchProviderException { throws CertificateException, NoSuchProviderException {
ByteArrayInputStream bais = new ByteArrayInputStream(certBytes); ByteArrayInputStream bais = new ByteArrayInputStream(certBytes);
return getX509Certificate(bais); return getX509Certificate(bais);
} }
public static X509Certificate getX509Certificate(InputStream is) throws CertificateException, public static X509Certificate getX509Certificate(InputStream is)
NoSuchProviderException { throws CertificateException, NoSuchProviderException {
CertificateFactory cf = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME); CertificateFactory cf =
CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
return (X509Certificate) cf.generateCertificate(is); return (X509Certificate) cf.generateCertificate(is);
} }
public static CertPath getCertificateChain(String certChainPath) throws IOException, CertificateException, public static CertPath getCertificateChain(String certChainPath)
NoSuchProviderException { throws IOException, CertificateException, NoSuchProviderException {
InputStream is = null; InputStream is = null;
try { try {
is = new FileInputStream(certChainPath); is = new FileInputStream(certChainPath);
@ -93,30 +94,37 @@ public class SM2CertUtil {
} }
} }
public static CertPath getCertificateChain(byte[] certChainBytes) throws CertificateException, public static CertPath getCertificateChain(byte[] certChainBytes)
NoSuchProviderException { throws CertificateException, NoSuchProviderException {
ByteArrayInputStream bais = new ByteArrayInputStream(certChainBytes); ByteArrayInputStream bais = new ByteArrayInputStream(certChainBytes);
return getCertificateChain(bais); return getCertificateChain(bais);
} }
public static byte[] getCertificateChainBytes(CertPath certChain) throws CertificateEncodingException { public static byte[] getCertificateChainBytes(CertPath certChain)
throws CertificateEncodingException {
return certChain.getEncoded("PKCS7"); return certChain.getEncoded("PKCS7");
} }
public static CertPath getCertificateChain(InputStream is) throws CertificateException, NoSuchProviderException { public static CertPath getCertificateChain(InputStream is)
CertificateFactory cf = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME); throws CertificateException, NoSuchProviderException {
CertificateFactory cf =
CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
return cf.generateCertPath(is, "PKCS7"); return cf.generateCertPath(is, "PKCS7");
} }
public static CertPath getCertificateChain(List<X509Certificate> certs) throws CertificateException, public static CertPath getCertificateChain(List<X509Certificate> certs)
NoSuchProviderException { throws CertificateException, NoSuchProviderException {
CertificateFactory cf = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME); CertificateFactory cf =
CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
return cf.generateCertPath(certs); return cf.generateCertPath(certs);
} }
public static X509Certificate getX509CertificateFromPfx(byte[] pfxDER, String passwd) throws Exception { public static X509Certificate getX509CertificateFromPfx(byte[] pfxDER, String passwd)
InputDecryptorProvider inputDecryptorProvider = new JcePKCSPBEInputDecryptorProviderBuilder() throws Exception {
.setProvider(BouncyCastleProvider.PROVIDER_NAME).build(passwd.toCharArray()); InputDecryptorProvider inputDecryptorProvider =
new JcePKCSPBEInputDecryptorProviderBuilder()
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
.build(passwd.toCharArray());
PKCS12PfxPdu pfx = new PKCS12PfxPdu(pfxDER); PKCS12PfxPdu pfx = new PKCS12PfxPdu(pfxDER);
ContentInfo[] infos = pfx.getContentInfos(); ContentInfo[] infos = pfx.getContentInfos();
@ -126,7 +134,8 @@ public class SM2CertUtil {
for (int i = 0; i != infos.length; i++) { for (int i = 0; i != infos.length; i++) {
if (infos[i].getContentType().equals(PKCSObjectIdentifiers.encryptedData)) { if (infos[i].getContentType().equals(PKCSObjectIdentifiers.encryptedData)) {
PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i], inputDecryptorProvider); PKCS12SafeBagFactory dataFact =
new PKCS12SafeBagFactory(infos[i], inputDecryptorProvider);
PKCS12SafeBag[] bags = dataFact.getSafeBags(); PKCS12SafeBag[] bags = dataFact.getSafeBags();
X509CertificateHolder certHoler = (X509CertificateHolder) bags[0].getBagValue(); X509CertificateHolder certHoler = (X509CertificateHolder) bags[0].getBagValue();
return SM2CertUtil.getX509Certificate(certHoler.getEncoded()); return SM2CertUtil.getX509Certificate(certHoler.getEncoded());
@ -140,9 +149,12 @@ public class SM2CertUtil {
return SM2CertUtil.getBCECPublicKey(getX509CertificateFromPfx(pfxDER, passwd)); return SM2CertUtil.getBCECPublicKey(getX509CertificateFromPfx(pfxDER, passwd));
} }
public static BCECPrivateKey getPrivateKeyFromPfx(byte[] pfxDER, String passwd) throws Exception { public static BCECPrivateKey getPrivateKeyFromPfx(byte[] pfxDER, String passwd)
InputDecryptorProvider inputDecryptorProvider = new JcePKCSPBEInputDecryptorProviderBuilder() throws Exception {
.setProvider(BouncyCastleProvider.PROVIDER_NAME).build(passwd.toCharArray()); InputDecryptorProvider inputDecryptorProvider =
new JcePKCSPBEInputDecryptorProviderBuilder()
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
.build(passwd.toCharArray());
PKCS12PfxPdu pfx = new PKCS12PfxPdu(pfxDER); PKCS12PfxPdu pfx = new PKCS12PfxPdu(pfxDER);
ContentInfo[] infos = pfx.getContentInfos(); ContentInfo[] infos = pfx.getContentInfos();
@ -154,7 +166,8 @@ public class SM2CertUtil {
if (!infos[i].getContentType().equals(PKCSObjectIdentifiers.encryptedData)) { if (!infos[i].getContentType().equals(PKCSObjectIdentifiers.encryptedData)) {
PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i]); PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i]);
PKCS12SafeBag[] bags = dataFact.getSafeBags(); PKCS12SafeBag[] bags = dataFact.getSafeBags();
PKCS8EncryptedPrivateKeyInfo encInfo = (PKCS8EncryptedPrivateKeyInfo) bags[0].getBagValue(); PKCS8EncryptedPrivateKeyInfo encInfo =
(PKCS8EncryptedPrivateKeyInfo) bags[0].getBagValue();
PrivateKeyInfo info = encInfo.decryptPrivateKeyInfo(inputDecryptorProvider); PrivateKeyInfo info = encInfo.decryptPrivateKeyInfo(inputDecryptorProvider);
BCECPrivateKey privateKey = BCECUtil.convertPKCS8ToECPrivateKey(info.getEncoded()); BCECPrivateKey privateKey = BCECUtil.convertPKCS8ToECPrivateKey(info.getEncoded());
return privateKey; return privateKey;

View File

@ -21,41 +21,41 @@ public class SM2PfxMaker {
/** /**
* @param privKey 用户私钥 * @param privKey 用户私钥
* @param pubKey 用户公钥 * @param pubKey 用户公钥
* @param chain X509证书数组切记这里固定了必须是3个元素的数组且第一个必须是叶子证书第二个为中级CA证书第三个为根CA证书 * @param chain X509证书数组切记这里固定了必须是3个元素的数组且第一个必须是叶子证书第二个为中级CA证书第三个为根CA证书
* @param passwd 口令 * @param passwd 口令
* @return * @return
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException
* @throws IOException * @throws IOException
* @throws PKCSException * @throws PKCSException
*/ */
public PKCS12PfxPdu makePfx(PrivateKey privKey, PublicKey pubKey, X509Certificate[] chain, String passwd) public PKCS12PfxPdu makePfx(PrivateKey privKey, PublicKey pubKey, X509Certificate[] chain,
throws NoSuchAlgorithmException, IOException, PKCSException { String passwd) throws NoSuchAlgorithmException, IOException, PKCSException {
JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils(); JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
PKCS12SafeBagBuilder taCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[2]); PKCS12SafeBagBuilder taCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[2]);
taCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, taCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
new DERBMPString("Primary Certificate")); new DERBMPString("Primary Certificate"));
PKCS12SafeBagBuilder caCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[1]); PKCS12SafeBagBuilder caCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[1]);
caCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, caCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
new DERBMPString("Intermediate Certificate")); new DERBMPString("Intermediate Certificate"));
PKCS12SafeBagBuilder eeCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[0]); PKCS12SafeBagBuilder eeCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[0]);
eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
new DERBMPString("User Key")); new DERBMPString("User Key"));
eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId,
extUtils.createSubjectKeyIdentifier(pubKey)); extUtils.createSubjectKeyIdentifier(pubKey));
char[] passwdChars = passwd.toCharArray(); char[] passwdChars = passwd.toCharArray();
PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(privKey, PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(privKey,
new BcPKCS12PBEOutputEncryptorBuilder( new BcPKCS12PBEOutputEncryptorBuilder(
PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC,
new CBCBlockCipher(new DESedeEngine())).build(passwdChars)); new CBCBlockCipher(new DESedeEngine())).build(passwdChars));
keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
new DERBMPString("User Key")); new DERBMPString("User Key"));
keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId,
extUtils.createSubjectKeyIdentifier(pubKey)); extUtils.createSubjectKeyIdentifier(pubKey));
PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder(); PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder();
PKCS12SafeBag[] certs = new PKCS12SafeBag[3]; PKCS12SafeBag[] certs = new PKCS12SafeBag[3];
@ -64,49 +64,47 @@ public class SM2PfxMaker {
certs[2] = taCertBagBuilder.build(); certs[2] = taCertBagBuilder.build();
pfxPduBuilder.addEncryptedData(new BcPKCS12PBEOutputEncryptorBuilder( pfxPduBuilder.addEncryptedData(new BcPKCS12PBEOutputEncryptorBuilder(
PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC,
new CBCBlockCipher(new RC2Engine())).build(passwdChars), new CBCBlockCipher(new RC2Engine())).build(passwdChars), certs);
certs);
pfxPduBuilder.addData(keyBagBuilder.build()); pfxPduBuilder.addData(keyBagBuilder.build());
return pfxPduBuilder.build(new BcPKCS12MacCalculatorBuilder(), passwdChars); return pfxPduBuilder.build(new BcPKCS12MacCalculatorBuilder(), passwdChars);
} }
/** /**
* @param privKey 用户私钥 * @param privKey 用户私钥
* @param pubKey 用户公钥 * @param pubKey 用户公钥
* @param cert X509证书 * @param cert X509证书
* @param passwd 口令 * @param passwd 口令
* @return * @return
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException
* @throws IOException * @throws IOException
* @throws PKCSException * @throws PKCSException
*/ */
public PKCS12PfxPdu makePfx(PrivateKey privKey, PublicKey pubKey, X509Certificate cert, String passwd) public PKCS12PfxPdu makePfx(PrivateKey privKey, PublicKey pubKey, X509Certificate cert,
throws NoSuchAlgorithmException, IOException, PKCSException { String passwd) throws NoSuchAlgorithmException, IOException, PKCSException {
JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils(); JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
PKCS12SafeBagBuilder eeCertBagBuilder = new JcaPKCS12SafeBagBuilder(cert); PKCS12SafeBagBuilder eeCertBagBuilder = new JcaPKCS12SafeBagBuilder(cert);
eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
new DERBMPString("User Key")); new DERBMPString("User Key"));
eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId,
extUtils.createSubjectKeyIdentifier(pubKey)); extUtils.createSubjectKeyIdentifier(pubKey));
char[] passwdChars = passwd.toCharArray(); char[] passwdChars = passwd.toCharArray();
PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(privKey, PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(privKey,
new BcPKCS12PBEOutputEncryptorBuilder( new BcPKCS12PBEOutputEncryptorBuilder(
PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC,
new CBCBlockCipher(new DESedeEngine())).build(passwdChars)); new CBCBlockCipher(new DESedeEngine())).build(passwdChars));
keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
new DERBMPString("User Key")); new DERBMPString("User Key"));
keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId,
extUtils.createSubjectKeyIdentifier(pubKey)); extUtils.createSubjectKeyIdentifier(pubKey));
PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder(); PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder();
PKCS12SafeBag[] certs = new PKCS12SafeBag[1]; PKCS12SafeBag[] certs = new PKCS12SafeBag[1];
certs[0] = eeCertBagBuilder.build(); certs[0] = eeCertBagBuilder.build();
pfxPduBuilder.addEncryptedData(new BcPKCS12PBEOutputEncryptorBuilder( pfxPduBuilder.addEncryptedData(new BcPKCS12PBEOutputEncryptorBuilder(
PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC,
new CBCBlockCipher(new RC2Engine())).build(passwdChars), new CBCBlockCipher(new RC2Engine())).build(passwdChars), certs);
certs);
pfxPduBuilder.addData(keyBagBuilder.build()); pfxPduBuilder.addData(keyBagBuilder.build());
return pfxPduBuilder.build(new BcPKCS12MacCalculatorBuilder(), passwdChars); return pfxPduBuilder.build(new BcPKCS12MacCalculatorBuilder(), passwdChars);
} }

View File

@ -12,9 +12,8 @@ public class SM2Pkcs12Maker {
/** /**
* @param privKey 用户私钥 * @param privKey 用户私钥
* @param chain X509证书数组 * @param chain X509证书数组 第一个index 0为privKey对应的证书index i+1 是index i的CA证书
* 第一个index 0为privKey对应的证书index i+1 是index i的CA证书 * @param passwd 口令
* @param passwd 口令
* @return the PKCS#12 keystore * @return the PKCS#12 keystore
* @throws NoSuchProviderException * @throws NoSuchProviderException
* @throws KeyStoreException * @throws KeyStoreException
@ -24,8 +23,8 @@ public class SM2Pkcs12Maker {
* @throws PKCSException * @throws PKCSException
*/ */
public KeyStore makePkcs12(PrivateKey privKey, X509Certificate[] chain, char[] passwd) public KeyStore makePkcs12(PrivateKey privKey, X509Certificate[] chain, char[] passwd)
throws KeyStoreException, NoSuchProviderException, throws KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException,
NoSuchAlgorithmException, CertificateException, IOException { CertificateException, IOException {
KeyStore ks = KeyStore.getInstance("PKCS12", "BC"); KeyStore ks = KeyStore.getInstance("PKCS12", "BC");
ks.load(null, passwd); ks.load(null, passwd);
ks.setKeyEntry("User Key", privKey, passwd, chain); ks.setKeyEntry("User Key", privKey, passwd, chain);
@ -34,16 +33,16 @@ public class SM2Pkcs12Maker {
/** /**
* @param privKey 用户私钥 * @param privKey 用户私钥
* @param cert X509证书 * @param cert X509证书
* @param passwd 口令 * @param passwd 口令
* @return the PKCS12 keystore * @return the PKCS12 keystore
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException
* @throws IOException * @throws IOException
* @throws PKCSException * @throws PKCSException
*/ */
public KeyStore makePkcs12(PrivateKey privKey, X509Certificate cert, char[] passwd) public KeyStore makePkcs12(PrivateKey privKey, X509Certificate cert, char[] passwd)
throws KeyStoreException, NoSuchProviderException, throws KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException,
NoSuchAlgorithmException, CertificateException, IOException { CertificateException, IOException {
return makePkcs12(privKey, new X509Certificate[] {cert}, passwd); return makePkcs12(privKey, new X509Certificate[] {cert}, passwd);
} }
} }

View File

@ -23,7 +23,8 @@ public class SM2PrivateKey extends BCECPrivateKey {
public SM2PrivateKey(BCECPrivateKey privateKey, BCECPublicKey publicKey) { public SM2PrivateKey(BCECPrivateKey privateKey, BCECPublicKey publicKey) {
super(privateKey.getAlgorithm(), privateKey); super(privateKey.getAlgorithm(), privateKey);
this.sm2PublicKey = getSM2PublicKeyDetails(new SM2PublicKey(publicKey.getAlgorithm(), publicKey)); this.sm2PublicKey =
getSM2PublicKeyDetails(new SM2PublicKey(publicKey.getAlgorithm(), publicKey));
this.withCompression = false; this.withCompression = false;
} }
@ -33,8 +34,8 @@ public class SM2PrivateKey extends BCECPrivateKey {
} }
/** /**
* Return a PKCS8 representation of the key. The sequence returned * Return a PKCS8 representation of the key. The sequence returned represents a full
* represents a full PrivateKeyInfo object. * PrivateKeyInfo object.
* *
* @return a PKCS8 representation of the key. * @return a PKCS8 representation of the key.
*/ */
@ -48,20 +49,25 @@ public class SM2PrivateKey extends BCECPrivateKey {
if (ecSpec == null) { if (ecSpec == null) {
orderBitLength = ECUtil.getOrderBitLength(configuration, null, this.getS()); orderBitLength = ECUtil.getOrderBitLength(configuration, null, this.getS());
} else { } else {
orderBitLength = ECUtil.getOrderBitLength(configuration, ecSpec.getOrder(), this.getS()); orderBitLength =
ECUtil.getOrderBitLength(configuration, ecSpec.getOrder(), this.getS());
} }
PrivateKeyInfo info; PrivateKeyInfo info;
org.bouncycastle.asn1.sec.ECPrivateKey keyStructure; org.bouncycastle.asn1.sec.ECPrivateKey keyStructure;
if (sm2PublicKey != null) { if (sm2PublicKey != null) {
keyStructure = new org.bouncycastle.asn1.sec.ECPrivateKey(orderBitLength, this.getS(), sm2PublicKey, params); keyStructure = new org.bouncycastle.asn1.sec.ECPrivateKey(orderBitLength, this.getS(),
sm2PublicKey, params);
} else { } else {
keyStructure = new org.bouncycastle.asn1.sec.ECPrivateKey(orderBitLength, this.getS(), params); keyStructure =
new org.bouncycastle.asn1.sec.ECPrivateKey(orderBitLength, this.getS(), params);
} }
try { try {
info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), keyStructure); info = new PrivateKeyInfo(
new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params),
keyStructure);
return info.getEncoded(ASN1Encoding.DER); return info.getEncoded(ASN1Encoding.DER);
} catch (IOException e) { } catch (IOException e) {
@ -71,10 +77,11 @@ public class SM2PrivateKey extends BCECPrivateKey {
private DERBitString getSM2PublicKeyDetails(SM2PublicKey pub) { private DERBitString getSM2PublicKeyDetails(SM2PublicKey pub) {
try { try {
SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded())); SubjectPublicKeyInfo info =
SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
return info.getPublicKeyData(); return info.getPublicKeyData();
} catch (IOException e) { // should never happen } catch (IOException e) { // should never happen
return null; return null;
} }
} }

View File

@ -10,7 +10,8 @@ import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
public class SM2PublicKey extends BCECPublicKey { public class SM2PublicKey extends BCECPublicKey {
public static final ASN1ObjectIdentifier ID_SM2_PUBKEY_PARAM = new ASN1ObjectIdentifier("1.2.156.10197.1.301"); public static final ASN1ObjectIdentifier ID_SM2_PUBKEY_PARAM =
new ASN1ObjectIdentifier("1.2.156.10197.1.301");
private boolean withCompression; private boolean withCompression;
@ -26,13 +27,13 @@ public class SM2PublicKey extends BCECPublicKey {
@Override @Override
public byte[] getEncoded() { public byte[] getEncoded() {
ASN1OctetString p = ASN1OctetString.getInstance( ASN1OctetString p = ASN1OctetString
new X9ECPoint(getQ(), withCompression).toASN1Primitive()); .getInstance(new X9ECPoint(getQ(), withCompression).toASN1Primitive());
// stored curve is null if ImplicitlyCa // stored curve is null if ImplicitlyCa
SubjectPublicKeyInfo info = new SubjectPublicKeyInfo( SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, ID_SM2_PUBKEY_PARAM), new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, ID_SM2_PUBKEY_PARAM),
p.getOctets()); p.getOctets());
return KeyUtil.getEncodedSubjectPublicKeyInfo(info); return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
} }

View File

@ -28,9 +28,7 @@ import java.util.List;
public class SM2X509CertMaker { public class SM2X509CertMaker {
private static enum CertLevel { private static enum CertLevel {
RootCA, RootCA, SubCA, EndEntity
SubCA,
EndEntity
} // class CertLevel } // class CertLevel
public static final String SIGN_ALGO_SM3WITHSM2 = "SM3withSM2"; public static final String SIGN_ALGO_SM3WITHSM2 = "SM3withSM2";
@ -41,16 +39,14 @@ public class SM2X509CertMaker {
private KeyPair issuerKeyPair; private KeyPair issuerKeyPair;
/** /**
* @param issuerKeyPair 证书颁发者的密钥对 * @param issuerKeyPair 证书颁发者的密钥对 其实一般的CA的私钥都是要严格保护的 一般CA的私钥都会放在加密卡/加密机里证书的签名由加密卡/加密机完成
* 其实一般的CA的私钥都是要严格保护的 * 这里仅是为了演示BC库签发证书的用法所以暂时不作太多要求
* 一般CA的私钥都会放在加密卡/加密机里证书的签名由加密卡/加密机完成 * @param certExpire 证书有效时间单位毫秒
* 这里仅是为了演示BC库签发证书的用法所以暂时不作太多要求 * @param issuer 证书颁发者信息
* @param certExpire 证书有效时间单位毫秒 * @param snAllocator 维护/分配证书序列号的实例证书序列号应该递增且不重复
* @param issuer 证书颁发者信息
* @param snAllocator 维护/分配证书序列号的实例证书序列号应该递增且不重复
*/ */
public SM2X509CertMaker(KeyPair issuerKeyPair, long certExpire, X500Name issuer, public SM2X509CertMaker(KeyPair issuerKeyPair, long certExpire, X500Name issuer,
CertSNAllocator snAllocator) { CertSNAllocator snAllocator) {
this.issuerKeyPair = issuerKeyPair; this.issuerKeyPair = issuerKeyPair;
this.certExpire = certExpire; this.certExpire = certExpire;
this.issuerDN = issuer; this.issuerDN = issuer;
@ -64,8 +60,7 @@ public class SM2X509CertMaker {
* @return 新的证书 * @return 新的证书
* @throws Exception 如果错误发生 * @throws Exception 如果错误发生
*/ */
public X509Certificate makeRootCACert(byte[] csr) public X509Certificate makeRootCACert(byte[] csr) throws Exception {
throws Exception {
KeyUsage usage = new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign); KeyUsage usage = new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign);
return makeCertificate(CertLevel.RootCA, null, csr, usage, null); return makeCertificate(CertLevel.RootCA, null, csr, usage, null);
} }
@ -77,8 +72,7 @@ public class SM2X509CertMaker {
* @return 新的证书 * @return 新的证书
* @throws Exception 如果错误发生 * @throws Exception 如果错误发生
*/ */
public X509Certificate makeSubCACert(byte[] csr) public X509Certificate makeSubCACert(byte[] csr) throws Exception {
throws Exception {
KeyUsage usage = new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign); KeyUsage usage = new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign);
return makeCertificate(CertLevel.SubCA, 0, csr, usage, null); return makeCertificate(CertLevel.SubCA, 0, csr, usage, null);
} }
@ -90,10 +84,9 @@ public class SM2X509CertMaker {
* @return 新的证书 * @return 新的证书
* @throws Exception 如果错误发生 * @throws Exception 如果错误发生
*/ */
public X509Certificate makeSSLEndEntityCert(byte[] csr) public X509Certificate makeSSLEndEntityCert(byte[] csr) throws Exception {
throws Exception {
return makeEndEntityCert(csr, return makeEndEntityCert(csr,
new KeyPurposeId[] {KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_serverAuth}); new KeyPurposeId[] {KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_serverAuth});
} }
/** /**
@ -104,28 +97,26 @@ public class SM2X509CertMaker {
* @return 新的证书 * @return 新的证书
* @throws Exception 如果错误发生 * @throws Exception 如果错误发生
*/ */
public X509Certificate makeEndEntityCert(byte[] csr, public X509Certificate makeEndEntityCert(byte[] csr, KeyPurposeId[] extendedKeyUsages)
KeyPurposeId[] extendedKeyUsages)
throws Exception { throws Exception {
KeyUsage usage = new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyAgreement KeyUsage usage = new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyAgreement
| KeyUsage.dataEncipherment | KeyUsage.keyEncipherment); | KeyUsage.dataEncipherment | KeyUsage.keyEncipherment);
return makeCertificate(CertLevel.SubCA, null, csr, usage, extendedKeyUsages); return makeCertificate(CertLevel.SubCA, null, csr, usage, extendedKeyUsages);
} }
/** /**
* @param isCA 是否是颁发给CA的证书 * @param isCA 是否是颁发给CA的证书
* @param keyUsage 证书用途 * @param keyUsage 证书用途
* @param csr CSR * @param csr CSR
* @return * @return
* @throws Exception * @throws Exception
*/ */
private X509Certificate makeCertificate(CertLevel certLevel, Integer pathLenConstrain, private X509Certificate makeCertificate(CertLevel certLevel, Integer pathLenConstrain,
byte[] csr, KeyUsage keyUsage, KeyPurposeId[] extendedKeyUsages) byte[] csr, KeyUsage keyUsage, KeyPurposeId[] extendedKeyUsages) throws Exception {
throws Exception {
if (certLevel == CertLevel.EndEntity) { if (certLevel == CertLevel.EndEntity) {
if (keyUsage.hasUsages(KeyUsage.keyCertSign)) { if (keyUsage.hasUsages(KeyUsage.keyCertSign)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"keyusage keyCertSign is not allowed in EndEntity Certificate"); "keyusage keyCertSign is not allowed in EndEntity Certificate");
} }
} }
@ -139,13 +130,11 @@ public class SM2X509CertMaker {
String email = null; String email = null;
String commonName = null; String commonName = null;
/* /*
* RFC 5280 §4.2.1.6 Subject * RFC 5280 §4.2.1.6 Subject Conforming implementations generating new certificates with
* Conforming implementations generating new certificates with * electronic mail addresses MUST use the rfc822Name in the subject alternative name
* electronic mail addresses MUST use the rfc822Name in the subject * extension (Section 4.2.1.6) to describe such identities. Simultaneous inclusion of the
* alternative name extension (Section 4.2.1.6) to describe such * emailAddress attribute in the subject distinguished name to support legacy
* identities. Simultaneous inclusion of the emailAddress attribute in * implementations is deprecated but permitted.
* the subject distinguished name to support legacy implementations is
* deprecated but permitted.
*/ */
RDN[] rdns = subject.getRDNs(); RDN[] rdns = subject.getRDNs();
List<RDN> newRdns = new ArrayList<>(rdns.length); List<RDN> newRdns = new ArrayList<>(rdns.length);
@ -167,9 +156,8 @@ public class SM2X509CertMaker {
List<GeneralName> subjectAltNames = new LinkedList<>(); List<GeneralName> subjectAltNames = new LinkedList<>();
if (email != null) { if (email != null) {
subject = new X500Name(newRdns.toArray(new RDN[0])); subject = new X500Name(newRdns.toArray(new RDN[0]));
subjectAltNames.add( subjectAltNames
new GeneralName(GeneralName.rfc822Name, .add(new GeneralName(GeneralName.rfc822Name, new DERIA5String(email, true)));
new DERIA5String(email, true)));
} }
boolean selfSignedEECert = false; boolean selfSignedEECert = false;
@ -178,13 +166,14 @@ public class SM2X509CertMaker {
if (issuerDN.equals(subject)) { if (issuerDN.equals(subject)) {
subject = issuerDN; subject = issuerDN;
} else { } else {
throw new IllegalArgumentException("subject != issuer for certLevel " + CertLevel.RootCA); throw new IllegalArgumentException(
"subject != issuer for certLevel " + CertLevel.RootCA);
} }
break; break;
case SubCA: case SubCA:
if (issuerDN.equals(subject)) { if (issuerDN.equals(subject)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"subject MUST not equals issuer for certLevel " + certLevel); "subject MUST not equals issuer for certLevel " + certLevel);
} }
break; break;
default: default:
@ -197,17 +186,16 @@ public class SM2X509CertMaker {
BigInteger serialNumber = snAllocator.nextSerialNumber(); BigInteger serialNumber = snAllocator.nextSerialNumber();
Date notBefore = new Date(); Date notBefore = new Date();
Date notAfter = new Date(notBefore.getTime() + certExpire); Date notAfter = new Date(notBefore.getTime() + certExpire);
X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder( X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder(issuerDN, serialNumber,
issuerDN, serialNumber, notBefore, notAfter, subject, subPub);
notBefore, notAfter,
subject, subPub);
JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils(); JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
v3CertGen.addExtension(Extension.subjectKeyIdentifier, false, v3CertGen.addExtension(Extension.subjectKeyIdentifier, false,
extUtils.createSubjectKeyIdentifier(subPub)); extUtils.createSubjectKeyIdentifier(subPub));
if (certLevel != CertLevel.RootCA && !selfSignedEECert) { if (certLevel != CertLevel.RootCA && !selfSignedEECert) {
v3CertGen.addExtension(Extension.authorityKeyIdentifier, false, v3CertGen.addExtension(Extension.authorityKeyIdentifier, false,
extUtils.createAuthorityKeyIdentifier(SubjectPublicKeyInfo.getInstance(issPub.getEncoded()))); extUtils.createAuthorityKeyIdentifier(
SubjectPublicKeyInfo.getInstance(issPub.getEncoded())));
} }
// RFC 5280 §4.2.1.9 Basic Constraints: // RFC 5280 §4.2.1.9 Basic Constraints:
@ -219,12 +207,13 @@ public class SM2X509CertMaker {
if (certLevel == CertLevel.EndEntity) { if (certLevel == CertLevel.EndEntity) {
basicConstraints = new BasicConstraints(false); basicConstraints = new BasicConstraints(false);
} else { } else {
basicConstraints = pathLenConstrain == null basicConstraints = pathLenConstrain == null ? new BasicConstraints(true)
? new BasicConstraints(true) : new BasicConstraints(pathLenConstrain.intValue()); : new BasicConstraints(pathLenConstrain.intValue());
} }
v3CertGen.addExtension(Extension.basicConstraints, true, basicConstraints); v3CertGen.addExtension(Extension.basicConstraints, true, basicConstraints);
// RFC 5280 §4.2.1.3 Key Usage: When present, conforming CAs SHOULD mark this extension as critical. // RFC 5280 §4.2.1.3 Key Usage: When present, conforming CAs SHOULD mark this extension as
// critical.
v3CertGen.addExtension(Extension.keyUsage, true, keyUsage); v3CertGen.addExtension(Extension.keyUsage, true, keyUsage);
if (extendedKeyUsages != null) { if (extendedKeyUsages != null) {
@ -243,20 +232,21 @@ public class SM2X509CertMaker {
if (commonName == null) { if (commonName == null) {
throw new IllegalArgumentException("commonName must not be null"); throw new IllegalArgumentException("commonName must not be null");
} }
GeneralName name = new GeneralName(GeneralName.dNSName, GeneralName name =
new DERIA5String(commonName, true)); new GeneralName(GeneralName.dNSName, new DERIA5String(commonName, true));
subjectAltNames.add(name); subjectAltNames.add(name);
} }
} }
if (!subjectAltNames.isEmpty()) { if (!subjectAltNames.isEmpty()) {
v3CertGen.addExtension(Extension.subjectAlternativeName, false, v3CertGen.addExtension(Extension.subjectAlternativeName, false,
new GeneralNames(subjectAltNames.toArray(new GeneralName[0]))); new GeneralNames(subjectAltNames.toArray(new GeneralName[0])));
} }
JcaContentSignerBuilder contentSignerBuilder = makeContentSignerBuilder(issPub); JcaContentSignerBuilder contentSignerBuilder = makeContentSignerBuilder(issPub);
X509Certificate cert = new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME) X509Certificate cert =
.getCertificate(v3CertGen.build(contentSignerBuilder.build(issPriv))); new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME)
.getCertificate(v3CertGen.build(contentSignerBuilder.build(issPriv)));
cert.verify(issPub); cert.verify(issPub);
return cert; return cert;
@ -264,7 +254,8 @@ public class SM2X509CertMaker {
private JcaContentSignerBuilder makeContentSignerBuilder(PublicKey issPub) throws Exception { private JcaContentSignerBuilder makeContentSignerBuilder(PublicKey issPub) throws Exception {
if (issPub.getAlgorithm().equals("EC")) { if (issPub.getAlgorithm().equals("EC")) {
JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder(SIGN_ALGO_SM3WITHSM2); JcaContentSignerBuilder contentSignerBuilder =
new JcaContentSignerBuilder(SIGN_ALGO_SM3WITHSM2);
contentSignerBuilder.setProvider(BouncyCastleProvider.PROVIDER_NAME); contentSignerBuilder.setProvider(BouncyCastleProvider.PROVIDER_NAME);
return contentSignerBuilder; return contentSignerBuilder;
} }

30
src/main/java/org/paillier/PaillierCipher.java Executable file → Normal file
View File

@ -37,8 +37,8 @@ public class PaillierCipher {
byte[] data = new byte[nLenBytes.length + nBytes.length + cipherBytes.length]; byte[] data = new byte[nLenBytes.length + nBytes.length + cipherBytes.length];
System.arraycopy(nLenBytes, 0, data, 0, nLenBytes.length); System.arraycopy(nLenBytes, 0, data, 0, nLenBytes.length);
System.arraycopy(nBytes, 0, data, nLenBytes.length, nBytes.length); System.arraycopy(nBytes, 0, data, nLenBytes.length, nBytes.length);
System.arraycopy( System.arraycopy(cipherBytes, 0, data, nLenBytes.length + nBytes.length,
cipherBytes, 0, data, nLenBytes.length + nBytes.length, cipherBytes.length); cipherBytes.length);
return data; return data;
} }
@ -49,11 +49,8 @@ public class PaillierCipher {
public static BigInteger decrypt(byte[] ciphertext, PrivateKey privateKey) { public static BigInteger decrypt(byte[] ciphertext, PrivateKey privateKey) {
RSAPrivateCrtKey rsaPriKey = (RSAPrivateCrtKey) privateKey; RSAPrivateCrtKey rsaPriKey = (RSAPrivateCrtKey) privateKey;
BigInteger n = rsaPriKey.getModulus(); BigInteger n = rsaPriKey.getModulus();
BigInteger lambda = BigInteger lambda = rsaPriKey.getPrimeP().subtract(BigInteger.ONE)
rsaPriKey .multiply(rsaPriKey.getPrimeQ().subtract(BigInteger.ONE));
.getPrimeP()
.subtract(BigInteger.ONE)
.multiply(rsaPriKey.getPrimeQ().subtract(BigInteger.ONE));
int nLen = CommonUtils.byte2ToUnsignedShort(ciphertext); int nLen = CommonUtils.byte2ToUnsignedShort(ciphertext);
byte[] nBytes = new byte[nLen]; byte[] nBytes = new byte[nLen];
@ -70,13 +67,8 @@ public class PaillierCipher {
BigInteger mu = lambda.modInverse(n); BigInteger mu = lambda.modInverse(n);
BigInteger nsquare = n.multiply(n); BigInteger nsquare = n.multiply(n);
BigInteger message = BigInteger message = intCiphertext.modPow(lambda, nsquare).subtract(BigInteger.ONE)
intCiphertext .divide(n).multiply(mu).mod(n);
.modPow(lambda, nsquare)
.subtract(BigInteger.ONE)
.divide(n)
.multiply(mu)
.mod(n);
BigInteger maxValue = BigInteger.ONE.shiftLeft(n.bitLength() / 2); BigInteger maxValue = BigInteger.ONE.shiftLeft(n.bitLength() / 2);
if (message.compareTo(maxValue) > 0) { if (message.compareTo(maxValue) > 0) {
return message.subtract(n); return message.subtract(n);
@ -86,10 +78,8 @@ public class PaillierCipher {
} }
public static String ciphertextAdd(String ciphertext1, String ciphertext2) { public static String ciphertextAdd(String ciphertext1, String ciphertext2) {
return CommonUtils.byteToHexString( return CommonUtils.byteToHexString(ciphertextAdd(CommonUtils.hexStringToBytes(ciphertext1),
ciphertextAdd( CommonUtils.hexStringToBytes(ciphertext2)));
CommonUtils.hexStringToBytes(ciphertext1),
CommonUtils.hexStringToBytes(ciphertext2)));
} }
public static byte[] ciphertextAdd(byte[] ciphertext1, byte[] ciphertext2) { public static byte[] ciphertextAdd(byte[] ciphertext1, byte[] ciphertext2) {
@ -122,8 +112,8 @@ public class PaillierCipher {
byte[] data = new byte[nLenBytes.length + nBytes1.length + cipherBytes.length]; byte[] data = new byte[nLenBytes.length + nBytes1.length + cipherBytes.length];
System.arraycopy(nLenBytes, 0, data, 0, nLenBytes.length); System.arraycopy(nLenBytes, 0, data, 0, nLenBytes.length);
System.arraycopy(nBytes1, 0, data, nLenBytes.length, nBytes1.length); System.arraycopy(nBytes1, 0, data, nLenBytes.length, nBytes1.length);
System.arraycopy( System.arraycopy(cipherBytes, 0, data, nLenBytes.length + nBytes1.length,
cipherBytes, 0, data, nLenBytes.length + nBytes1.length, cipherBytes.length); cipherBytes.length);
return data; return data;
} }
} }

60
src/test/java/org/paillier/PaillierTest.java Executable file → Normal file
View File

@ -2,8 +2,6 @@ package org.paillier;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.paillier.PaillierCipher;
import org.paillier.PaillierKeyPair;
import java.math.BigInteger; import java.math.BigInteger;
import java.security.KeyPair; import java.security.KeyPair;
@ -18,7 +16,7 @@ public class PaillierTest {
KeyPair keypair = PaillierKeyPair.generateGoodKeyPair(); KeyPair keypair = PaillierKeyPair.generateGoodKeyPair();
RSAPublicKey pubKey = (RSAPublicKey) keypair.getPublic(); RSAPublicKey pubKey = (RSAPublicKey) keypair.getPublic();
RSAPrivateCrtKey priKey = (RSAPrivateCrtKey) keypair.getPrivate(); RSAPrivateCrtKey priKey = (RSAPrivateCrtKey) keypair.getPrivate();
System.out.println("e:" + priKey.getPublicExponent().intValue()); System.out.println("e:" + priKey.getPublicExponent().intValue());
String publicKeyStr = PaillierKeyPair.publicKeyToPem(pubKey); String publicKeyStr = PaillierKeyPair.publicKeyToPem(pubKey);
String privateKeyStr = PaillierKeyPair.privateKeyToPem(priKey); String privateKeyStr = PaillierKeyPair.privateKeyToPem(priKey);
@ -62,35 +60,33 @@ public class PaillierTest {
@Test @Test
public void decryptTest() { public void decryptTest() {
String privateKeyStr = String privateKeyStr = "-----BEGIN PRIVATE KEY-----\n"
"-----BEGIN PRIVATE KEY-----\n" + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1f/Oa//I+SFNN\n"
+ "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1f/Oa//I+SFNN\n" + "v+PmHGJ1vLGFDu6A0IQV9DcX/hf2R2JFW/ONxfjlrtAh4dW7itMwIA6u64UlKiml\n"
+ "v+PmHGJ1vLGFDu6A0IQV9DcX/hf2R2JFW/ONxfjlrtAh4dW7itMwIA6u64UlKiml\n" + "4UuVBT9ca4wv7R87DFqhxquh+ObMzo2x6QAaXnvL5WMmu8+/aLg6Nc06BXtJHsiw\n"
+ "4UuVBT9ca4wv7R87DFqhxquh+ObMzo2x6QAaXnvL5WMmu8+/aLg6Nc06BXtJHsiw\n" + "TO7B09AcDNccdDyI+gXP4LEsIoh9HR1p41cq1RKe5c9khLryc5zQqf6NWlw4aWr9\n"
+ "TO7B09AcDNccdDyI+gXP4LEsIoh9HR1p41cq1RKe5c9khLryc5zQqf6NWlw4aWr9\n" + "AI5w4m7zhsTiDH1R9qLSJugOltY+9hLF7E9LexMLwXoQUYyi0WGxRe0h03+EQszv\n"
+ "AI5w4m7zhsTiDH1R9qLSJugOltY+9hLF7E9LexMLwXoQUYyi0WGxRe0h03+EQszv\n" + "4gQA4paJPAnk8k6VrUyTlBdeoYneInxZ0FEtFffk/rqVt4B80jjVRTbleSmDNvb7\n"
+ "4gQA4paJPAnk8k6VrUyTlBdeoYneInxZ0FEtFffk/rqVt4B80jjVRTbleSmDNvb7\n" + "KFp+KHSrAgMBAAECggEAG0jM2jQ3ul0tCLccD2+c7Y4cMaB5AixWbuZzkcvE1mUM\n"
+ "KFp+KHSrAgMBAAECggEAG0jM2jQ3ul0tCLccD2+c7Y4cMaB5AixWbuZzkcvE1mUM\n" + "xNh52Io2THDnIPDOLI9GCCoJiwokzd10vVcNAa30RHR2co327+1/gmpXStYb/BXg\n"
+ "xNh52Io2THDnIPDOLI9GCCoJiwokzd10vVcNAa30RHR2co327+1/gmpXStYb/BXg\n" + "/ynDtjMV8STeruf05xVa/IUyANLqIafbC4XFLqYk1tKnU8O1hfHwBbwFZlkao5QH\n"
+ "/ynDtjMV8STeruf05xVa/IUyANLqIafbC4XFLqYk1tKnU8O1hfHwBbwFZlkao5QH\n" + "IN9CyDIsyyv30JbHz47HJePZkTm/2iOq4ru+pKYFHeDz4EIEJRGl8HD7wtpo3F5E\n"
+ "IN9CyDIsyyv30JbHz47HJePZkTm/2iOq4ru+pKYFHeDz4EIEJRGl8HD7wtpo3F5E\n" + "mxe9uI5GMCdbswGnmw1a0u/VrSXpxwVyQMGHP6KWZ0dIunFW0Sh4DEdf9/tygtwx\n"
+ "mxe9uI5GMCdbswGnmw1a0u/VrSXpxwVyQMGHP6KWZ0dIunFW0Sh4DEdf9/tygtwx\n" + "nJ+/RYGqTKLv59+OkJGH/e6J6BV9rKYfjTiRC+hAAQKBgQD/1dW9WSXnquVGdJkq\n"
+ "nJ+/RYGqTKLv59+OkJGH/e6J6BV9rKYfjTiRC+hAAQKBgQD/1dW9WSXnquVGdJkq\n" + "QnohnMp/EkaXA3e3RiS9Bx9hhNwfdijqx3zyV1LnHGhuEaCXSCoy6zIOLQxOkkA8\n"
+ "QnohnMp/EkaXA3e3RiS9Bx9hhNwfdijqx3zyV1LnHGhuEaCXSCoy6zIOLQxOkkA8\n" + "rLCzpN/hp3c8pQUwYlQodZ+G/0272jCsD2vmdOuRP2WuFA9hqGgFvUbXkXh4mcEB\n"
+ "rLCzpN/hp3c8pQUwYlQodZ+G/0272jCsD2vmdOuRP2WuFA9hqGgFvUbXkXh4mcEB\n" + "xKJY/jAddZvmnvs/dcLt6oJMqwKBgQC1nd18hcjQmIRARRUGs1ZU75yTaLKp+lXf\n"
+ "xKJY/jAddZvmnvs/dcLt6oJMqwKBgQC1nd18hcjQmIRARRUGs1ZU75yTaLKp+lXf\n" + "M7lg8RKE9sWf4ZoT3Snj+pimUOqliE10LiHruawa137q/UC+iI0/I4H9AUhv2mAw\n"
+ "M7lg8RKE9sWf4ZoT3Snj+pimUOqliE10LiHruawa137q/UC+iI0/I4H9AUhv2mAw\n" + "m5drd+G4s6uTiCf7OQxBTmGHEvv5xH7gQih6sjOJI+N57xanC1XMGxijMOSy/D+O\n"
+ "m5drd+G4s6uTiCf7OQxBTmGHEvv5xH7gQih6sjOJI+N57xanC1XMGxijMOSy/D+O\n" + "sLxB8yJ4AQKBgQDYYX3kJnB+3vYIfznEmnE92KUUkNqPg2lP483S6yFJk9ux6Hh3\n"
+ "sLxB8yJ4AQKBgQDYYX3kJnB+3vYIfznEmnE92KUUkNqPg2lP483S6yFJk9ux6Hh3\n" + "Cr7NIbqGqmpRHiubiHfYlUDC6KsOEXivWMgjSQHqk3+wFUqsP546kjGZNnoCtmqQ\n"
+ "Cr7NIbqGqmpRHiubiHfYlUDC6KsOEXivWMgjSQHqk3+wFUqsP546kjGZNnoCtmqQ\n" + "PILgameLc/mGIIVZ7dv9brdqQCmKp1CtNCiz6Fm9sOlpR3HtnKaAH+aQ/QKBgFVW\n"
+ "PILgameLc/mGIIVZ7dv9brdqQCmKp1CtNCiz6Fm9sOlpR3HtnKaAH+aQ/QKBgFVW\n" + "37tidfEmqYY1r+KdJGT2zqEpokJi4jTmbiZSQPx/pG8zKB5LXyLEHzSPcyLjQFnm\n"
+ "37tidfEmqYY1r+KdJGT2zqEpokJi4jTmbiZSQPx/pG8zKB5LXyLEHzSPcyLjQFnm\n" + "T4Qfk/Js7jNnWyPssEpJ2gvTrYD5oRdWFTmndEZBDs9dPEQ9Ezggp40763D61w9z\n"
+ "T4Qfk/Js7jNnWyPssEpJ2gvTrYD5oRdWFTmndEZBDs9dPEQ9Ezggp40763D61w9z\n" + "pue4kqTPW1Vxdjh6CA/Hb7VHBT/hbdAT1fI7WCgBAoGAZq1rFESL3roi8DtOWl51\n"
+ "pue4kqTPW1Vxdjh6CA/Hb7VHBT/hbdAT1fI7WCgBAoGAZq1rFESL3roi8DtOWl51\n" + "nduNO20Yloe6tlhUAKo63krRHKBeKTyLXycpZHcq6UEfys3dixFfu0lN6002lUku\n"
+ "nduNO20Yloe6tlhUAKo63krRHKBeKTyLXycpZHcq6UEfys3dixFfu0lN6002lUku\n" + "MTbmNOJWhOCa2xuZY0CeINKFnKBnbiauBpo6x+2J0PoWFn8wd1tzFJPbodk8Km1f\n"
+ "MTbmNOJWhOCa2xuZY0CeINKFnKBnbiauBpo6x+2J0PoWFn8wd1tzFJPbodk8Km1f\n" + "qySov+6mrQxHojQYBu9/yYQ=\n" + "-----END PRIVATE KEY-----";
+ "qySov+6mrQxHojQYBu9/yYQ=\n"
+ "-----END PRIVATE KEY-----";
String cipher = String cipher =
"0100B57FF39AFFF23E48534DBFE3E61C6275BCB1850EEE80D08415F43717FE17F64762455BF38DC5F8E5AED021E1D5BB8AD330200EAEEB85252A29A5E14B95053F5C6B8C2FED1F3B0C5AA1C6ABA1F8E6CCCE8DB1E9001A5E7BCBE56326BBCFBF68B83A35CD3A057B491EC8B04CEEC1D3D01C0CD71C743C88FA05CFE0B12C22887D1D1D69E3572AD5129EE5CF6484BAF2739CD0A9FE8D5A5C38696AFD008E70E26EF386C4E20C7D51F6A2D226E80E96D63EF612C5EC4F4B7B130BC17A10518CA2D161B145ED21D37F8442CCEFE20400E296893C09E4F24E95AD4C9394175EA189DE227C59D0512D15F7E4FEBA95B7807CD238D54536E579298336F6FB285A7E2874AB6914BF4FF089BFD98EC18D9E8B3D7FB2F5CFC20715C62D34F08E36D84F2CDABA2D1A1798C95161B7831167ED27E8894F1EB25D4E74DF382BF276D9ACBEADB56795F3DF8A4E6CE9DF7B6CFEFD5C66F0BC45D24CCC8E8095A7BF5CE69FEC5579B874A4C9B7C8F13126EC59D7C6DF0404816F638C7D4A84FE038E6F00B5667AC88E4307990E4C06B3864D86B7349275B20A3FB50FBA64706F214CC642219DCEF4453C30B89790F6FB1566A5D557AD7EC5890CA50E80111319F9742943FBD675D18753E5ABD21941832A11332ED902C334309E3770512AC042E1556C3F0ECCFC056C66D7362BA4E7896EA0807412817C68D7B5434AFA0D95A12B950573994F081F996545B871E485C392288E2D61C3B0CBB9FC4E68C1C558A598B03BACFF27967BE8AEA8F1322EC3E0957A3ED84810164A59BDEE2D1514EA68228CB96B59D8BA1E9234A24D57E5F8D7E55724EF0AE9D83F6E2A84B9A1E47B59091201B1B65542BBBB5A988CBBD5395335C4DF821ACEF289D20444B74CABC406A7C4F810EFF85838994DBDD38EDF74D4821153A5128AB98C15409C73891415B194803B3ABF761CEE57D1F58813A7125260E58864970CA2650E0D46C239ED92FCC3491C5FA372838B475D14E4946FCC3C421A76C434C5310D1A17A744551CFB5F99547BB216AD7C1ADA5C27CA64B34C29152D29B0A4B90B0C72A7A18BD19CF278B6F39186A39F91FB4D"; "0100B57FF39AFFF23E48534DBFE3E61C6275BCB1850EEE80D08415F43717FE17F64762455BF38DC5F8E5AED021E1D5BB8AD330200EAEEB85252A29A5E14B95053F5C6B8C2FED1F3B0C5AA1C6ABA1F8E6CCCE8DB1E9001A5E7BCBE56326BBCFBF68B83A35CD3A057B491EC8B04CEEC1D3D01C0CD71C743C88FA05CFE0B12C22887D1D1D69E3572AD5129EE5CF6484BAF2739CD0A9FE8D5A5C38696AFD008E70E26EF386C4E20C7D51F6A2D226E80E96D63EF612C5EC4F4B7B130BC17A10518CA2D161B145ED21D37F8442CCEFE20400E296893C09E4F24E95AD4C9394175EA189DE227C59D0512D15F7E4FEBA95B7807CD238D54536E579298336F6FB285A7E2874AB6914BF4FF089BFD98EC18D9E8B3D7FB2F5CFC20715C62D34F08E36D84F2CDABA2D1A1798C95161B7831167ED27E8894F1EB25D4E74DF382BF276D9ACBEADB56795F3DF8A4E6CE9DF7B6CFEFD5C66F0BC45D24CCC8E8095A7BF5CE69FEC5579B874A4C9B7C8F13126EC59D7C6DF0404816F638C7D4A84FE038E6F00B5667AC88E4307990E4C06B3864D86B7349275B20A3FB50FBA64706F214CC642219DCEF4453C30B89790F6FB1566A5D557AD7EC5890CA50E80111319F9742943FBD675D18753E5ABD21941832A11332ED902C334309E3770512AC042E1556C3F0ECCFC056C66D7362BA4E7896EA0807412817C68D7B5434AFA0D95A12B950573994F081F996545B871E485C392288E2D61C3B0CBB9FC4E68C1C558A598B03BACFF27967BE8AEA8F1322EC3E0957A3ED84810164A59BDEE2D1514EA68228CB96B59D8BA1E9234A24D57E5F8D7E55724EF0AE9D83F6E2A84B9A1E47B59091201B1B65542BBBB5A988CBBD5395335C4DF821ACEF289D20444B74CABC406A7C4F810EFF85838994DBDD38EDF74D4821153A5128AB98C15409C73891415B194803B3ABF761CEE57D1F58813A7125260E58864970CA2650E0D46C239ED92FCC3491C5FA372838B475D14E4946FCC3C421A76C434C5310D1A17A744551CFB5F99547BB216AD7C1ADA5C27CA64B34C29152D29B0A4B90B0C72A7A18BD19CF278B6F39186A39F91FB4D";