diff --git a/build.gradle b/build.gradle index 1160d35..1e6f9c6 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,9 @@ plugins { id 'maven-publish' id 'signing' } + +apply from: '../spotless.gradle' + group 'org.bdware.bdcontract' version '0.2.0' sourceCompatibility = 1.8 diff --git a/src/main/java/org.zz/gmhelper/BCECUtil.java b/src/main/java/org.zz/gmhelper/BCECUtil.java index 87ae5ca..406f601 100644 --- a/src/main/java/org.zz/gmhelper/BCECUtil.java +++ b/src/main/java/org.zz/gmhelper/BCECUtil.java @@ -57,15 +57,12 @@ public class BCECUtil { } public static KeyPair generateKeyPair(ECDomainParameters domainParameters, SecureRandom random) - throws NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { + throws NoSuchProviderException, NoSuchAlgorithmException, + InvalidAlgorithmParameterException { KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGO_NAME_EC, BouncyCastleProvider.PROVIDER_NAME); - ECParameterSpec parameterSpec = - new ECParameterSpec( - domainParameters.getCurve(), - domainParameters.getG(), - domainParameters.getN(), - domainParameters.getH()); + ECParameterSpec parameterSpec = new ECParameterSpec(domainParameters.getCurve(), + domainParameters.getG(), domainParameters.getN(), domainParameters.getH()); kpg.initialize(parameterSpec, (null == random ? new SecureRandom() : random)); 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} * @return */ - public static ECPrivateKeyParameters createECPrivateKeyParameters( - String dHex, ECDomainParameters domainParameters) { + public static ECPrivateKeyParameters createECPrivateKeyParameters(String dHex, + ECDomainParameters 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} * @return */ - public static ECPrivateKeyParameters createECPrivateKeyParameters( - byte[] dBytes, ECDomainParameters domainParameters) { + public static ECPrivateKeyParameters createECPrivateKeyParameters(byte[] dBytes, + ECDomainParameters domainParameters) { return createECPrivateKeyParameters(new BigInteger(1, dBytes), domainParameters); } /** - * @param d 大数形式的私钥d值 + * @param d 大数形式的私钥d值 * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS} * @return */ - public static ECPrivateKeyParameters createECPrivateKeyParameters( - BigInteger d, ECDomainParameters domainParameters) { + public static ECPrivateKeyParameters createECPrivateKeyParameters(BigInteger d, + ECDomainParameters domainParameters) { return new ECPrivateKeyParameters(d, domainParameters); } @@ -128,46 +125,48 @@ public class BCECUtil { * @param priKey ECC私钥参数对象 * @return */ - public static ECPublicKeyParameters buildECPublicKeyByPrivateKey(ECPrivateKeyParameters priKey) { + public static ECPublicKeyParameters buildECPublicKeyByPrivateKey( + ECPrivateKeyParameters priKey) { ECDomainParameters domainParameters = priKey.getParameters(); ECPoint q = new FixedPointCombMultiplier().multiply(domainParameters.getG(), priKey.getD()); return new ECPublicKeyParameters(q, domainParameters); } /** - * @param x 大数形式的公钥x分量 - * @param y 大数形式的公钥y分量 - * @param curve EC曲线参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#CURVE} + * @param x 大数形式的公钥x分量 + * @param y 大数形式的公钥y分量 + * @param curve EC曲线参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#CURVE} * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS} * @return */ - public static ECPublicKeyParameters createECPublicKeyParameters( - BigInteger x, BigInteger y, ECCurve curve, ECDomainParameters domainParameters) { - return createECPublicKeyParameters(x.toByteArray(), y.toByteArray(), curve, domainParameters); + public static ECPublicKeyParameters createECPublicKeyParameters(BigInteger x, BigInteger y, + ECCurve curve, ECDomainParameters domainParameters) { + return createECPublicKeyParameters(x.toByteArray(), y.toByteArray(), curve, + domainParameters); } /** - * @param xHex 十六进制形式的公钥x分量,如果是SM2算法,Hex字符串长度应该是64(即32字节) - * @param yHex 十六进制形式的公钥y分量,如果是SM2算法,Hex字符串长度应该是64(即32字节) - * @param curve EC曲线参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#CURVE} + * @param xHex 十六进制形式的公钥x分量,如果是SM2算法,Hex字符串长度应该是64(即32字节) + * @param yHex 十六进制形式的公钥y分量,如果是SM2算法,Hex字符串长度应该是64(即32字节) + * @param curve EC曲线参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#CURVE} * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS} * @return */ - public static ECPublicKeyParameters createECPublicKeyParameters( - String xHex, String yHex, ECCurve curve, ECDomainParameters domainParameters) { - return createECPublicKeyParameters( - ByteUtils.fromHexString(xHex), ByteUtils.fromHexString(yHex), curve, domainParameters); + public static ECPublicKeyParameters createECPublicKeyParameters(String xHex, String yHex, + ECCurve curve, ECDomainParameters domainParameters) { + return createECPublicKeyParameters(ByteUtils.fromHexString(xHex), + ByteUtils.fromHexString(yHex), curve, domainParameters); } /** - * @param xBytes 十六进制形式的公钥x分量,如果是SM2算法,应该是32字节 - * @param yBytes 十六进制形式的公钥y分量,如果是SM2算法,应该是32字节 - * @param curve EC曲线参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#CURVE} + * @param xBytes 十六进制形式的公钥x分量,如果是SM2算法,应该是32字节 + * @param yBytes 十六进制形式的公钥y分量,如果是SM2算法,应该是32字节 + * @param curve EC曲线参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#CURVE} * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS} * @return */ - public static ECPublicKeyParameters createECPublicKeyParameters( - byte[] xBytes, byte[] yBytes, ECCurve curve, ECDomainParameters domainParameters) { + public static ECPublicKeyParameters createECPublicKeyParameters(byte[] xBytes, byte[] yBytes, + ECCurve curve, ECDomainParameters domainParameters) { final byte uncompressedFlag = 0x04; int curveLength = getCurveLength(domainParameters); xBytes = fixToCurveLengthBytes(curveLength, xBytes); @@ -180,44 +179,35 @@ public class BCECUtil { } /** - * @param str 十六进制形式的公钥x分量,如果是SM2算法,应该是32字节 - * @param curve EC曲线参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#CURVE} + * @param str 十六进制形式的公钥x分量,如果是SM2算法,应该是32字节 + * @param curve EC曲线参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#CURVE} * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS} * @return */ - public static ECPublicKeyParameters createECPublicKeyFromStrParameters( - String str, ECCurve curve, ECDomainParameters domainParameters) { - return new ECPublicKeyParameters( - curve.decodePoint(ByteUtils.fromHexString(str)), domainParameters); + public static ECPublicKeyParameters createECPublicKeyFromStrParameters(String str, + ECCurve curve, ECDomainParameters domainParameters) { + return new ECPublicKeyParameters(curve.decodePoint(ByteUtils.fromHexString(str)), + domainParameters); } public static ECPrivateKeyParameters convertPrivateKeyToParameters(BCECPrivateKey ecPriKey) { ECParameterSpec parameterSpec = ecPriKey.getParameters(); - ECDomainParameters domainParameters = - new ECDomainParameters( - parameterSpec.getCurve(), - parameterSpec.getG(), - parameterSpec.getN(), - parameterSpec.getH()); + ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), + parameterSpec.getG(), parameterSpec.getN(), parameterSpec.getH()); return new ECPrivateKeyParameters(ecPriKey.getD(), domainParameters); } public static ECPublicKeyParameters convertPublicKeyToParameters(BCECPublicKey ecPubKey) { ECParameterSpec parameterSpec = ecPubKey.getParameters(); - ECDomainParameters domainParameters = - new ECDomainParameters( - parameterSpec.getCurve(), - parameterSpec.getG(), - parameterSpec.getN(), - parameterSpec.getH()); + ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), + parameterSpec.getG(), parameterSpec.getN(), parameterSpec.getH()); return new ECPublicKeyParameters(ecPubKey.getQ(), domainParameters); } public static BCECPublicKey createPublicKeyFromSubjectPublicKeyInfo( - SubjectPublicKeyInfo subPubInfo) - throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException, - IOException { + SubjectPublicKeyInfo subPubInfo) throws NoSuchProviderException, + NoSuchAlgorithmException, InvalidKeySpecException, IOException { return BCECUtil.convertX509ToECPublicKey( subPubInfo.toASN1Primitive().getEncoded(ASN1Encoding.DER)); } @@ -229,19 +219,18 @@ public class BCECUtil { * @param pubKey 可以为空,但是如果为空的话得到的结果OpenSSL可能解析不了 * @return */ - public static byte[] convertECPrivateKeyToPKCS8( - ECPrivateKeyParameters priKey, ECPublicKeyParameters pubKey) { + public static byte[] convertECPrivateKeyToPKCS8(ECPrivateKeyParameters priKey, + ECPublicKeyParameters pubKey) { ECDomainParameters domainParams = priKey.getParameters(); - ECParameterSpec spec = - new ECParameterSpec( - domainParams.getCurve(), domainParams.getG(), domainParams.getN(), domainParams.getH()); + ECParameterSpec spec = new ECParameterSpec(domainParams.getCurve(), domainParams.getG(), + domainParams.getN(), domainParams.getH()); BCECPublicKey publicKey = 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 = - new BCECPrivateKey( - ALGO_NAME_EC, priKey, publicKey, spec, BouncyCastleProvider.CONFIGURATION); + BCECPrivateKey privateKey = new BCECPrivateKey(ALGO_NAME_EC, priKey, publicKey, spec, + BouncyCastleProvider.CONFIGURATION); return privateKey.getEncoded(); } @@ -292,8 +281,8 @@ public class BCECUtil { * @return * @throws IOException */ - public static byte[] convertECPrivateKeyToSEC1( - ECPrivateKeyParameters priKey, ECPublicKeyParameters pubKey) throws IOException { + public static byte[] convertECPrivateKeyToSEC1(ECPrivateKeyParameters priKey, + ECPublicKeyParameters pubKey) throws IOException { byte[] pkcs8Bytes = convertECPrivateKeyToPKCS8(priKey, pubKey); PrivateKeyInfo pki = PrivateKeyInfo.getInstance(pkcs8Bytes); ASN1Encodable encodable = pki.parsePrivateKey(); @@ -368,9 +357,8 @@ public class BCECUtil { */ public static byte[] convertECPublicKeyToX509(ECPublicKeyParameters pubKey) { ECDomainParameters domainParams = pubKey.getParameters(); - ECParameterSpec spec = - new ECParameterSpec( - domainParams.getCurve(), domainParams.getG(), domainParams.getN(), domainParams.getH()); + ECParameterSpec spec = new ECParameterSpec(domainParams.getCurve(), domainParams.getG(), + domainParams.getN(), domainParams.getH()); BCECPublicKey publicKey = new BCECPublicKey(ALGO_NAME_EC, pubKey, spec, BouncyCastleProvider.CONFIGURATION); return publicKey.getEncoded(); @@ -473,23 +461,18 @@ public class BCECUtil { } else { ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve()); - X9ECParameters ecP = - new X9ECParameters( - curve, - new X9ECPoint(EC5Util.convertPoint(curve, ecSpec.getGenerator()), withCompression), - ecSpec.getOrder(), - BigInteger.valueOf(ecSpec.getCofactor()), - ecSpec.getCurve().getSeed()); + X9ECParameters ecP = new X9ECParameters(curve, + new X9ECPoint(EC5Util.convertPoint(curve, ecSpec.getGenerator()), + withCompression), + ecSpec.getOrder(), BigInteger.valueOf(ecSpec.getCofactor()), + ecSpec.getCurve().getSeed()); //// 如果是1.62或更低版本的bcprov-jdk15on应该使用以下这段代码,因为高版本的EC5Util.convertPoint没有向下兼容 - /* - X9ECParameters ecP = new X9ECParameters( - curve, - EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), - ecSpec.getOrder(), - BigInteger.valueOf(ecSpec.getCofactor()), - ecSpec.getCurve().getSeed()); - */ + /* + * X9ECParameters ecP = new X9ECParameters( curve, EC5Util.convertPoint(curve, + * ecSpec.getGenerator(), withCompression), ecSpec.getOrder(), + * BigInteger.valueOf(ecSpec.getCofactor()), ecSpec.getCurve().getSeed()); + */ params = new X962Parameters(ecP); } diff --git a/src/main/java/org.zz/gmhelper/SM2KeyExchangeUtil.java b/src/main/java/org.zz/gmhelper/SM2KeyExchangeUtil.java index e82ba6a..ad38484 100644 --- a/src/main/java/org.zz/gmhelper/SM2KeyExchangeUtil.java +++ b/src/main/java/org.zz/gmhelper/SM2KeyExchangeUtil.java @@ -7,51 +7,53 @@ import java.util.Arrays; public class SM2KeyExchangeUtil { /** - * @param initiator true表示发起方,false表示响应方 - * @param keyBits 生成的密钥长度 - * @param selfStaticPriv 己方固定私钥 + * @param initiator true表示发起方,false表示响应方 + * @param keyBits 生成的密钥长度 + * @param selfStaticPriv 己方固定私钥 * @param selfEphemeralPriv 己方临时私钥 - * @param selfId 己方ID - * @param otherStaticPub 对方固定公钥 + * @param selfId 己方ID + * @param otherStaticPub 对方固定公钥 * @param otherEphemeralPub 对方临时公钥 - * @param otherId 对方ID + * @param otherId 对方ID * @return 返回协商出的密钥,但是这个密钥是没有经过确认的 */ public static byte[] calculateKey(boolean initiator, int keyBits, - ECPrivateKeyParameters selfStaticPriv, ECPrivateKeyParameters selfEphemeralPriv, byte[] selfId, - ECPublicKeyParameters otherStaticPub, ECPublicKeyParameters otherEphemeralPub, byte[] otherId) { + ECPrivateKeyParameters selfStaticPriv, ECPrivateKeyParameters selfEphemeralPriv, + byte[] selfId, ECPublicKeyParameters otherStaticPub, + ECPublicKeyParameters otherEphemeralPub, byte[] otherId) { SM2KeyExchange exch = new SM2KeyExchange(); exch.init(new ParametersWithID( - new SM2KeyExchangePrivateParameters(initiator, selfStaticPriv, selfEphemeralPriv), - selfId)); - return exch.calculateKey( - keyBits, - new ParametersWithID(new SM2KeyExchangePublicParameters(otherStaticPub, otherEphemeralPub), otherId)); + new SM2KeyExchangePrivateParameters(initiator, selfStaticPriv, selfEphemeralPriv), + selfId)); + return exch.calculateKey(keyBits, new ParametersWithID( + new SM2KeyExchangePublicParameters(otherStaticPub, otherEphemeralPub), otherId)); } /** - * @param initiator true表示发起方,false表示响应方 - * @param keyBits 生成的密钥长度 - * @param confirmationTag 确认信息,如果是响应方可以为null;如果是发起方则应为响应方的s1 - * @param selfStaticPriv 己方固定私钥 + * @param initiator true表示发起方,false表示响应方 + * @param keyBits 生成的密钥长度 + * @param confirmationTag 确认信息,如果是响应方可以为null;如果是发起方则应为响应方的s1 + * @param selfStaticPriv 己方固定私钥 * @param selfEphemeralPriv 己方临时私钥 - * @param selfId 己方ID - * @param otherStaticPub 对方固定公钥 + * @param selfId 己方ID + * @param otherStaticPub 对方固定公钥 * @param otherEphemeralPub 对方临时公钥 - * @param otherId 对方ID + * @param otherId 对方ID * @return */ - public static ExchangeResult calculateKeyWithConfirmation(boolean initiator, int keyBits, byte[] confirmationTag, - ECPrivateKeyParameters selfStaticPriv, ECPrivateKeyParameters selfEphemeralPriv, byte[] selfId, - ECPublicKeyParameters otherStaticPub, ECPublicKeyParameters otherEphemeralPub, byte[] otherId) { + public static ExchangeResult calculateKeyWithConfirmation(boolean initiator, int keyBits, + byte[] confirmationTag, ECPrivateKeyParameters selfStaticPriv, + ECPrivateKeyParameters selfEphemeralPriv, byte[] selfId, + ECPublicKeyParameters otherStaticPub, ECPublicKeyParameters otherEphemeralPub, + byte[] otherId) { SM2KeyExchange exch = new SM2KeyExchange(); exch.init(new ParametersWithID( - new SM2KeyExchangePrivateParameters(initiator, selfStaticPriv, selfEphemeralPriv), - selfId)); - byte[][] result = exch.calculateKeyWithConfirmation( - keyBits, - confirmationTag, - new ParametersWithID(new SM2KeyExchangePublicParameters(otherStaticPub, otherEphemeralPub), otherId)); + new SM2KeyExchangePrivateParameters(initiator, selfStaticPriv, selfEphemeralPriv), + selfId)); + byte[][] result = exch.calculateKeyWithConfirmation(keyBits, confirmationTag, + new ParametersWithID( + new SM2KeyExchangePublicParameters(otherStaticPub, otherEphemeralPub), + otherId)); ExchangeResult confirmResult = new ExchangeResult(); confirmResult.setKey(result[0]); if (initiator) { diff --git a/src/main/java/org.zz/gmhelper/SM2KeyPair.java b/src/main/java/org.zz/gmhelper/SM2KeyPair.java index cdb053f..b4366a2 100644 --- a/src/main/java/org.zz/gmhelper/SM2KeyPair.java +++ b/src/main/java/org.zz/gmhelper/SM2KeyPair.java @@ -32,15 +32,14 @@ public class SM2KeyPair { JsonObject jo = JsonParser.parseString(jsonStr).getAsJsonObject(); String publicKeyStr = jo.get("publicKey").getAsString(); String privateKeyStr = jo.get("privateKey").getAsString(); - ECPublicKeyParameters point = - BCECUtil.createECPublicKeyFromStrParameters( - publicKeyStr, SM2Util.CURVE, SM2Util.DOMAIN_PARAMS); + ECPublicKeyParameters point = BCECUtil.createECPublicKeyFromStrParameters(publicKeyStr, + SM2Util.CURVE, SM2Util.DOMAIN_PARAMS); return new SM2KeyPair(point, new BigInteger(privateKeyStr, 16)); } public static ECPublicKeyParameters publicKeyStr2ECPoint(String pubKey) { - return BCECUtil.createECPublicKeyFromStrParameters( - pubKey, SM2Util.CURVE, SM2Util.DOMAIN_PARAMS); + return BCECUtil.createECPublicKeyFromStrParameters(pubKey, SM2Util.CURVE, + SM2Util.DOMAIN_PARAMS); } public ECPublicKeyParameters getPublicKey() { @@ -74,29 +73,16 @@ public class SM2KeyPair { public KeyPair toJavaSecurity() { ECDomainParameters domainParams = privateKey.getParameters(); - ECParameterSpec spec = - new ECParameterSpec( - domainParams.getCurve(), - domainParams.getG(), - domainParams.getN(), - domainParams.getH()); + ECParameterSpec spec = new ECParameterSpec(domainParams.getCurve(), domainParams.getG(), + domainParams.getN(), domainParams.getH()); BCECPublicKey bcPublicKey = null; BCECPrivateKey bcPrivateKey; if (null != publicKey) { - bcPublicKey = - new BCECPublicKey( - BCECUtil.ALGO_NAME_EC, - publicKey, - spec, - BouncyCastleProvider.CONFIGURATION); + bcPublicKey = new BCECPublicKey(BCECUtil.ALGO_NAME_EC, publicKey, spec, + BouncyCastleProvider.CONFIGURATION); } - bcPrivateKey = - new BCECPrivateKey( - BCECUtil.ALGO_NAME_EC, - privateKey, - bcPublicKey, - spec, - BouncyCastleProvider.CONFIGURATION); + bcPrivateKey = new BCECPrivateKey(BCECUtil.ALGO_NAME_EC, privateKey, bcPublicKey, spec, + BouncyCastleProvider.CONFIGURATION); return new KeyPair(bcPublicKey, bcPrivateKey); } diff --git a/src/main/java/org.zz/gmhelper/SM2PreprocessSigner.java b/src/main/java/org.zz/gmhelper/SM2PreprocessSigner.java index fb980dd..262656b 100644 --- a/src/main/java/org.zz/gmhelper/SM2PreprocessSigner.java +++ b/src/main/java/org.zz/gmhelper/SM2PreprocessSigner.java @@ -20,7 +20,7 @@ import java.math.BigInteger; * 有的国密需求是用户可以自己做预处理,签名验签只是对预处理的结果进行签名和验签 */ 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 Digest digest = null; @@ -44,11 +44,12 @@ public class SM2PreprocessSigner implements ECConstants { * 初始化 * * @param forSigning true表示用于签名,false表示用于验签 - * @param digest SM2算法的话,一般是采用SM3摘要算法 + * @param digest SM2算法的话,一般是采用SM3摘要算法 * @param param * @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; if (digest.getDigestSize() != DIGEST_LENGTH) { @@ -76,7 +77,8 @@ public class SM2PreprocessSigner implements ECConstants { ecParams = ecKey.getParameters(); 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 { ecKey = (ECKeyParameters) baseParam; 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 */ @@ -126,7 +125,7 @@ public class SM2PreprocessSigner implements ECConstants { ECMultiplier basePointMultiplier = createBasePointMultiplier(); - // 5.2.1 Draft RFC: SM2 Public Key Algorithms + // 5.2.1 Draft RFC: SM2 Public Key Algorithms do // generate s { BigInteger k; @@ -140,16 +139,14 @@ public class SM2PreprocessSigner implements ECConstants { // A5 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 BigInteger dPlus1ModN = d.add(ONE).modInverse(n); s = k.subtract(r.multiply(d)).mod(n); s = dPlus1ModN.multiply(s).mod(n); - } - while (s.equals(ZERO)); + } while (s.equals(ZERO)); // A7 try { @@ -162,7 +159,7 @@ public class SM2PreprocessSigner implements ECConstants { private boolean verifySignature(byte[] eHash, BigInteger r, BigInteger s) { BigInteger n = ecParams.getN(); - // 5.3.1 Draft RFC: SM2 Public Key Algorithms + // 5.3.1 Draft RFC: SM2 Public Key Algorithms // B1 if (r.compareTo(ONE) < 0 || r.compareTo(n) >= 0) { return false; @@ -245,8 +242,7 @@ public class SM2PreprocessSigner implements ECConstants { return new BigInteger(1, message); } - protected BigInteger[] derDecode(byte[] encoding) - throws IOException { + protected BigInteger[] derDecode(byte[] encoding) throws IOException { ASN1Sequence seq = ASN1Sequence.getInstance(ASN1Primitive.fromByteArray(encoding)); if (seq.size() != 2) { return null; @@ -260,11 +256,10 @@ public class SM2PreprocessSigner implements ECConstants { return null; } - return new BigInteger[]{r, s}; + return new BigInteger[] {r, s}; } - protected byte[] derEncode(BigInteger r, BigInteger s) - throws IOException { + protected byte[] derEncode(BigInteger r, BigInteger s) throws IOException { ASN1EncodableVector v = new ASN1EncodableVector(); v.add(new ASN1Integer(r)); diff --git a/src/main/java/org.zz/gmhelper/SM2Signer.java b/src/main/java/org.zz/gmhelper/SM2Signer.java index ad6b819..fd732c0 100644 --- a/src/main/java/org.zz/gmhelper/SM2Signer.java +++ b/src/main/java/org.zz/gmhelper/SM2Signer.java @@ -19,195 +19,196 @@ import org.bouncycastle.util.encoders.Hex; import java.math.BigInteger; public class SM2Signer implements Signer, ECConstants { - private final DSAKCalculator kCalculator; - private final Digest digest; - private final DSAEncoding encoding; - private ECDomainParameters ecParams; - private ECPoint pubPoint; - private ECKeyParameters ecKey; - private byte[] z; + private final DSAKCalculator kCalculator; + private final Digest digest; + private final DSAEncoding encoding; + private ECDomainParameters ecParams; + private ECPoint pubPoint; + private ECKeyParameters ecKey; + private byte[] z; - public SM2Signer() { - 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"); + public SM2Signer() { + this(StandardDSAEncoding.INSTANCE, new SM3Digest()); } - if (var1) { - if (var3 instanceof ParametersWithRandom) { - 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(); + public SM2Signer(Digest var1) { + this(StandardDSAEncoding.INSTANCE, var1); } - this.z = this.getZ(var4); - this.digest.update(this.z, 0, this.z.length); - } - - 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 SM2Signer(DSAEncoding var1) { + this.kCalculator = new RandomDSAKCalculator(); + this.encoding = var1; + this.digest = new SM3Digest(); } - } - public void reset() { - this.digest.reset(); - if (this.z != null) { - this.digest.update(this.z, 0, this.z.length); + public SM2Signer(DSAEncoding var1, Digest var2) { + this.kCalculator = new RandomDSAKCalculator(); + this.encoding = var1; + this.digest = var2; } - } - public byte[] generateSignature() throws CryptoException { - 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(); - - while (true) { - 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; + 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 { - 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); - } + var3 = var2; + var4 = Hex.decodeStrict("31323334353637383132333435363738"); } - } else { - return false; - } - } else { - return false; + + if (var1) { + if (var3 instanceof ParametersWithRandom) { + 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); + this.digest.update(this.z, 0, this.z.length); } - } - private byte[] digestDoFinal() { - byte[] var1 = new byte[this.digest.getDigestSize()]; - this.digest.doFinal(var1, 0); - this.reset(); - return var1; - } + public void update(byte var1) { + this.digest.update(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; - } + public void update(byte[] var1, int var2, int var3) { + this.digest.update(var1, var2, var3); + } - 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); - } + 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; + } + } - private void addFieldElement(Digest var1, ECFieldElement var2) { - byte[] var3 = var2.getEncoded(); - var1.update(var3, 0, var3.length); - } + public void reset() { + this.digest.reset(); + if (this.z != null) { + this.digest.update(this.z, 0, this.z.length); + } + } - protected ECMultiplier createBasePointMultiplier() { - return new FixedPointCombMultiplier(); - } + public byte[] generateSignature() throws CryptoException { + 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) { - return new BigInteger(1, var2); - } + while (true) { + 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); + } } diff --git a/src/main/java/org.zz/gmhelper/SM2Util.java b/src/main/java/org.zz/gmhelper/SM2Util.java index 77ba837..53ae7d6 100644 --- a/src/main/java/org.zz/gmhelper/SM2Util.java +++ b/src/main/java/org.zz/gmhelper/SM2Util.java @@ -44,21 +44,17 @@ public class SM2Util extends GMBaseUtil { ////////////////////////////////////////////////////////////////////////////////////// public static final EllipticCurve JDK_CURVE = new EllipticCurve(new ECFieldFp(SM2_ECC_P), SM2_ECC_A, SM2_ECC_B); - public static final java.security.spec.ECPoint JDK_G_POINT = - new java.security.spec.ECPoint( - G_POINT.getAffineXCoord().toBigInteger(), - G_POINT.getAffineYCoord().toBigInteger()); + public static final java.security.spec.ECPoint JDK_G_POINT = new java.security.spec.ECPoint( + G_POINT.getAffineXCoord().toBigInteger(), G_POINT.getAffineYCoord().toBigInteger()); public static final java.security.spec.ECParameterSpec JDK_EC_SPEC = - new java.security.spec.ECParameterSpec( - JDK_CURVE, JDK_G_POINT, SM2_ECC_N, SM2_ECC_H.intValue()); + new java.security.spec.ECParameterSpec(JDK_CURVE, JDK_G_POINT, SM2_ECC_N, + SM2_ECC_H.intValue()); public static final int SM3_DIGEST_LENGTH = 32; ////////////////////////////////////////////////////////////////////////////////////// - static ECCurve.Fp SM2_ECC_FP = - new ECCurve.Fp( - SM2_ECC_P, // q - SM2_ECC_A, // a - SM2_ECC_B); // b + static ECCurve.Fp SM2_ECC_FP = new ECCurve.Fp(SM2_ECC_P, // q + SM2_ECC_A, // a + SM2_ECC_B); // b /** * 生成ECC密钥对 @@ -79,9 +75,8 @@ public class SM2Util extends GMBaseUtil { * @throws NoSuchAlgorithmException * @throws InvalidAlgorithmParameterException */ - public static KeyPair generateKeyPair(SecureRandom random) - throws NoSuchProviderException, NoSuchAlgorithmException, - InvalidAlgorithmParameterException { + public static KeyPair generateKeyPair(SecureRandom random) throws NoSuchProviderException, + NoSuchAlgorithmException, InvalidAlgorithmParameterException { return BCECUtil.generateKeyPair(DOMAIN_PARAMS, random); } @@ -95,9 +90,8 @@ public class SM2Util extends GMBaseUtil { BCECPrivateKey privateKey = (BCECPrivateKey) key.getPrivate(); BCECPublicKey publicKey = (BCECPublicKey) key.getPublic(); byte[] point = publicKey.getQ().getEncoded(false); - ECPublicKeyParameters parameters = - BCECUtil.createECPublicKeyFromStrParameters( - ByteUtils.toHexString(point), CURVE, DOMAIN_PARAMS); + ECPublicKeyParameters parameters = BCECUtil.createECPublicKeyFromStrParameters( + ByteUtils.toHexString(point), CURVE, DOMAIN_PARAMS); return new SM2KeyPair(parameters, privateKey.getD()); } catch (Exception e) { e.printStackTrace(); @@ -129,7 +123,7 @@ public class SM2Util extends GMBaseUtil { } /** - * @param pubKey 公钥 + * @param pubKey 公钥 * @param srcData 原文 * @return 默认输出C1C3C2顺序的密文。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。 * @throws InvalidCipherTextException @@ -141,8 +135,8 @@ public class SM2Util extends GMBaseUtil { } /** - * @param mode 指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2 - * @param pubKey 公钥 + * @param mode 指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2 + * @param pubKey 公钥 * @param srcData 原文 * @return 根据mode不同,输出的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。 * @throws InvalidCipherTextException @@ -155,7 +149,7 @@ public class SM2Util extends GMBaseUtil { /** * @param pubKeyParameters 公钥 - * @param srcData 原文 + * @param srcData 原文 * @return 默认输出C1C3C2顺序的密文。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。 * @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 srcData 原文 + * @param srcData 原文 * @return 根据mode不同,输出的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。 * @throws InvalidCipherTextException */ @@ -180,8 +174,9 @@ public class SM2Util extends GMBaseUtil { } /** - * @param priKey 私钥 - * @param sm2Cipher 默认输入C1C3C2顺序的密文。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。 + * @param priKey 私钥 + * @param sm2Cipher + * 默认输入C1C3C2顺序的密文。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。 * @return 原文。SM2解密返回了数据则一定是原文,因为SM2自带校验,如果密文被篡改或者密钥对不上,都是会直接报异常的。 * @throws InvalidCipherTextException */ @@ -192,9 +187,10 @@ public class SM2Util extends GMBaseUtil { } /** - * @param mode 指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2 - * @param priKey 私钥 - * @param sm2Cipher 根据mode不同,需要输入的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。 + * @param mode 指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2 + * @param priKey 私钥 + * @param sm2Cipher + * 根据mode不同,需要输入的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。 * @return 原文。SM2解密返回了数据则一定是原文,因为SM2自带校验,如果密文被篡改或者密钥对不上,都是会直接报异常的。 * @throws InvalidCipherTextException */ @@ -206,7 +202,8 @@ public class SM2Util extends GMBaseUtil { /** * @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自带校验,如果密文被篡改或者密钥对不上,都是会直接报异常的。 * @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 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自带校验,如果密文被篡改或者密钥对不上,都是会直接报异常的。 * @throws InvalidCipherTextException */ - public static byte[] decrypt( - Mode mode, ECPrivateKeyParameters priKeyParameters, byte[] sm2Cipher) - throws InvalidCipherTextException { + public static byte[] decrypt(Mode mode, ECPrivateKeyParameters priKeyParameters, + byte[] sm2Cipher) throws InvalidCipherTextException { SM2Engine engine = new SM2Engine(mode); engine.init(false, priKeyParameters); if (sm2Cipher[0] != 4) { @@ -239,7 +236,8 @@ public class SM2Util extends GMBaseUtil { /** * 分解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 * @throws Exception */ @@ -251,8 +249,9 @@ public class SM2Util extends GMBaseUtil { /** * 分解SM2密文 * - * @param mode 指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2 - * @param cipherText 根据mode不同,需要输入的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。 + * @param mode 指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2 + * @param cipherText + * 根据mode不同,需要输入的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。 * @return */ 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 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 * @throws Exception */ @@ -275,14 +275,15 @@ public class SM2Util extends GMBaseUtil { /** * 分解SM2密文 * - * @param mode 指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2 - * @param curveLength 曲线长度,SM2的话就是256位。 + * @param mode 指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2 + * @param curveLength 曲线长度,SM2的话就是256位。 * @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 */ - public static SM2Cipher parseSM2Cipher( - Mode mode, int curveLength, int digestLength, byte[] cipherText) throws Exception { + public static SM2Cipher parseSM2Cipher(Mode mode, int curveLength, int digestLength, + byte[] cipherText) throws Exception { byte[] c1 = new byte[curveLength * 2 + 1]; byte[] c2 = new byte[cipherText.length - c1.length - digestLength]; byte[] c3 = new byte[digestLength]; @@ -321,8 +322,9 @@ public class SM2Util extends GMBaseUtil { /** * DER编码密文 * - * @param mode 指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2 - * @param cipher 根据mode不同,需要输入的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。 + * @param mode 指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2 + * @param cipher + * 根据mode不同,需要输入的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。 * @return 按指定mode DER编码后的密文 * @throws Exception */ @@ -334,9 +336,9 @@ public class SM2Util extends GMBaseUtil { /** * DER编码密文 * - * @param curveLength 曲线长度,SM2的话就是256位。 + * @param curveLength 曲线长度,SM2的话就是256位。 * @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编码的结果 * @throws IOException */ @@ -346,15 +348,16 @@ public class SM2Util extends GMBaseUtil { } /** - * @param mode 指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2 - * @param curveLength 曲线长度,SM2的话就是256位。 + * @param mode 指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2 + * @param curveLength 曲线长度,SM2的话就是256位。 * @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编码后的密文 * @throws Exception */ - public static byte[] encodeSM2CipherToDER( - Mode mode, int curveLength, int digestLength, byte[] cipher) throws Exception { + public static byte[] encodeSM2CipherToDER(Mode mode, int curveLength, int digestLength, + byte[] cipher) throws Exception { byte[] c1x = new byte[curveLength]; byte[] c1y = new byte[curveLength]; @@ -379,8 +382,8 @@ public class SM2Util extends GMBaseUtil { } ASN1Encodable[] arr = new ASN1Encodable[4]; - arr[0] = new ASN1Integer(new BigInteger(1,c1x)); - arr[1] = new ASN1Integer(new BigInteger(1,c1y)); + arr[0] = new ASN1Integer(new BigInteger(1, c1x)); + arr[1] = new ASN1Integer(new BigInteger(1, c1y)); if (mode == Mode.C1C2C3) { arr[2] = new DEROctetString(c2); 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编码后的密文 * @return 根据mode不同,输出的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。 * @throws Exception @@ -450,7 +453,7 @@ public class SM2Util extends GMBaseUtil { /** * 签名 * - * @param priKey 私钥 + * @param priKey 私钥 * @param srcData 原文 * @return DER编码后的签名值 * @throws CryptoException @@ -464,7 +467,7 @@ public class SM2Util extends GMBaseUtil { * 签名 不指定withId,则默认withId为字节数组:"1234567812345678".getBytes() * * @param priKeyParameters 私钥 - * @param srcData 原文 + * @param srcData 原文 * @return DER编码后的签名值 * @throws CryptoException */ @@ -476,8 +479,8 @@ public class SM2Util extends GMBaseUtil { /** * 私钥签名 * - * @param priKey 私钥 - * @param withId 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes() + * @param priKey 私钥 + * @param withId 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes() * @param srcData 原文 * @return DER编码后的签名值 * @throws CryptoException @@ -492,14 +495,13 @@ public class SM2Util extends GMBaseUtil { * 签名 * * @param priKeyParameters 私钥 - * @param withId 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes() - * @param srcData 源数据 + * @param withId 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes() + * @param srcData 源数据 * @return DER编码后的签名值 * @throws CryptoException */ - public static byte[] sign( - ECPrivateKeyParameters priKeyParameters, byte[] withId, byte[] srcData) - throws CryptoException { + public static byte[] sign(ECPrivateKeyParameters priKeyParameters, byte[] withId, + byte[] srcData) throws CryptoException { SM2Signer signer = new SM2Signer(); CipherParameters param = null; ParametersWithRandom pwr = new ParametersWithRandom(priKeyParameters, new SecureRandom()); @@ -576,22 +578,22 @@ public class SM2Util extends GMBaseUtil { * 验签 不指定withId,则默认withId为字节数组:"1234567812345678".getBytes() * * @param pubKeyParameters 公钥 - * @param srcData 原文 - * @param sign DER编码的签名值 + * @param srcData 原文 + * @param sign DER编码的签名值 * @return 验签成功返回true,失败返回false */ - public static boolean verify( - ECPublicKeyParameters pubKeyParameters, byte[] srcData, byte[] sign) { + public static boolean verify(ECPublicKeyParameters pubKeyParameters, byte[] srcData, + byte[] sign) { return verify(pubKeyParameters, null, srcData, sign); } /** * 验签 * - * @param pubKey 公钥 - * @param withId 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes() + * @param pubKey 公钥 + * @param withId 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes() * @param srcData 原文 - * @param sign DER编码的签名值 + * @param sign DER编码的签名值 * @return */ public static boolean verify(BCECPublicKey pubKey, byte[] withId, byte[] srcData, byte[] sign) { @@ -603,13 +605,13 @@ public class SM2Util extends GMBaseUtil { * 验签 * * @param pubKeyParameters 公钥 - * @param withId 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes() - * @param srcData 原文 - * @param sign DER编码的签名值 + * @param withId 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes() + * @param srcData 原文 + * @param sign DER编码的签名值 * @return 验签成功返回true,失败返回false */ - public static boolean verify( - ECPublicKeyParameters pubKeyParameters, byte[] withId, byte[] srcData, byte[] sign) { + public static boolean verify(ECPublicKeyParameters pubKeyParameters, byte[] withId, + byte[] srcData, byte[] sign) { SM2Signer signer = new SM2Signer(); CipherParameters param; if (withId != null) { @@ -647,13 +649,12 @@ public class SM2Util extends GMBaseUtil { byte[] sigByte = ByteUtils.fromHexString(signature); // TODO 是否需要der编码? // try { - // sigByte = SM2Util.encodeSM2SignToDER(sigByte); + // sigByte = SM2Util.encodeSM2SignToDER(sigByte); // } catch (Exception e) { - // e.printStackTrace(); + // e.printStackTrace(); // } - ECPublicKeyParameters pubkey = - BCECUtil.createECPublicKeyFromStrParameters( - publicKey, SM2Util.CURVE, SM2Util.DOMAIN_PARAMS); + ECPublicKeyParameters pubkey = BCECUtil.createECPublicKeyFromStrParameters(publicKey, + SM2Util.CURVE, SM2Util.DOMAIN_PARAMS); boolean result = SM2Util.verify(pubkey, toVerify.getBytes(), sigByte); return result; } catch (Exception e) { diff --git a/src/main/java/org.zz/gmhelper/SM3Util.java b/src/main/java/org.zz/gmhelper/SM3Util.java index 83b604e..0230d8a 100644 --- a/src/main/java/org.zz/gmhelper/SM3Util.java +++ b/src/main/java/org.zz/gmhelper/SM3Util.java @@ -41,7 +41,7 @@ public class SM3Util extends GMBaseUtil { /** * 计算SM3 Mac值 * - * @param key key值,可以是任意长度的字节数组 + * @param key key值,可以是任意长度的字节数组 * @param srcData 原文 * @return Mac值,对于HMac-SM3来说是32字节 */ diff --git a/src/main/java/org.zz/gmhelper/SM4Util.java b/src/main/java/org.zz/gmhelper/SM4Util.java index 55fd837..f3fe222 100644 --- a/src/main/java/org.zz/gmhelper/SM4Util.java +++ b/src/main/java/org.zz/gmhelper/SM4Util.java @@ -32,8 +32,10 @@ public class SM4Util extends GMBaseUtil { return generateKey(DEFAULT_KEY_SIZE); } - public static byte[] generateKey(int keySize) throws NoSuchAlgorithmException, NoSuchProviderException { - KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME); + public static byte[] generateKey(int keySize) + throws NoSuchAlgorithmException, NoSuchProviderException { + KeyGenerator kg = + KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME); kg.init(keySize, new SecureRandom()); return kg.generateKey().getEncoded(); } @@ -86,7 +88,8 @@ public class SM4Util extends GMBaseUtil { throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, 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); } @@ -94,18 +97,20 @@ public class SM4Util extends GMBaseUtil { throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, 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); } - public static byte[] doCMac(byte[] key, byte[] data) throws NoSuchProviderException, NoSuchAlgorithmException, - InvalidKeyException { + public static byte[] doCMac(byte[] key, byte[] data) + throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException { Key keyObj = new SecretKeySpec(key, ALGORITHM_NAME); return doMac("SM4-CMAC", keyObj, 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); } @@ -119,7 +124,8 @@ public class SM4Util extends GMBaseUtil { */ public static byte[] doCBCMac(byte[] key, byte[] iv, byte[] data) { 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); } @@ -131,19 +137,22 @@ public class SM4Util extends GMBaseUtil { * @return * @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(); if (padding == null) { if (data.length % engine.getBlockSize() != 0) { 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); } - 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); mac.init(new ParametersWithIV(cipherParameters, iv)); mac.update(data, 0, data.length); @@ -152,8 +161,8 @@ public class SM4Util extends GMBaseUtil { return result; } - private static byte[] doMac(String algorithmName, Key key, byte[] data) throws NoSuchProviderException, - NoSuchAlgorithmException, InvalidKeyException { + private static byte[] doMac(String algorithmName, Key key, byte[] data) + throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException { Mac mac = Mac.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME); mac.init(key); mac.update(data); @@ -170,8 +179,8 @@ public class SM4Util extends GMBaseUtil { } private static Cipher generateCBCCipher(String algorithmName, int mode, byte[] key, byte[] iv) - throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, - NoSuchProviderException, NoSuchPaddingException { + throws InvalidKeyException, InvalidAlgorithmParameterException, + NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException { Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME); Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME); IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); diff --git a/src/main/java/org.zz/gmhelper/cert/CommonUtil.java b/src/main/java/org.zz/gmhelper/cert/CommonUtil.java index 13c71f9..0619c3d 100644 --- a/src/main/java/org.zz/gmhelper/cert/CommonUtil.java +++ b/src/main/java/org.zz/gmhelper/cert/CommonUtil.java @@ -29,7 +29,8 @@ public class CommonUtil { * @return * @throws InvalidX500NameException */ - public static X500Name buildX500Name(Map names) throws InvalidX500NameException { + public static X500Name buildX500Name(Map names) + throws InvalidX500NameException { if (names == null || names.size() == 0) { 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, - String signAlgo) throws OperatorCreationException { - PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(subject, pubKey); + public static PKCS10CertificationRequest createCSR(X500Name subject, SM2PublicKey pubKey, + PrivateKey priKey, String signAlgo) throws OperatorCreationException { + PKCS10CertificationRequestBuilder csrBuilder = + new JcaPKCS10CertificationRequestBuilder(subject, pubKey); ContentSigner signerBuilder = new JcaContentSignerBuilder(signAlgo) - .setProvider(BouncyCastleProvider.PROVIDER_NAME).build(priKey); + .setProvider(BouncyCastleProvider.PROVIDER_NAME).build(priKey); return csrBuilder.build(signerBuilder); } public static AlgorithmIdentifier findSignatureAlgorithmIdentifier(String algoName) { - DefaultSignatureAlgorithmIdentifierFinder sigFinder = new DefaultSignatureAlgorithmIdentifierFinder(); + DefaultSignatureAlgorithmIdentifierFinder sigFinder = + new DefaultSignatureAlgorithmIdentifierFinder(); return sigFinder.find(algoName); } public static AlgorithmIdentifier findDigestAlgorithmIdentifier(String algoName) { - DefaultDigestAlgorithmIdentifierFinder digFinder = new DefaultDigestAlgorithmIdentifierFinder(); + DefaultDigestAlgorithmIdentifierFinder digFinder = + new DefaultDigestAlgorithmIdentifierFinder(); return digFinder.find(findSignatureAlgorithmIdentifier(algoName)); } } diff --git a/src/main/java/org.zz/gmhelper/cert/RandomSNAllocator.java b/src/main/java/org.zz/gmhelper/cert/RandomSNAllocator.java index 0d2803d..fae8e9d 100644 --- a/src/main/java/org.zz/gmhelper/cert/RandomSNAllocator.java +++ b/src/main/java/org.zz/gmhelper/cert/RandomSNAllocator.java @@ -32,10 +32,10 @@ public class RandomSNAllocator implements CertSNAllocator { 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 int bitLen; /** @@ -47,14 +47,15 @@ public class RandomSNAllocator implements CertSNAllocator { /** * Constructor with the specification of bitLen. + * * @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]. */ public RandomSNAllocator(int bitLen) { if (bitLen < MIN_SERIALNUMBER_SIZE || bitLen > MAX_SERIALNUMBER_SIZE) { - throw new IllegalArgumentException(String.format( - "%s may not be out of the range [%d, %d]: %d", - "bitLen", MIN_SERIALNUMBER_SIZE, MAX_SERIALNUMBER_SIZE, bitLen)); + throw new IllegalArgumentException( + String.format("%s may not be out of the range [%d, %d]: %d", "bitLen", + MIN_SERIALNUMBER_SIZE, MAX_SERIALNUMBER_SIZE, bitLen)); } this.random = new SecureRandom(); @@ -74,5 +75,5 @@ public class RandomSNAllocator implements CertSNAllocator { return new BigInteger(1, rdnBytes); } - + } diff --git a/src/main/java/org.zz/gmhelper/cert/SM2CertUtil.java b/src/main/java/org.zz/gmhelper/cert/SM2CertUtil.java index 2913a1d..76a3533 100644 --- a/src/main/java/org.zz/gmhelper/cert/SM2CertUtil.java +++ b/src/main/java/org.zz/gmhelper/cert/SM2CertUtil.java @@ -33,17 +33,17 @@ public class SM2CertUtil { ECPublicKey pubKey = (ECPublicKey) sm2Cert.getPublicKey(); ECPoint q = pubKey.getQ(); 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); return new BCECPublicKey(pubKey.getAlgorithm(), pubKeySpec, - BouncyCastleProvider.CONFIGURATION); + BouncyCastleProvider.CONFIGURATION); } /** * 校验证书 * * @param issuerPubKey 从颁发者CA证书中提取出来的公钥 - * @param cert 待校验的证书 + * @param cert 待校验的证书 * @return */ public static boolean verifyCertificate(BCECPublicKey issuerPubKey, X509Certificate cert) { @@ -55,8 +55,8 @@ public class SM2CertUtil { return true; } - public static X509Certificate getX509Certificate(String certFilePath) throws IOException, CertificateException, - NoSuchProviderException { + public static X509Certificate getX509Certificate(String certFilePath) + throws IOException, CertificateException, NoSuchProviderException { InputStream is = null; try { is = new FileInputStream(certFilePath); @@ -68,20 +68,21 @@ public class SM2CertUtil { } } - public static X509Certificate getX509Certificate(byte[] certBytes) throws CertificateException, - NoSuchProviderException { + public static X509Certificate getX509Certificate(byte[] certBytes) + throws CertificateException, NoSuchProviderException { ByteArrayInputStream bais = new ByteArrayInputStream(certBytes); return getX509Certificate(bais); } - public static X509Certificate getX509Certificate(InputStream is) throws CertificateException, - NoSuchProviderException { - CertificateFactory cf = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME); + public static X509Certificate getX509Certificate(InputStream is) + throws CertificateException, NoSuchProviderException { + CertificateFactory cf = + CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME); return (X509Certificate) cf.generateCertificate(is); } - public static CertPath getCertificateChain(String certChainPath) throws IOException, CertificateException, - NoSuchProviderException { + public static CertPath getCertificateChain(String certChainPath) + throws IOException, CertificateException, NoSuchProviderException { InputStream is = null; try { is = new FileInputStream(certChainPath); @@ -93,30 +94,37 @@ public class SM2CertUtil { } } - public static CertPath getCertificateChain(byte[] certChainBytes) throws CertificateException, - NoSuchProviderException { + public static CertPath getCertificateChain(byte[] certChainBytes) + throws CertificateException, NoSuchProviderException { ByteArrayInputStream bais = new ByteArrayInputStream(certChainBytes); return getCertificateChain(bais); } - public static byte[] getCertificateChainBytes(CertPath certChain) throws CertificateEncodingException { + public static byte[] getCertificateChainBytes(CertPath certChain) + throws CertificateEncodingException { return certChain.getEncoded("PKCS7"); } - public static CertPath getCertificateChain(InputStream is) throws CertificateException, NoSuchProviderException { - CertificateFactory cf = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME); + public static CertPath getCertificateChain(InputStream is) + throws CertificateException, NoSuchProviderException { + CertificateFactory cf = + CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME); return cf.generateCertPath(is, "PKCS7"); } - public static CertPath getCertificateChain(List certs) throws CertificateException, - NoSuchProviderException { - CertificateFactory cf = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME); + public static CertPath getCertificateChain(List certs) + throws CertificateException, NoSuchProviderException { + CertificateFactory cf = + CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME); return cf.generateCertPath(certs); } - public static X509Certificate getX509CertificateFromPfx(byte[] pfxDER, String passwd) throws Exception { - InputDecryptorProvider inputDecryptorProvider = new JcePKCSPBEInputDecryptorProviderBuilder() - .setProvider(BouncyCastleProvider.PROVIDER_NAME).build(passwd.toCharArray()); + public static X509Certificate getX509CertificateFromPfx(byte[] pfxDER, String passwd) + throws Exception { + InputDecryptorProvider inputDecryptorProvider = + new JcePKCSPBEInputDecryptorProviderBuilder() + .setProvider(BouncyCastleProvider.PROVIDER_NAME) + .build(passwd.toCharArray()); PKCS12PfxPdu pfx = new PKCS12PfxPdu(pfxDER); ContentInfo[] infos = pfx.getContentInfos(); @@ -126,7 +134,8 @@ public class SM2CertUtil { for (int i = 0; i != infos.length; i++) { 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(); X509CertificateHolder certHoler = (X509CertificateHolder) bags[0].getBagValue(); return SM2CertUtil.getX509Certificate(certHoler.getEncoded()); @@ -140,9 +149,12 @@ public class SM2CertUtil { return SM2CertUtil.getBCECPublicKey(getX509CertificateFromPfx(pfxDER, passwd)); } - public static BCECPrivateKey getPrivateKeyFromPfx(byte[] pfxDER, String passwd) throws Exception { - InputDecryptorProvider inputDecryptorProvider = new JcePKCSPBEInputDecryptorProviderBuilder() - .setProvider(BouncyCastleProvider.PROVIDER_NAME).build(passwd.toCharArray()); + public static BCECPrivateKey getPrivateKeyFromPfx(byte[] pfxDER, String passwd) + throws Exception { + InputDecryptorProvider inputDecryptorProvider = + new JcePKCSPBEInputDecryptorProviderBuilder() + .setProvider(BouncyCastleProvider.PROVIDER_NAME) + .build(passwd.toCharArray()); PKCS12PfxPdu pfx = new PKCS12PfxPdu(pfxDER); ContentInfo[] infos = pfx.getContentInfos(); @@ -154,7 +166,8 @@ public class SM2CertUtil { if (!infos[i].getContentType().equals(PKCSObjectIdentifiers.encryptedData)) { PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i]); PKCS12SafeBag[] bags = dataFact.getSafeBags(); - PKCS8EncryptedPrivateKeyInfo encInfo = (PKCS8EncryptedPrivateKeyInfo) bags[0].getBagValue(); + PKCS8EncryptedPrivateKeyInfo encInfo = + (PKCS8EncryptedPrivateKeyInfo) bags[0].getBagValue(); PrivateKeyInfo info = encInfo.decryptPrivateKeyInfo(inputDecryptorProvider); BCECPrivateKey privateKey = BCECUtil.convertPKCS8ToECPrivateKey(info.getEncoded()); return privateKey; diff --git a/src/main/java/org.zz/gmhelper/cert/SM2PfxMaker.java b/src/main/java/org.zz/gmhelper/cert/SM2PfxMaker.java index 834a738..c56ebb8 100644 --- a/src/main/java/org.zz/gmhelper/cert/SM2PfxMaker.java +++ b/src/main/java/org.zz/gmhelper/cert/SM2PfxMaker.java @@ -21,41 +21,41 @@ public class SM2PfxMaker { /** * @param privKey 用户私钥 - * @param pubKey 用户公钥 - * @param chain X509证书数组,切记这里固定了必须是3个元素的数组,且第一个必须是叶子证书、第二个为中级CA证书、第三个为根CA证书 - * @param passwd 口令 + * @param pubKey 用户公钥 + * @param chain X509证书数组,切记这里固定了必须是3个元素的数组,且第一个必须是叶子证书、第二个为中级CA证书、第三个为根CA证书 + * @param passwd 口令 * @return * @throws NoSuchAlgorithmException * @throws IOException * @throws PKCSException */ - public PKCS12PfxPdu makePfx(PrivateKey privKey, PublicKey pubKey, X509Certificate[] chain, String passwd) - throws NoSuchAlgorithmException, IOException, PKCSException { + public PKCS12PfxPdu makePfx(PrivateKey privKey, PublicKey pubKey, X509Certificate[] chain, + String passwd) throws NoSuchAlgorithmException, IOException, PKCSException { JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils(); PKCS12SafeBagBuilder taCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[2]); taCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, - new DERBMPString("Primary Certificate")); + new DERBMPString("Primary Certificate")); PKCS12SafeBagBuilder caCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[1]); caCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, - new DERBMPString("Intermediate Certificate")); + new DERBMPString("Intermediate Certificate")); PKCS12SafeBagBuilder eeCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[0]); eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, - new DERBMPString("User Key")); + new DERBMPString("User Key")); eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, - extUtils.createSubjectKeyIdentifier(pubKey)); + extUtils.createSubjectKeyIdentifier(pubKey)); char[] passwdChars = passwd.toCharArray(); PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(privKey, - new BcPKCS12PBEOutputEncryptorBuilder( - PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, - new CBCBlockCipher(new DESedeEngine())).build(passwdChars)); + new BcPKCS12PBEOutputEncryptorBuilder( + PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, + new CBCBlockCipher(new DESedeEngine())).build(passwdChars)); keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, - new DERBMPString("User Key")); + new DERBMPString("User Key")); keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, - extUtils.createSubjectKeyIdentifier(pubKey)); + extUtils.createSubjectKeyIdentifier(pubKey)); PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder(); PKCS12SafeBag[] certs = new PKCS12SafeBag[3]; @@ -64,49 +64,47 @@ public class SM2PfxMaker { certs[2] = taCertBagBuilder.build(); pfxPduBuilder.addEncryptedData(new BcPKCS12PBEOutputEncryptorBuilder( PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, - new CBCBlockCipher(new RC2Engine())).build(passwdChars), - certs); + new CBCBlockCipher(new RC2Engine())).build(passwdChars), certs); pfxPduBuilder.addData(keyBagBuilder.build()); return pfxPduBuilder.build(new BcPKCS12MacCalculatorBuilder(), passwdChars); } /** * @param privKey 用户私钥 - * @param pubKey 用户公钥 - * @param cert X509证书 - * @param passwd 口令 + * @param pubKey 用户公钥 + * @param cert X509证书 + * @param passwd 口令 * @return * @throws NoSuchAlgorithmException * @throws IOException * @throws PKCSException */ - public PKCS12PfxPdu makePfx(PrivateKey privKey, PublicKey pubKey, X509Certificate cert, String passwd) - throws NoSuchAlgorithmException, IOException, PKCSException { + public PKCS12PfxPdu makePfx(PrivateKey privKey, PublicKey pubKey, X509Certificate cert, + String passwd) throws NoSuchAlgorithmException, IOException, PKCSException { JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils(); PKCS12SafeBagBuilder eeCertBagBuilder = new JcaPKCS12SafeBagBuilder(cert); eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, - new DERBMPString("User Key")); + new DERBMPString("User Key")); eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, - extUtils.createSubjectKeyIdentifier(pubKey)); + extUtils.createSubjectKeyIdentifier(pubKey)); char[] passwdChars = passwd.toCharArray(); PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(privKey, - new BcPKCS12PBEOutputEncryptorBuilder( - PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, - new CBCBlockCipher(new DESedeEngine())).build(passwdChars)); + new BcPKCS12PBEOutputEncryptorBuilder( + PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, + new CBCBlockCipher(new DESedeEngine())).build(passwdChars)); keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, - new DERBMPString("User Key")); + new DERBMPString("User Key")); keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, - extUtils.createSubjectKeyIdentifier(pubKey)); + extUtils.createSubjectKeyIdentifier(pubKey)); PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder(); PKCS12SafeBag[] certs = new PKCS12SafeBag[1]; certs[0] = eeCertBagBuilder.build(); pfxPduBuilder.addEncryptedData(new BcPKCS12PBEOutputEncryptorBuilder( PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, - new CBCBlockCipher(new RC2Engine())).build(passwdChars), - certs); + new CBCBlockCipher(new RC2Engine())).build(passwdChars), certs); pfxPduBuilder.addData(keyBagBuilder.build()); return pfxPduBuilder.build(new BcPKCS12MacCalculatorBuilder(), passwdChars); } diff --git a/src/main/java/org.zz/gmhelper/cert/SM2Pkcs12Maker.java b/src/main/java/org.zz/gmhelper/cert/SM2Pkcs12Maker.java index ca04a36..9cd07a2 100644 --- a/src/main/java/org.zz/gmhelper/cert/SM2Pkcs12Maker.java +++ b/src/main/java/org.zz/gmhelper/cert/SM2Pkcs12Maker.java @@ -12,9 +12,8 @@ public class SM2Pkcs12Maker { /** * @param privKey 用户私钥 - * @param chain X509证书数组, - * 第一个(index 0)为privKey对应的证书,index i+1 是index i的CA证书 - * @param passwd 口令 + * @param chain X509证书数组, 第一个(index 0)为privKey对应的证书,index i+1 是index i的CA证书 + * @param passwd 口令 * @return the PKCS#12 keystore * @throws NoSuchProviderException * @throws KeyStoreException @@ -24,8 +23,8 @@ public class SM2Pkcs12Maker { * @throws PKCSException */ public KeyStore makePkcs12(PrivateKey privKey, X509Certificate[] chain, char[] passwd) - throws KeyStoreException, NoSuchProviderException, - NoSuchAlgorithmException, CertificateException, IOException { + throws KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException, + CertificateException, IOException { KeyStore ks = KeyStore.getInstance("PKCS12", "BC"); ks.load(null, passwd); ks.setKeyEntry("User Key", privKey, passwd, chain); @@ -34,16 +33,16 @@ public class SM2Pkcs12Maker { /** * @param privKey 用户私钥 - * @param cert X509证书 - * @param passwd 口令 + * @param cert X509证书 + * @param passwd 口令 * @return the PKCS12 keystore * @throws NoSuchAlgorithmException * @throws IOException * @throws PKCSException */ public KeyStore makePkcs12(PrivateKey privKey, X509Certificate cert, char[] passwd) - throws KeyStoreException, NoSuchProviderException, - NoSuchAlgorithmException, CertificateException, IOException { - return makePkcs12(privKey, new X509Certificate[] {cert}, passwd); + throws KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException, + CertificateException, IOException { + return makePkcs12(privKey, new X509Certificate[] {cert}, passwd); } } diff --git a/src/main/java/org.zz/gmhelper/cert/SM2PrivateKey.java b/src/main/java/org.zz/gmhelper/cert/SM2PrivateKey.java index ec93b3e..aab5835 100644 --- a/src/main/java/org.zz/gmhelper/cert/SM2PrivateKey.java +++ b/src/main/java/org.zz/gmhelper/cert/SM2PrivateKey.java @@ -23,7 +23,8 @@ public class SM2PrivateKey extends BCECPrivateKey { public SM2PrivateKey(BCECPrivateKey privateKey, BCECPublicKey publicKey) { super(privateKey.getAlgorithm(), privateKey); - this.sm2PublicKey = getSM2PublicKeyDetails(new SM2PublicKey(publicKey.getAlgorithm(), publicKey)); + this.sm2PublicKey = + getSM2PublicKeyDetails(new SM2PublicKey(publicKey.getAlgorithm(), publicKey)); this.withCompression = false; } @@ -33,8 +34,8 @@ public class SM2PrivateKey extends BCECPrivateKey { } /** - * Return a PKCS8 representation of the key. The sequence returned - * represents a full PrivateKeyInfo object. + * Return a PKCS8 representation of the key. The sequence returned represents a full + * PrivateKeyInfo object. * * @return a PKCS8 representation of the key. */ @@ -48,20 +49,25 @@ public class SM2PrivateKey extends BCECPrivateKey { if (ecSpec == null) { orderBitLength = ECUtil.getOrderBitLength(configuration, null, this.getS()); } else { - orderBitLength = ECUtil.getOrderBitLength(configuration, ecSpec.getOrder(), this.getS()); + orderBitLength = + ECUtil.getOrderBitLength(configuration, ecSpec.getOrder(), this.getS()); } PrivateKeyInfo info; org.bouncycastle.asn1.sec.ECPrivateKey keyStructure; 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 { - keyStructure = new org.bouncycastle.asn1.sec.ECPrivateKey(orderBitLength, this.getS(), params); + keyStructure = + new org.bouncycastle.asn1.sec.ECPrivateKey(orderBitLength, this.getS(), params); } 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); } catch (IOException e) { @@ -71,10 +77,11 @@ public class SM2PrivateKey extends BCECPrivateKey { private DERBitString getSM2PublicKeyDetails(SM2PublicKey pub) { try { - SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded())); + SubjectPublicKeyInfo info = + SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded())); return info.getPublicKeyData(); - } catch (IOException e) { // should never happen + } catch (IOException e) { // should never happen return null; } } diff --git a/src/main/java/org.zz/gmhelper/cert/SM2PublicKey.java b/src/main/java/org.zz/gmhelper/cert/SM2PublicKey.java index 87e1d3f..b688df6 100644 --- a/src/main/java/org.zz/gmhelper/cert/SM2PublicKey.java +++ b/src/main/java/org.zz/gmhelper/cert/SM2PublicKey.java @@ -10,7 +10,8 @@ import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; 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; @@ -26,13 +27,13 @@ public class SM2PublicKey extends BCECPublicKey { @Override public byte[] getEncoded() { - ASN1OctetString p = ASN1OctetString.getInstance( - new X9ECPoint(getQ(), withCompression).toASN1Primitive()); + ASN1OctetString p = ASN1OctetString + .getInstance(new X9ECPoint(getQ(), withCompression).toASN1Primitive()); // stored curve is null if ImplicitlyCa SubjectPublicKeyInfo info = new SubjectPublicKeyInfo( - new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, ID_SM2_PUBKEY_PARAM), - p.getOctets()); + new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, ID_SM2_PUBKEY_PARAM), + p.getOctets()); return KeyUtil.getEncodedSubjectPublicKeyInfo(info); } diff --git a/src/main/java/org.zz/gmhelper/cert/SM2X509CertMaker.java b/src/main/java/org.zz/gmhelper/cert/SM2X509CertMaker.java index 943fac8..fe21f75 100644 --- a/src/main/java/org.zz/gmhelper/cert/SM2X509CertMaker.java +++ b/src/main/java/org.zz/gmhelper/cert/SM2X509CertMaker.java @@ -26,11 +26,9 @@ import java.util.LinkedList; import java.util.List; public class SM2X509CertMaker { - + private static enum CertLevel { - RootCA, - SubCA, - EndEntity + RootCA, SubCA, EndEntity } // class CertLevel public static final String SIGN_ALGO_SM3WITHSM2 = "SM3withSM2"; @@ -41,16 +39,14 @@ public class SM2X509CertMaker { private KeyPair issuerKeyPair; /** - * @param issuerKeyPair 证书颁发者的密钥对。 - * 其实一般的CA的私钥都是要严格保护的。 - * 一般CA的私钥都会放在加密卡/加密机里,证书的签名由加密卡/加密机完成。 - * 这里仅是为了演示BC库签发证书的用法,所以暂时不作太多要求。 - * @param certExpire 证书有效时间,单位毫秒 - * @param issuer 证书颁发者信息 - * @param snAllocator 维护/分配证书序列号的实例,证书序列号应该递增且不重复 + * @param issuerKeyPair 证书颁发者的密钥对。 其实一般的CA的私钥都是要严格保护的。 一般CA的私钥都会放在加密卡/加密机里,证书的签名由加密卡/加密机完成。 + * 这里仅是为了演示BC库签发证书的用法,所以暂时不作太多要求。 + * @param certExpire 证书有效时间,单位毫秒 + * @param issuer 证书颁发者信息 + * @param snAllocator 维护/分配证书序列号的实例,证书序列号应该递增且不重复 */ public SM2X509CertMaker(KeyPair issuerKeyPair, long certExpire, X500Name issuer, - CertSNAllocator snAllocator) { + CertSNAllocator snAllocator) { this.issuerKeyPair = issuerKeyPair; this.certExpire = certExpire; this.issuerDN = issuer; @@ -64,12 +60,11 @@ public class SM2X509CertMaker { * @return 新的证书 * @throws Exception 如果错误发生 */ - public X509Certificate makeRootCACert(byte[] csr) - throws Exception { + public X509Certificate makeRootCACert(byte[] csr) throws Exception { KeyUsage usage = new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign); return makeCertificate(CertLevel.RootCA, null, csr, usage, null); } - + /** * 生成SubCA证书 * @@ -77,8 +72,7 @@ public class SM2X509CertMaker { * @return 新的证书 * @throws Exception 如果错误发生 */ - public X509Certificate makeSubCACert(byte[] csr) - throws Exception { + public X509Certificate makeSubCACert(byte[] csr) throws Exception { KeyUsage usage = new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign); return makeCertificate(CertLevel.SubCA, 0, csr, usage, null); } @@ -90,10 +84,9 @@ public class SM2X509CertMaker { * @return 新的证书 * @throws Exception 如果错误发生 */ - public X509Certificate makeSSLEndEntityCert(byte[] csr) - throws Exception { + public X509Certificate makeSSLEndEntityCert(byte[] csr) throws Exception { return makeEndEntityCert(csr, - new KeyPurposeId[] {KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_serverAuth}); + new KeyPurposeId[] {KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_serverAuth}); } /** @@ -104,54 +97,50 @@ public class SM2X509CertMaker { * @return 新的证书 * @throws Exception 如果错误发生 */ - public X509Certificate makeEndEntityCert(byte[] csr, - KeyPurposeId[] extendedKeyUsages) + public X509Certificate makeEndEntityCert(byte[] csr, KeyPurposeId[] extendedKeyUsages) throws Exception { KeyUsage usage = new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyAgreement - | KeyUsage.dataEncipherment | KeyUsage.keyEncipherment); + | KeyUsage.dataEncipherment | KeyUsage.keyEncipherment); return makeCertificate(CertLevel.SubCA, null, csr, usage, extendedKeyUsages); } /** - * @param isCA 是否是颁发给CA的证书 + * @param isCA 是否是颁发给CA的证书 * @param keyUsage 证书用途 - * @param csr CSR + * @param csr CSR * @return * @throws Exception */ private X509Certificate makeCertificate(CertLevel certLevel, Integer pathLenConstrain, - byte[] csr, KeyUsage keyUsage, KeyPurposeId[] extendedKeyUsages) - throws Exception { + byte[] csr, KeyUsage keyUsage, KeyPurposeId[] extendedKeyUsages) throws Exception { if (certLevel == CertLevel.EndEntity) { if (keyUsage.hasUsages(KeyUsage.keyCertSign)) { - throw new IllegalArgumentException( - "keyusage keyCertSign is not allowed in EndEntity Certificate"); + throw new IllegalArgumentException( + "keyusage keyCertSign is not allowed in EndEntity Certificate"); } } - + PKCS10CertificationRequest request = new PKCS10CertificationRequest(csr); SubjectPublicKeyInfo subPub = request.getSubjectPublicKeyInfo(); PrivateKey issPriv = issuerKeyPair.getPrivate(); PublicKey issPub = issuerKeyPair.getPublic(); - + X500Name subject = request.getSubject(); String email = null; String commonName = null; /* - * RFC 5280 §4.2.1.6 Subject - * Conforming implementations generating new certificates with - * electronic mail addresses MUST use the rfc822Name in the subject - * alternative name extension (Section 4.2.1.6) to describe such - * identities. Simultaneous inclusion of the emailAddress attribute in - * the subject distinguished name to support legacy implementations is - * deprecated but permitted. + * RFC 5280 §4.2.1.6 Subject Conforming implementations generating new certificates with + * electronic mail addresses MUST use the rfc822Name in the subject alternative name + * extension (Section 4.2.1.6) to describe such identities. Simultaneous inclusion of the + * emailAddress attribute in the subject distinguished name to support legacy + * implementations is deprecated but permitted. */ RDN[] rdns = subject.getRDNs(); List newRdns = new ArrayList<>(rdns.length); for (int i = 0; i < rdns.length; i++) { RDN rdn = rdns[i]; - + AttributeTypeAndValue atv = rdn.getFirst(); ASN1ObjectIdentifier type = atv.getType(); if (BCStyle.EmailAddress.equals(type)) { @@ -163,28 +152,28 @@ public class SM2X509CertMaker { newRdns.add(rdn); } } - + List subjectAltNames = new LinkedList<>(); if (email != null) { subject = new X500Name(newRdns.toArray(new RDN[0])); - subjectAltNames.add( - new GeneralName(GeneralName.rfc822Name, - new DERIA5String(email, true))); + subjectAltNames + .add(new GeneralName(GeneralName.rfc822Name, new DERIA5String(email, true))); } - + boolean selfSignedEECert = false; switch (certLevel) { case RootCA: if (issuerDN.equals(subject)) { subject = issuerDN; } else { - throw new IllegalArgumentException("subject != issuer for certLevel " + CertLevel.RootCA); + throw new IllegalArgumentException( + "subject != issuer for certLevel " + CertLevel.RootCA); } break; case SubCA: if (issuerDN.equals(subject)) { throw new IllegalArgumentException( - "subject MUST not equals issuer for certLevel " + certLevel); + "subject MUST not equals issuer for certLevel " + certLevel); } break; default: @@ -197,17 +186,16 @@ public class SM2X509CertMaker { BigInteger serialNumber = snAllocator.nextSerialNumber(); Date notBefore = new Date(); Date notAfter = new Date(notBefore.getTime() + certExpire); - X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder( - issuerDN, serialNumber, - notBefore, notAfter, - subject, subPub); + X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder(issuerDN, serialNumber, + notBefore, notAfter, subject, subPub); JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils(); v3CertGen.addExtension(Extension.subjectKeyIdentifier, false, - extUtils.createSubjectKeyIdentifier(subPub)); + extUtils.createSubjectKeyIdentifier(subPub)); if (certLevel != CertLevel.RootCA && !selfSignedEECert) { 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: @@ -219,18 +207,19 @@ public class SM2X509CertMaker { if (certLevel == CertLevel.EndEntity) { basicConstraints = new BasicConstraints(false); } else { - basicConstraints = pathLenConstrain == null - ? new BasicConstraints(true) : new BasicConstraints(pathLenConstrain.intValue()); + basicConstraints = pathLenConstrain == null ? new BasicConstraints(true) + : new BasicConstraints(pathLenConstrain.intValue()); } 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); if (extendedKeyUsages != null) { ExtendedKeyUsage xku = new ExtendedKeyUsage(extendedKeyUsages); v3CertGen.addExtension(Extension.extendedKeyUsage, false, xku); - + boolean forSSLServer = false; for (KeyPurposeId purposeId : extendedKeyUsages) { if (KeyPurposeId.id_kp_serverAuth.equals(purposeId)) { @@ -243,20 +232,21 @@ public class SM2X509CertMaker { if (commonName == null) { throw new IllegalArgumentException("commonName must not be null"); } - GeneralName name = new GeneralName(GeneralName.dNSName, - new DERIA5String(commonName, true)); + GeneralName name = + new GeneralName(GeneralName.dNSName, new DERIA5String(commonName, true)); subjectAltNames.add(name); } } - + if (!subjectAltNames.isEmpty()) { v3CertGen.addExtension(Extension.subjectAlternativeName, false, - new GeneralNames(subjectAltNames.toArray(new GeneralName[0]))); + new GeneralNames(subjectAltNames.toArray(new GeneralName[0]))); } JcaContentSignerBuilder contentSignerBuilder = makeContentSignerBuilder(issPub); - X509Certificate cert = new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME) - .getCertificate(v3CertGen.build(contentSignerBuilder.build(issPriv))); + X509Certificate cert = + new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME) + .getCertificate(v3CertGen.build(contentSignerBuilder.build(issPriv))); cert.verify(issPub); return cert; @@ -264,7 +254,8 @@ public class SM2X509CertMaker { private JcaContentSignerBuilder makeContentSignerBuilder(PublicKey issPub) throws Exception { if (issPub.getAlgorithm().equals("EC")) { - JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder(SIGN_ALGO_SM3WITHSM2); + JcaContentSignerBuilder contentSignerBuilder = + new JcaContentSignerBuilder(SIGN_ALGO_SM3WITHSM2); contentSignerBuilder.setProvider(BouncyCastleProvider.PROVIDER_NAME); return contentSignerBuilder; } diff --git a/src/main/java/org/paillier/PaillierCipher.java b/src/main/java/org/paillier/PaillierCipher.java old mode 100755 new mode 100644 index 3ee4773..d6721a0 --- a/src/main/java/org/paillier/PaillierCipher.java +++ b/src/main/java/org/paillier/PaillierCipher.java @@ -37,8 +37,8 @@ public class PaillierCipher { byte[] data = new byte[nLenBytes.length + nBytes.length + cipherBytes.length]; System.arraycopy(nLenBytes, 0, data, 0, nLenBytes.length); System.arraycopy(nBytes, 0, data, nLenBytes.length, nBytes.length); - System.arraycopy( - cipherBytes, 0, data, nLenBytes.length + nBytes.length, cipherBytes.length); + System.arraycopy(cipherBytes, 0, data, nLenBytes.length + nBytes.length, + cipherBytes.length); return data; } @@ -49,11 +49,8 @@ public class PaillierCipher { public static BigInteger decrypt(byte[] ciphertext, PrivateKey privateKey) { RSAPrivateCrtKey rsaPriKey = (RSAPrivateCrtKey) privateKey; BigInteger n = rsaPriKey.getModulus(); - BigInteger lambda = - rsaPriKey - .getPrimeP() - .subtract(BigInteger.ONE) - .multiply(rsaPriKey.getPrimeQ().subtract(BigInteger.ONE)); + BigInteger lambda = rsaPriKey.getPrimeP().subtract(BigInteger.ONE) + .multiply(rsaPriKey.getPrimeQ().subtract(BigInteger.ONE)); int nLen = CommonUtils.byte2ToUnsignedShort(ciphertext); byte[] nBytes = new byte[nLen]; @@ -70,13 +67,8 @@ public class PaillierCipher { BigInteger mu = lambda.modInverse(n); BigInteger nsquare = n.multiply(n); - BigInteger message = - intCiphertext - .modPow(lambda, nsquare) - .subtract(BigInteger.ONE) - .divide(n) - .multiply(mu) - .mod(n); + BigInteger message = intCiphertext.modPow(lambda, nsquare).subtract(BigInteger.ONE) + .divide(n).multiply(mu).mod(n); BigInteger maxValue = BigInteger.ONE.shiftLeft(n.bitLength() / 2); if (message.compareTo(maxValue) > 0) { return message.subtract(n); @@ -86,10 +78,8 @@ public class PaillierCipher { } public static String ciphertextAdd(String ciphertext1, String ciphertext2) { - return CommonUtils.byteToHexString( - ciphertextAdd( - CommonUtils.hexStringToBytes(ciphertext1), - CommonUtils.hexStringToBytes(ciphertext2))); + return CommonUtils.byteToHexString(ciphertextAdd(CommonUtils.hexStringToBytes(ciphertext1), + CommonUtils.hexStringToBytes(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]; System.arraycopy(nLenBytes, 0, data, 0, nLenBytes.length); System.arraycopy(nBytes1, 0, data, nLenBytes.length, nBytes1.length); - System.arraycopy( - cipherBytes, 0, data, nLenBytes.length + nBytes1.length, cipherBytes.length); + System.arraycopy(cipherBytes, 0, data, nLenBytes.length + nBytes1.length, + cipherBytes.length); return data; } } diff --git a/src/test/java/org/paillier/PaillierTest.java b/src/test/java/org/paillier/PaillierTest.java old mode 100755 new mode 100644 index 3735084..45c7a2b --- a/src/test/java/org/paillier/PaillierTest.java +++ b/src/test/java/org/paillier/PaillierTest.java @@ -2,8 +2,6 @@ package org.paillier; import org.junit.Assert; import org.junit.Test; -import org.paillier.PaillierCipher; -import org.paillier.PaillierKeyPair; import java.math.BigInteger; import java.security.KeyPair; @@ -18,7 +16,7 @@ public class PaillierTest { KeyPair keypair = PaillierKeyPair.generateGoodKeyPair(); RSAPublicKey pubKey = (RSAPublicKey) keypair.getPublic(); 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 privateKeyStr = PaillierKeyPair.privateKeyToPem(priKey); @@ -62,35 +60,33 @@ public class PaillierTest { @Test public void decryptTest() { - String privateKeyStr = - "-----BEGIN PRIVATE KEY-----\n" - + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1f/Oa//I+SFNN\n" - + "v+PmHGJ1vLGFDu6A0IQV9DcX/hf2R2JFW/ONxfjlrtAh4dW7itMwIA6u64UlKiml\n" - + "4UuVBT9ca4wv7R87DFqhxquh+ObMzo2x6QAaXnvL5WMmu8+/aLg6Nc06BXtJHsiw\n" - + "TO7B09AcDNccdDyI+gXP4LEsIoh9HR1p41cq1RKe5c9khLryc5zQqf6NWlw4aWr9\n" - + "AI5w4m7zhsTiDH1R9qLSJugOltY+9hLF7E9LexMLwXoQUYyi0WGxRe0h03+EQszv\n" - + "4gQA4paJPAnk8k6VrUyTlBdeoYneInxZ0FEtFffk/rqVt4B80jjVRTbleSmDNvb7\n" - + "KFp+KHSrAgMBAAECggEAG0jM2jQ3ul0tCLccD2+c7Y4cMaB5AixWbuZzkcvE1mUM\n" - + "xNh52Io2THDnIPDOLI9GCCoJiwokzd10vVcNAa30RHR2co327+1/gmpXStYb/BXg\n" - + "/ynDtjMV8STeruf05xVa/IUyANLqIafbC4XFLqYk1tKnU8O1hfHwBbwFZlkao5QH\n" - + "IN9CyDIsyyv30JbHz47HJePZkTm/2iOq4ru+pKYFHeDz4EIEJRGl8HD7wtpo3F5E\n" - + "mxe9uI5GMCdbswGnmw1a0u/VrSXpxwVyQMGHP6KWZ0dIunFW0Sh4DEdf9/tygtwx\n" - + "nJ+/RYGqTKLv59+OkJGH/e6J6BV9rKYfjTiRC+hAAQKBgQD/1dW9WSXnquVGdJkq\n" - + "QnohnMp/EkaXA3e3RiS9Bx9hhNwfdijqx3zyV1LnHGhuEaCXSCoy6zIOLQxOkkA8\n" - + "rLCzpN/hp3c8pQUwYlQodZ+G/0272jCsD2vmdOuRP2WuFA9hqGgFvUbXkXh4mcEB\n" - + "xKJY/jAddZvmnvs/dcLt6oJMqwKBgQC1nd18hcjQmIRARRUGs1ZU75yTaLKp+lXf\n" - + "M7lg8RKE9sWf4ZoT3Snj+pimUOqliE10LiHruawa137q/UC+iI0/I4H9AUhv2mAw\n" - + "m5drd+G4s6uTiCf7OQxBTmGHEvv5xH7gQih6sjOJI+N57xanC1XMGxijMOSy/D+O\n" - + "sLxB8yJ4AQKBgQDYYX3kJnB+3vYIfznEmnE92KUUkNqPg2lP483S6yFJk9ux6Hh3\n" - + "Cr7NIbqGqmpRHiubiHfYlUDC6KsOEXivWMgjSQHqk3+wFUqsP546kjGZNnoCtmqQ\n" - + "PILgameLc/mGIIVZ7dv9brdqQCmKp1CtNCiz6Fm9sOlpR3HtnKaAH+aQ/QKBgFVW\n" - + "37tidfEmqYY1r+KdJGT2zqEpokJi4jTmbiZSQPx/pG8zKB5LXyLEHzSPcyLjQFnm\n" - + "T4Qfk/Js7jNnWyPssEpJ2gvTrYD5oRdWFTmndEZBDs9dPEQ9Ezggp40763D61w9z\n" - + "pue4kqTPW1Vxdjh6CA/Hb7VHBT/hbdAT1fI7WCgBAoGAZq1rFESL3roi8DtOWl51\n" - + "nduNO20Yloe6tlhUAKo63krRHKBeKTyLXycpZHcq6UEfys3dixFfu0lN6002lUku\n" - + "MTbmNOJWhOCa2xuZY0CeINKFnKBnbiauBpo6x+2J0PoWFn8wd1tzFJPbodk8Km1f\n" - + "qySov+6mrQxHojQYBu9/yYQ=\n" - + "-----END PRIVATE KEY-----"; + String privateKeyStr = "-----BEGIN PRIVATE KEY-----\n" + + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1f/Oa//I+SFNN\n" + + "v+PmHGJ1vLGFDu6A0IQV9DcX/hf2R2JFW/ONxfjlrtAh4dW7itMwIA6u64UlKiml\n" + + "4UuVBT9ca4wv7R87DFqhxquh+ObMzo2x6QAaXnvL5WMmu8+/aLg6Nc06BXtJHsiw\n" + + "TO7B09AcDNccdDyI+gXP4LEsIoh9HR1p41cq1RKe5c9khLryc5zQqf6NWlw4aWr9\n" + + "AI5w4m7zhsTiDH1R9qLSJugOltY+9hLF7E9LexMLwXoQUYyi0WGxRe0h03+EQszv\n" + + "4gQA4paJPAnk8k6VrUyTlBdeoYneInxZ0FEtFffk/rqVt4B80jjVRTbleSmDNvb7\n" + + "KFp+KHSrAgMBAAECggEAG0jM2jQ3ul0tCLccD2+c7Y4cMaB5AixWbuZzkcvE1mUM\n" + + "xNh52Io2THDnIPDOLI9GCCoJiwokzd10vVcNAa30RHR2co327+1/gmpXStYb/BXg\n" + + "/ynDtjMV8STeruf05xVa/IUyANLqIafbC4XFLqYk1tKnU8O1hfHwBbwFZlkao5QH\n" + + "IN9CyDIsyyv30JbHz47HJePZkTm/2iOq4ru+pKYFHeDz4EIEJRGl8HD7wtpo3F5E\n" + + "mxe9uI5GMCdbswGnmw1a0u/VrSXpxwVyQMGHP6KWZ0dIunFW0Sh4DEdf9/tygtwx\n" + + "nJ+/RYGqTKLv59+OkJGH/e6J6BV9rKYfjTiRC+hAAQKBgQD/1dW9WSXnquVGdJkq\n" + + "QnohnMp/EkaXA3e3RiS9Bx9hhNwfdijqx3zyV1LnHGhuEaCXSCoy6zIOLQxOkkA8\n" + + "rLCzpN/hp3c8pQUwYlQodZ+G/0272jCsD2vmdOuRP2WuFA9hqGgFvUbXkXh4mcEB\n" + + "xKJY/jAddZvmnvs/dcLt6oJMqwKBgQC1nd18hcjQmIRARRUGs1ZU75yTaLKp+lXf\n" + + "M7lg8RKE9sWf4ZoT3Snj+pimUOqliE10LiHruawa137q/UC+iI0/I4H9AUhv2mAw\n" + + "m5drd+G4s6uTiCf7OQxBTmGHEvv5xH7gQih6sjOJI+N57xanC1XMGxijMOSy/D+O\n" + + "sLxB8yJ4AQKBgQDYYX3kJnB+3vYIfznEmnE92KUUkNqPg2lP483S6yFJk9ux6Hh3\n" + + "Cr7NIbqGqmpRHiubiHfYlUDC6KsOEXivWMgjSQHqk3+wFUqsP546kjGZNnoCtmqQ\n" + + "PILgameLc/mGIIVZ7dv9brdqQCmKp1CtNCiz6Fm9sOlpR3HtnKaAH+aQ/QKBgFVW\n" + + "37tidfEmqYY1r+KdJGT2zqEpokJi4jTmbiZSQPx/pG8zKB5LXyLEHzSPcyLjQFnm\n" + + "T4Qfk/Js7jNnWyPssEpJ2gvTrYD5oRdWFTmndEZBDs9dPEQ9Ezggp40763D61w9z\n" + + "pue4kqTPW1Vxdjh6CA/Hb7VHBT/hbdAT1fI7WCgBAoGAZq1rFESL3roi8DtOWl51\n" + + "nduNO20Yloe6tlhUAKo63krRHKBeKTyLXycpZHcq6UEfys3dixFfu0lN6002lUku\n" + + "MTbmNOJWhOCa2xuZY0CeINKFnKBnbiauBpo6x+2J0PoWFn8wd1tzFJPbodk8Km1f\n" + + "qySov+6mrQxHojQYBu9/yYQ=\n" + "-----END PRIVATE KEY-----"; String cipher = "0100B57FF39AFFF23E48534DBFE3E61C6275BCB1850EEE80D08415F43717FE17F64762455BF38DC5F8E5AED021E1D5BB8AD330200EAEEB85252A29A5E14B95053F5C6B8C2FED1F3B0C5AA1C6ABA1F8E6CCCE8DB1E9001A5E7BCBE56326BBCFBF68B83A35CD3A057B491EC8B04CEEC1D3D01C0CD71C743C88FA05CFE0B12C22887D1D1D69E3572AD5129EE5CF6484BAF2739CD0A9FE8D5A5C38696AFD008E70E26EF386C4E20C7D51F6A2D226E80E96D63EF612C5EC4F4B7B130BC17A10518CA2D161B145ED21D37F8442CCEFE20400E296893C09E4F24E95AD4C9394175EA189DE227C59D0512D15F7E4FEBA95B7807CD238D54536E579298336F6FB285A7E2874AB6914BF4FF089BFD98EC18D9E8B3D7FB2F5CFC20715C62D34F08E36D84F2CDABA2D1A1798C95161B7831167ED27E8894F1EB25D4E74DF382BF276D9ACBEADB56795F3DF8A4E6CE9DF7B6CFEFD5C66F0BC45D24CCC8E8095A7BF5CE69FEC5579B874A4C9B7C8F13126EC59D7C6DF0404816F638C7D4A84FE038E6F00B5667AC88E4307990E4C06B3864D86B7349275B20A3FB50FBA64706F214CC642219DCEF4453C30B89790F6FB1566A5D557AD7EC5890CA50E80111319F9742943FBD675D18753E5ABD21941832A11332ED902C334309E3770512AC042E1556C3F0ECCFC056C66D7362BA4E7896EA0807412817C68D7B5434AFA0D95A12B950573994F081F996545B871E485C392288E2D61C3B0CBB9FC4E68C1C558A598B03BACFF27967BE8AEA8F1322EC3E0957A3ED84810164A59BDEE2D1514EA68228CB96B59D8BA1E9234A24D57E5F8D7E55724EF0AE9D83F6E2A84B9A1E47B59091201B1B65542BBBB5A988CBBD5395335C4DF821ACEF289D20444B74CABC406A7C4F810EFF85838994DBDD38EDF74D4821153A5128AB98C15409C73891415B194803B3ABF761CEE57D1F58813A7125260E58864970CA2650E0D46C239ED92FCC3491C5FA372838B475D14E4946FCC3C421A76C434C5310D1A17A744551CFB5F99547BB216AD7C1ADA5C27CA64B34C29152D29B0A4B90B0C72A7A18BD19CF278B6F39186A39F91FB4D";