@@ -21,11 +21,11 @@ public class RSACryptoFunction implements AsymmetricEncryptionFunction, Signatur | |||
private static final CryptoAlgorithm RSA = ClassicAlgorithm.RSA; | |||
// modulus.length = 256, publicExponent.length = 1 | |||
private static final int PUBKEY_SIZE = 257; | |||
// modulus.length = 256, publicExponent.length = 1, privateExponent.length = 256, p.length = 128, q.length =128, | |||
// modulus.length = 256, publicExponent.length = 3 | |||
private static final int PUBKEY_SIZE = 259; | |||
// modulus.length = 256, publicExponent.length = 3, privateExponent.length = 256, p.length = 128, q.length =128, | |||
// dP.length = 128, dQ.length = 128, qInv.length = 128 | |||
private static final int PRIVKEY_SIZE = 1153; | |||
private static final int PRIVKEY_SIZE = 1155; | |||
private static final int SIGNATUREDIGEST_SIZE = 256; | |||
private static final int CIPHERTEXTBLOCK_SIZE = 256; | |||
@@ -308,14 +308,14 @@ public class RSAUtils { | |||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pubKeyBytes); | |||
KeyFactory keyFactory = null; | |||
KeyFactory keyFactory; | |||
try { | |||
keyFactory = KeyFactory.getInstance("RSA"); | |||
} catch (NoSuchAlgorithmException e) { | |||
throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e); | |||
} | |||
RSAPublicKey publicKey = null; | |||
RSAPublicKey publicKey; | |||
try { | |||
publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec); | |||
} catch (InvalidKeySpecException e) { | |||
@@ -451,7 +451,7 @@ public class RSAUtils { | |||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyBytes); | |||
KeyFactory keyFactory = null; | |||
KeyFactory keyFactory; | |||
try { | |||
keyFactory = KeyFactory.getInstance("RSA"); | |||
} catch (NoSuchAlgorithmException e) { | |||
@@ -55,15 +55,15 @@ public class RSACryptoFunctionTest { | |||
PrivKey privKey = keyPair.getPrivKey(); | |||
assertEquals(PUBLIC.CODE, pubKey.getKeyType().CODE); | |||
assertEquals(257, pubKey.getRawKeyBytes().length); | |||
assertEquals(259, pubKey.getRawKeyBytes().length); | |||
assertEquals(PRIVATE.CODE, privKey.getKeyType().CODE); | |||
assertEquals(1153, privKey.getRawKeyBytes().length); | |||
assertEquals(1155, privKey.getRawKeyBytes().length); | |||
assertEquals(algorithm.code(), pubKey.getAlgorithm()); | |||
assertEquals(algorithm.code(), privKey.getAlgorithm()); | |||
assertEquals(2 + 1 + 257, pubKey.toBytes().length); | |||
assertEquals(2 + 1 + 1153, privKey.toBytes().length); | |||
assertEquals(2 + 1 + 259, pubKey.toBytes().length); | |||
assertEquals(2 + 1 + 1155, privKey.toBytes().length); | |||
byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); | |||
byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE }; | |||
@@ -243,7 +243,7 @@ public class RSACryptoFunctionTest { | |||
PrivKey resolvedPrivKey = signatureFunction.resolvePrivKey(privKeyBytes); | |||
assertEquals(PRIVATE.CODE, resolvedPrivKey.getKeyType().CODE); | |||
assertEquals(1153, resolvedPrivKey.getRawKeyBytes().length); | |||
assertEquals(1155, resolvedPrivKey.getRawKeyBytes().length); | |||
assertEquals(ClassicAlgorithm.RSA.code(), resolvedPrivKey.getAlgorithm()); | |||
assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)), | |||
resolvedPrivKey.getAlgorithm()); | |||
@@ -308,7 +308,7 @@ public class RSACryptoFunctionTest { | |||
PubKey resolvedPubKey = signatureFunction.resolvePubKey(pubKeyBytes); | |||
assertEquals(PUBLIC.CODE, resolvedPubKey.getKeyType().CODE); | |||
assertEquals(257, resolvedPubKey.getRawKeyBytes().length); | |||
assertEquals(259, resolvedPubKey.getRawKeyBytes().length); | |||
assertEquals(ClassicAlgorithm.RSA.code(), resolvedPubKey.getAlgorithm()); | |||
assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)), | |||
resolvedPubKey.getAlgorithm()); | |||
@@ -0,0 +1,26 @@ | |||
package com.jd.blockchain.crypto.service.pki; | |||
import com.jd.blockchain.crypto.CryptoAlgorithm; | |||
import com.jd.blockchain.crypto.CryptoAlgorithmDefinition; | |||
/** | |||
* @author zhanglin33 | |||
* @title: PKIAlgorithm | |||
* @description: TODO | |||
* @date 2019-05-15, 16:34 | |||
*/ | |||
public class PKIAlgorithm { | |||
public static final CryptoAlgorithm SHA1WITHRSA2048 = CryptoAlgorithmDefinition.defineSignature("SHA1WITHRSA2048", | |||
false, (byte) 31); | |||
public static final CryptoAlgorithm SHA1WITHRSA4096 = CryptoAlgorithmDefinition.defineSignature("SHA1WITHRSA4096", | |||
false, (byte) 32); | |||
public static final CryptoAlgorithm SM3WITHSM2 = CryptoAlgorithmDefinition.defineSignature("SM3WITHSM2", | |||
false, (byte) 33); | |||
private PKIAlgorithm() { | |||
} | |||
} |
@@ -0,0 +1,36 @@ | |||
package com.jd.blockchain.crypto.service.pki; | |||
import com.jd.blockchain.crypto.CryptoFunction; | |||
import com.jd.blockchain.crypto.CryptoService; | |||
import java.util.Arrays; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.List; | |||
/** | |||
* @author zhanglin33 | |||
* @title: PKICryptoService | |||
* @description: TODO | |||
* @date 2019-05-15, 16:35 | |||
*/ | |||
public class PKICryptoService implements CryptoService { | |||
public static final SHA1WITHRSA2048SignatureFunction SHA1WITHRSA2048 = new SHA1WITHRSA2048SignatureFunction(); | |||
public static final SHA1WITHRSA4096SignatureFunction SHA1WITHRSA4096 = new SHA1WITHRSA4096SignatureFunction(); | |||
public static final SM3WITHSM2SignatureFunction SM3WITHSM2 = new SM3WITHSM2SignatureFunction(); | |||
private static final Collection<CryptoFunction> FUNCTIONS; | |||
static { | |||
List<CryptoFunction> funcs = Arrays.asList(SHA1WITHRSA2048, SHA1WITHRSA4096, SM3WITHSM2); | |||
FUNCTIONS = Collections.unmodifiableList(funcs); | |||
} | |||
@Override | |||
public Collection<CryptoFunction> getFunctions() { | |||
return FUNCTIONS; | |||
} | |||
} |
@@ -0,0 +1,206 @@ | |||
package com.jd.blockchain.crypto.service.pki; | |||
import com.jd.blockchain.crypto.*; | |||
import org.bouncycastle.asn1.DERNull; | |||
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; | |||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier; | |||
import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey; | |||
import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; | |||
import org.bouncycastle.jce.provider.BouncyCastleProvider; | |||
import sun.security.rsa.RSAPrivateCrtKeyImpl; | |||
import sun.security.rsa.RSAPrivateKeyImpl; | |||
import sun.security.rsa.RSAPublicKeyImpl; | |||
import java.math.BigInteger; | |||
import java.security.*; | |||
import java.security.interfaces.RSAPrivateCrtKey; | |||
import java.security.interfaces.RSAPrivateKey; | |||
import java.security.interfaces.RSAPublicKey; | |||
import static com.jd.blockchain.crypto.BaseCryptoKey.KEY_TYPE_BYTES; | |||
import static com.jd.blockchain.crypto.CryptoBytes.ALGORYTHM_CODE_SIZE; | |||
import static com.jd.blockchain.crypto.CryptoKeyType.PRIVATE; | |||
import static com.jd.blockchain.crypto.CryptoKeyType.PUBLIC; | |||
import static com.jd.blockchain.crypto.service.pki.PKIAlgorithm.SHA1WITHRSA2048; | |||
/** | |||
* @author zhanglin33 | |||
* @title: SHA1WITHRSA2048SignatureFunction | |||
* @description: TODO | |||
* @date 2019-05-15, 16:37 | |||
*/ | |||
public class SHA1WITHRSA2048SignatureFunction implements SignatureFunction { | |||
private static final int RAW_PUBKEY_SIZE = 259; | |||
private static final int RAW_PRIVKEY_SIZE = 1155; | |||
private static final int RAW_SIGNATUREDIGEST_SIZE = 256; | |||
private static final AlgorithmIdentifier RSA_ALGORITHM_IDENTIFIER = | |||
new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE); | |||
@Override | |||
public SignatureDigest sign(PrivKey privKey, byte[] data) { | |||
byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||
if (rawPrivKeyBytes.length < RAW_PRIVKEY_SIZE) { | |||
throw new CryptoException("This key has wrong format!"); | |||
} | |||
if (privKey.getAlgorithm() != SHA1WITHRSA2048.code()) { | |||
throw new CryptoException("This key is not SHA1WITHRSA2048 private key!"); | |||
} | |||
RSAPrivateCrtKey rawPrivKey; | |||
Signature signer; | |||
byte[] signature; | |||
try { | |||
rawPrivKey = (RSAPrivateCrtKey) RSAPrivateCrtKeyImpl.newKey(rawPrivKeyBytes); | |||
signer = Signature.getInstance("SHA1withRSA"); | |||
signer.initSign(rawPrivKey); | |||
signer.update(data); | |||
signature = signer.sign(); | |||
} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { | |||
throw new CryptoException(e.getMessage(), e); | |||
} | |||
return new SignatureDigest(SHA1WITHRSA2048, signature); | |||
} | |||
@Override | |||
public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) { | |||
byte[] rawPubKeyBytes = pubKey.getRawKeyBytes(); | |||
byte[] rawDigestBytes = digest.getRawDigest(); | |||
if (rawPubKeyBytes.length < RAW_PUBKEY_SIZE) { | |||
throw new CryptoException("This key has wrong format!"); | |||
} | |||
if (pubKey.getAlgorithm() != SHA1WITHRSA2048.code()) { | |||
throw new CryptoException("This key is not SHA1WITHRSA2048 public key!"); | |||
} | |||
if (digest.getAlgorithm() != SHA1WITHRSA2048.code() || rawDigestBytes.length != RAW_SIGNATUREDIGEST_SIZE) { | |||
throw new CryptoException("This is not SHA1WITHRSA2048 signature digest!"); | |||
} | |||
RSAPublicKeyImpl rawPubKey; | |||
Signature verifier; | |||
boolean isValid = false; | |||
try { | |||
rawPubKey = new RSAPublicKeyImpl(rawPubKeyBytes); | |||
verifier = Signature.getInstance("SHA1withRSA"); | |||
verifier.initVerify(rawPubKey); | |||
verifier.update(data); | |||
isValid = verifier.verify(rawDigestBytes); | |||
} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { | |||
e.printStackTrace(); | |||
} | |||
return isValid; | |||
} | |||
@Override | |||
public boolean supportPubKey(byte[] pubKeyBytes) { | |||
return pubKeyBytes.length > (ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + RAW_PUBKEY_SIZE) | |||
&& CryptoAlgorithm.match(SHA1WITHRSA2048, pubKeyBytes) | |||
&& pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE; | |||
} | |||
@Override | |||
public PubKey resolvePubKey(byte[] pubKeyBytes) { | |||
if (supportPubKey(pubKeyBytes)) { | |||
return new PubKey(pubKeyBytes); | |||
} else { | |||
throw new CryptoException("pubKeyBytes are invalid!"); | |||
} | |||
} | |||
@Override | |||
public boolean supportPrivKey(byte[] privKeyBytes) { | |||
return privKeyBytes.length > (ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + RAW_PRIVKEY_SIZE) | |||
&& CryptoAlgorithm.match(SHA1WITHRSA2048, privKeyBytes) | |||
&& privKeyBytes[ALGORYTHM_CODE_SIZE] == PRIVATE.CODE; | |||
} | |||
@Override | |||
public PrivKey resolvePrivKey(byte[] privKeyBytes) { | |||
if (supportPrivKey(privKeyBytes)) { | |||
return new PrivKey(privKeyBytes); | |||
} else { | |||
throw new CryptoException("privKeyBytes are invalid!"); | |||
} | |||
} | |||
@Override | |||
public PubKey retrievePubKey(PrivKey privKey) { | |||
byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||
if (rawPrivKeyBytes.length < RAW_PRIVKEY_SIZE) { | |||
throw new CryptoException("This key has wrong format!"); | |||
} | |||
if (privKey.getAlgorithm() != SHA1WITHRSA2048.code()) { | |||
throw new CryptoException("This key is not SHA1WITHRSA2048 private key!"); | |||
} | |||
byte[] rawPubKeyBytes; | |||
try { | |||
RSAPrivateCrtKey rawPrivKey = (RSAPrivateCrtKey) RSAPrivateCrtKeyImpl.newKey(rawPrivKeyBytes); | |||
BigInteger modulus = rawPrivKey.getModulus(); | |||
BigInteger exponent = rawPrivKey.getPublicExponent(); | |||
rawPubKeyBytes = KeyUtil.getEncodedSubjectPublicKeyInfo(RSA_ALGORITHM_IDENTIFIER, | |||
new org.bouncycastle.asn1.pkcs.RSAPublicKey(modulus, exponent)); | |||
} catch (InvalidKeyException e) { | |||
throw new CryptoException(e.getMessage(), e); | |||
} | |||
return new PubKey(SHA1WITHRSA2048, rawPubKeyBytes); | |||
} | |||
@Override | |||
public boolean supportDigest(byte[] digestBytes) { | |||
return digestBytes.length == (RAW_SIGNATUREDIGEST_SIZE + ALGORYTHM_CODE_SIZE) | |||
&& CryptoAlgorithm.match(SHA1WITHRSA2048, digestBytes); | |||
} | |||
@Override | |||
public SignatureDigest resolveDigest(byte[] digestBytes) { | |||
if (supportDigest(digestBytes)) { | |||
return new SignatureDigest(digestBytes); | |||
} else { | |||
throw new CryptoException("digestBytes are invalid!"); | |||
} | |||
} | |||
@Override | |||
public AsymmetricKeypair generateKeypair() { | |||
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); | |||
KeyPairGenerator generator; | |||
PublicKey pubKey; | |||
PrivateKey privKey; | |||
try { | |||
generator = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME); | |||
generator.initialize(2048); | |||
KeyPair keyPair = generator.generateKeyPair(); | |||
pubKey = keyPair.getPublic(); | |||
privKey = keyPair.getPrivate(); | |||
} catch (NoSuchAlgorithmException | NoSuchProviderException e) { | |||
throw new CryptoException(e.getMessage(), e); | |||
} | |||
byte[] pubKeyBytes = pubKey.getEncoded(); | |||
byte[] privKeyBytes = privKey.getEncoded(); | |||
return new AsymmetricKeypair(new PubKey(SHA1WITHRSA2048, pubKeyBytes), | |||
new PrivKey(SHA1WITHRSA2048, privKeyBytes)); | |||
} | |||
@Override | |||
public CryptoAlgorithm getAlgorithm() { | |||
return SHA1WITHRSA2048; | |||
} | |||
} |
@@ -0,0 +1,68 @@ | |||
package com.jd.blockchain.crypto.service.pki; | |||
import com.jd.blockchain.crypto.*; | |||
import static com.jd.blockchain.crypto.service.pki.PKIAlgorithm.SHA1WITHRSA4096; | |||
/** | |||
* @author zhanglin33 | |||
* @title: SHA1WITHRSA4096SignatureFunction | |||
* @description: TODO | |||
* @date 2019-05-15, 17:13 | |||
*/ | |||
public class SHA1WITHRSA4096SignatureFunction implements SignatureFunction { | |||
@Override | |||
public SignatureDigest sign(PrivKey privKey, byte[] data) { | |||
return null; | |||
} | |||
@Override | |||
public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) { | |||
return false; | |||
} | |||
@Override | |||
public PubKey retrievePubKey(PrivKey privKey) { | |||
return null; | |||
} | |||
@Override | |||
public boolean supportPrivKey(byte[] privKeyBytes) { | |||
return false; | |||
} | |||
@Override | |||
public PrivKey resolvePrivKey(byte[] privKeyBytes) { | |||
return null; | |||
} | |||
@Override | |||
public boolean supportPubKey(byte[] pubKeyBytes) { | |||
return false; | |||
} | |||
@Override | |||
public PubKey resolvePubKey(byte[] pubKeyBytes) { | |||
return null; | |||
} | |||
@Override | |||
public boolean supportDigest(byte[] digestBytes) { | |||
return false; | |||
} | |||
@Override | |||
public SignatureDigest resolveDigest(byte[] digestBytes) { | |||
return null; | |||
} | |||
@Override | |||
public AsymmetricKeypair generateKeypair() { | |||
return null; | |||
} | |||
@Override | |||
public CryptoAlgorithm getAlgorithm() { | |||
return SHA1WITHRSA4096; | |||
} | |||
} |
@@ -0,0 +1,68 @@ | |||
package com.jd.blockchain.crypto.service.pki; | |||
import com.jd.blockchain.crypto.*; | |||
import static com.jd.blockchain.crypto.service.pki.PKIAlgorithm.SM3WITHSM2; | |||
/** | |||
* @author zhanglin33 | |||
* @title: SM3WITHSM2SignatureFunction | |||
* @description: TODO | |||
* @date 2019-05-15, 16:39 | |||
*/ | |||
public class SM3WITHSM2SignatureFunction implements SignatureFunction { | |||
@Override | |||
public SignatureDigest sign(PrivKey privKey, byte[] data) { | |||
return null; | |||
} | |||
@Override | |||
public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) { | |||
return false; | |||
} | |||
@Override | |||
public PubKey retrievePubKey(PrivKey privKey) { | |||
return null; | |||
} | |||
@Override | |||
public boolean supportPrivKey(byte[] privKeyBytes) { | |||
return false; | |||
} | |||
@Override | |||
public PrivKey resolvePrivKey(byte[] privKeyBytes) { | |||
return null; | |||
} | |||
@Override | |||
public boolean supportPubKey(byte[] pubKeyBytes) { | |||
return false; | |||
} | |||
@Override | |||
public PubKey resolvePubKey(byte[] pubKeyBytes) { | |||
return null; | |||
} | |||
@Override | |||
public boolean supportDigest(byte[] digestBytes) { | |||
return false; | |||
} | |||
@Override | |||
public SignatureDigest resolveDigest(byte[] digestBytes) { | |||
return null; | |||
} | |||
@Override | |||
public AsymmetricKeypair generateKeypair() { | |||
return null; | |||
} | |||
@Override | |||
public CryptoAlgorithm getAlgorithm() { | |||
return SM3WITHSM2; | |||
} | |||
} |
@@ -1,5 +1,6 @@ | |||
package com.jd.blockchain.crypto; | |||
package com.jd.blockchain.crypto.utils; | |||
import com.jd.blockchain.crypto.CryptoException; | |||
import org.bouncycastle.asn1.x500.X500Name; | |||
import org.bouncycastle.asn1.x500.X500NameBuilder; | |||
import org.bouncycastle.asn1.x500.style.BCStrictStyle; |
@@ -1,5 +1,6 @@ | |||
package com.jd.blockchain.crypto; | |||
package com.jd.blockchain.crypto.utils; | |||
import com.jd.blockchain.crypto.CryptoException; | |||
import org.bouncycastle.jce.provider.BouncyCastleProvider; | |||
import org.bouncycastle.util.encoders.Base64; | |||
import org.bouncycastle.util.io.pem.PemReader; | |||
@@ -15,7 +16,7 @@ import java.util.Date; | |||
/** | |||
* @author zhanglin33 | |||
* @title: CertParser | |||
* @description: TODO | |||
* @description: A parser for standard certificate, along with validation process | |||
* @date 2019-05-10, 15:17 | |||
*/ | |||
public class CertParser { |
@@ -0,0 +1 @@ | |||
com.jd.blockchain.crypto.service.pki.PKICryptoService |
@@ -1,5 +1,6 @@ | |||
package com.jd.blockchain.crypto; | |||
package com.jd.blockchain.crypto.utils; | |||
import com.jd.blockchain.crypto.utils.CSRBuilder; | |||
import org.bouncycastle.asn1.ASN1Encoding; | |||
import org.bouncycastle.asn1.DERSet; | |||
import org.bouncycastle.asn1.pkcs.CertificationRequestInfo; |
@@ -1,5 +1,6 @@ | |||
package com.jd.blockchain.crypto; | |||
package com.jd.blockchain.crypto.utils; | |||
import com.jd.blockchain.crypto.utils.CertParser; | |||
import org.junit.Test; | |||
import static org.junit.Assert.assertEquals; |