diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ClassicCryptoService.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ClassicCryptoService.java index 164f966c..e47edd21 100644 --- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ClassicCryptoService.java +++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ClassicCryptoService.java @@ -23,13 +23,14 @@ public class ClassicCryptoService implements CryptoService { public static final JVMSecureRandomFunction JVM_SECURE_RANDOM = new JVMSecureRandomFunction(); - // public static final ECDSASignatureFunction ECDSA = new - // ECDSASignatureFunction(); + public static final ECDSASignatureFunction ECDSA = new ECDSASignatureFunction(); + + public static final RSACryptoFunction RSA = new RSACryptoFunction(); private static final Collection FUNCTIONS; static { - List funcs = Arrays.asList(AES, ED25519, RIPEMD160, SHA256, JVM_SECURE_RANDOM); + List funcs = Arrays.asList(AES, ED25519, ECDSA, RSA, RIPEMD160, SHA256, JVM_SECURE_RANDOM); FUNCTIONS = Collections.unmodifiableList(funcs); } diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ECDSASignatureFunction.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ECDSASignatureFunction.java index 478c7733..d7ebe0b7 100644 --- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ECDSASignatureFunction.java +++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ECDSASignatureFunction.java @@ -1,60 +1,129 @@ package com.jd.blockchain.crypto.service.classic; -import com.jd.blockchain.crypto.CryptoAlgorithm; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.PrivKey; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.crypto.SignatureDigest; -import com.jd.blockchain.crypto.SignatureFunction; +import com.jd.blockchain.crypto.*; +import com.jd.blockchain.crypto.utils.classic.ECDSAUtils; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; + +import java.math.BigInteger; + +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; public class ECDSASignatureFunction implements SignatureFunction { + private static final CryptoAlgorithm ECDSA = ClassicAlgorithm.ECDSA; + + private static final int PUBKEY_SIZE = 65; + private static final int PRIVKEY_SIZE = 32; + private static final int SIGNATUREDIGEST_SIZE = 64; + + private static final int PUBKEY_LENGTH = ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + PUBKEY_SIZE; + private static final int PRIVKEY_LENGTH = ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + PRIVKEY_SIZE; + private static final int SIGNATUREDIGEST_LENGTH = ALGORYTHM_CODE_SIZE + SIGNATUREDIGEST_SIZE; + ECDSASignatureFunction() { } @Override public SignatureDigest sign(PrivKey privKey, byte[] data) { - return null; + + byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); + + // 验证原始私钥长度为256比特,即32字节 + if (rawPrivKeyBytes.length != PRIVKEY_SIZE) { + throw new CryptoException("This key has wrong format!"); + } + + // 验证密钥数据的算法标识对应ECDSA签名算法 + if (privKey.getAlgorithm() != ECDSA.code()) { + throw new CryptoException("This key is not ECDSA private key!"); + } + + // 调用ECDSA签名算法计算签名结果 + return new SignatureDigest(ECDSA, ECDSAUtils.sign(data, rawPrivKeyBytes)); } @Override public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) { - return false; + + byte[] rawPubKeyBytes = pubKey.getRawKeyBytes(); + byte[] rawDigestBytes = digest.getRawDigest(); + + // 验证原始公钥长度为256比特,即32字节 + if (rawPubKeyBytes.length != PUBKEY_SIZE) { + throw new CryptoException("This key has wrong format!"); + } + + // 验证密钥数据的算法标识对应ECDSA签名算法 + if (pubKey.getAlgorithm() != ECDSA.code()) { + throw new CryptoException("This key is not ECDSA public key!"); + } + + // 验证签名数据的算法标识对应ECDSA签名算法,并且原始摘要长度为64字节 + if (digest.getAlgorithm() != ECDSA.code() || rawDigestBytes.length != SIGNATUREDIGEST_SIZE) { + throw new CryptoException("This is not ECDSA signature digest!"); + } + + // 调用ECDSA验签算法验证签名结果 + return ECDSAUtils.verify(data, rawPubKeyBytes, rawDigestBytes); } @Override public PubKey retrievePubKey(PrivKey privKey) { - return null; + byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); + byte[] rawPubKeyBytes = ECDSAUtils.retrievePublicKey(rawPrivKeyBytes); + return new PubKey(ECDSA, rawPubKeyBytes); } @Override public boolean supportPrivKey(byte[] privKeyBytes) { - return false; + // 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应ECDSA签名算法,并且密钥类型是私钥 + return privKeyBytes.length == PRIVKEY_LENGTH && CryptoAlgorithm.match(ECDSA, privKeyBytes) + && privKeyBytes[ALGORYTHM_CODE_SIZE] == PRIVATE.CODE; } @Override public PrivKey resolvePrivKey(byte[] privKeyBytes) { - return null; + if (supportPrivKey(privKeyBytes)) { + return new PrivKey(privKeyBytes); + } else { + throw new CryptoException("privKeyBytes are invalid!"); + } } @Override public boolean supportPubKey(byte[] pubKeyBytes) { - return false; + // 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应ECDSA签名算法,并且密钥类型是公钥 + return pubKeyBytes.length == PUBKEY_LENGTH && CryptoAlgorithm.match(ECDSA, pubKeyBytes) + && pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE; } @Override public PubKey resolvePubKey(byte[] pubKeyBytes) { - return null; + if (supportPubKey(pubKeyBytes)) { + return new PubKey(pubKeyBytes); + } else { + throw new CryptoException("pubKeyBytes are invalid!"); + } } @Override public boolean supportDigest(byte[] digestBytes) { - return false; + // 验证输入字节数组长度=算法标识长度+摘要长度,字节数组的算法标识对应ECDSA算法 + return digestBytes.length == SIGNATUREDIGEST_LENGTH && CryptoAlgorithm.match(ECDSA, digestBytes); } @Override public SignatureDigest resolveDigest(byte[] digestBytes) { - return null; + if (supportDigest(digestBytes)) { + return new SignatureDigest(digestBytes); + } else { + throw new CryptoException("digestBytes are invalid!"); + } } @Override @@ -64,6 +133,28 @@ public class ECDSASignatureFunction implements SignatureFunction { @Override public AsymmetricKeypair generateKeypair() { - return null; + + // 调用ECDSA算法的密钥生成算法生成公私钥对priKey和pubKey,返回密钥对 + AsymmetricCipherKeyPair keyPair = ECDSAUtils.generateKeyPair(); + ECPrivateKeyParameters privKeyParams = (ECPrivateKeyParameters) keyPair.getPrivate(); + ECPublicKeyParameters pubKeyParams = (ECPublicKeyParameters) keyPair.getPublic(); + + byte[] privKeyBytes = BigIntegerTo32Bytes(privKeyParams.getD()); + byte[] pubKeyBytes = pubKeyParams.getQ().getEncoded(false); + + return new AsymmetricKeypair(new PubKey(ECDSA, pubKeyBytes), new PrivKey(ECDSA, privKeyBytes)); + } + + // To convert BigInteger to byte[] whose length is 32 + private static byte[] BigIntegerTo32Bytes(BigInteger b){ + byte[] tmp = b.toByteArray(); + byte[] result = new byte[32]; + if (tmp.length > result.length) { + System.arraycopy(tmp, tmp.length - result.length, result, 0, result.length); + } + else { + System.arraycopy(tmp,0,result,result.length-tmp.length,tmp.length); + } + return result; } } diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ED25519SignatureFunction.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ED25519SignatureFunction.java index e08dbe24..555586b5 100644 --- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ED25519SignatureFunction.java +++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ED25519SignatureFunction.java @@ -50,7 +50,6 @@ public class ED25519SignatureFunction implements SignatureFunction { // 调用ED25519签名算法计算签名结果 return new SignatureDigest(ED25519, ED25519Utils.sign(data, rawPrivKeyBytes)); - } @Override @@ -69,7 +68,7 @@ public class ED25519SignatureFunction implements SignatureFunction { throw new CryptoException("This key is not ED25519 public key!"); } - // 验证密文数据的算法标识对应ED25519签名算法,并且原始摘要长度为64字节 + // 验证签名数据的算法标识对应ED25519签名算法,并且原始摘要长度为64字节 if (digest.getAlgorithm() != ED25519.code() || rawDigestBytes.length != SIGNATUREDIGEST_SIZE) { throw new CryptoException("This is not ED25519 signature digest!"); } @@ -106,7 +105,6 @@ public class ED25519SignatureFunction implements SignatureFunction { // 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应ED25519签名算法,并且密钥类型是公钥 return pubKeyBytes.length == PUBKEY_LENGTH && CryptoAlgorithm.match(ED25519, pubKeyBytes) && pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE; - } @Override @@ -140,6 +138,7 @@ public class ED25519SignatureFunction implements SignatureFunction { @Override public AsymmetricKeypair generateKeypair() { + // 调用ED25519算法的密钥生成算法生成公私钥对priKey和pubKey,返回密钥对 AsymmetricCipherKeyPair keyPair = ED25519Utils.generateKeyPair(); Ed25519PrivateKeyParameters privKeyParams = (Ed25519PrivateKeyParameters) keyPair.getPrivate(); @@ -148,6 +147,5 @@ public class ED25519SignatureFunction implements SignatureFunction { byte[] privKeyBytes = privKeyParams.getEncoded(); byte[] pubKeyBytes = pubKeyParams.getEncoded(); return new AsymmetricKeypair(new PubKey(ED25519, pubKeyBytes), new PrivKey(ED25519, privKeyBytes)); - } } diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RSACryptoFunction.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RSACryptoFunction.java index e37c6d35..b7bd9c8d 100644 --- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RSACryptoFunction.java +++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RSACryptoFunction.java @@ -1,14 +1,15 @@ package com.jd.blockchain.crypto.service.classic; -import com.jd.blockchain.crypto.AsymmetricCiphertext; -import com.jd.blockchain.crypto.AsymmetricEncryptionFunction; -import com.jd.blockchain.crypto.Ciphertext; -import com.jd.blockchain.crypto.CryptoAlgorithm; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.PrivKey; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.crypto.SignatureDigest; -import com.jd.blockchain.crypto.SignatureFunction; +import com.jd.blockchain.crypto.*; +import com.jd.blockchain.crypto.utils.classic.RSAUtils; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; + +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; /** * @author zhanglin33 @@ -17,78 +18,195 @@ import com.jd.blockchain.crypto.SignatureFunction; * @date 2019-03-25, 17:28 */ public class RSACryptoFunction implements AsymmetricEncryptionFunction, SignatureFunction { + + 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, + // dP.length = 128, dQ.length = 128, qInv.length = 128 + private static final int PRIVKEY_SIZE = 1153; + + private static final int SIGNATUREDIGEST_SIZE = 256; + private static final int CIPHERTEXTBLOCK_SIZE = 256; + + private static final int PUBKEY_LENGTH = ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + PUBKEY_SIZE; + private static final int PRIVKEY_LENGTH = ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + PRIVKEY_SIZE; + private static final int SIGNATUREDIGEST_LENGTH = ALGORYTHM_CODE_SIZE + SIGNATUREDIGEST_SIZE; @Override public Ciphertext encrypt(PubKey pubKey, byte[] data) { - return null; + + byte[] rawPubKeyBytes = pubKey.getRawKeyBytes(); + + // 验证原始公钥长度为257字节 + if (rawPubKeyBytes.length != PUBKEY_SIZE) { + throw new CryptoException("This key has wrong format!"); + } + + // 验证密钥数据的算法标识对应RSA算法 + if (pubKey.getAlgorithm() != RSA.code()) { + throw new CryptoException("The is not RSA public key!"); + } + + // 调用RSA加密算法计算密文 + return new AsymmetricCiphertext(RSA, RSAUtils.encrypt(data, rawPubKeyBytes)); } @Override public byte[] decrypt(PrivKey privKey, Ciphertext ciphertext) { - return new byte[0]; + + byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); + byte[] rawCiphertextBytes = ciphertext.getRawCiphertext(); + + // 验证原始私钥长度为1153字节 + if (rawPrivKeyBytes.length != PRIVKEY_SIZE) { + throw new CryptoException("This key has wrong format!"); + } + + // 验证密钥数据的算法标识对应RSA算法 + if (privKey.getAlgorithm() != RSA.code()) { + throw new CryptoException("This key is not RSA private key!"); + } + + // 验证密文数据的算法标识对应RSA算法,并且密文是分组长度的整数倍 + if (ciphertext.getAlgorithm() != RSA.code() + || rawCiphertextBytes.length % CIPHERTEXTBLOCK_SIZE != 0) { + throw new CryptoException("This is not RSA ciphertext!"); + } + + // 调用RSA解密算法得到明文结果 + return RSAUtils.decrypt(rawCiphertextBytes, rawPrivKeyBytes); } @Override public PubKey retrievePubKey(PrivKey privKey) { - return null; + byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); + byte[] rawPubKeyBytes = RSAUtils.retrievePublicKey(rawPrivKeyBytes); + return new PubKey(RSA, rawPubKeyBytes); } @Override public SignatureDigest sign(PrivKey privKey, byte[] data) { - return null; + + byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); + + // 验证原始私钥长度为1153字节 + if (rawPrivKeyBytes.length != PRIVKEY_SIZE) { + throw new CryptoException("This key has wrong format!"); + } + + // 验证密钥数据的算法标识对应RSA签名算法 + if (privKey.getAlgorithm() != RSA.code()) { + throw new CryptoException("This key is not RSA private key!"); + } + + // 调用RSA签名算法计算签名结果 + return new SignatureDigest(RSA, RSAUtils.sign(data, rawPrivKeyBytes)); } @Override public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) { - return false; + + byte[] rawPubKeyBytes = pubKey.getRawKeyBytes(); + byte[] rawDigestBytes = digest.getRawDigest(); + + // 验证原始公钥长度为257字节 + if (rawPubKeyBytes.length != PUBKEY_SIZE) { + throw new CryptoException("This key has wrong format!"); + } + + // 验证密钥数据的算法标识对应RSA签名算法 + if (pubKey.getAlgorithm() != RSA.code()) { + throw new CryptoException("This key is not RSA public key!"); + } + + // 验证签名数据的算法标识对应RSA签名算法,并且原始签名长度为256字节 + if (digest.getAlgorithm() != RSA.code() || rawDigestBytes.length != SIGNATUREDIGEST_SIZE) { + throw new CryptoException("This is not RSA signature digest!"); + } + + // 调用RSA验签算法验证签名结果 + return RSAUtils.verify(data, rawPubKeyBytes, rawDigestBytes); } @Override public boolean supportPrivKey(byte[] privKeyBytes) { - return false; + // 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应RSA算法,并且密钥类型是私钥 + return privKeyBytes.length == PRIVKEY_LENGTH && CryptoAlgorithm.match(RSA, privKeyBytes) + && privKeyBytes[ALGORYTHM_CODE_SIZE] == PRIVATE.CODE; } @Override public PrivKey resolvePrivKey(byte[] privKeyBytes) { - return null; + if (supportPrivKey(privKeyBytes)) { + return new PrivKey(privKeyBytes); + } else { + throw new CryptoException("privKeyBytes are invalid!"); + } } @Override public boolean supportPubKey(byte[] pubKeyBytes) { - return false; + // 验证输入字节数组长度=算法标识长度+密钥类型长度+椭圆曲线点长度,密钥数据的算法标识对应RSA算法,并且密钥类型是公钥 + return pubKeyBytes.length == PUBKEY_LENGTH && CryptoAlgorithm.match(RSA, pubKeyBytes) + && pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE; } @Override public PubKey resolvePubKey(byte[] pubKeyBytes) { - return null; + if (supportPubKey(pubKeyBytes)) { + return new PubKey(pubKeyBytes); + } else { + throw new CryptoException("pubKeyBytes are invalid!"); + } } @Override public boolean supportDigest(byte[] digestBytes) { - return false; + // 验证输入字节数组长度=算法标识长度+签名长度,字节数组的算法标识对应RSA算法 + return digestBytes.length == SIGNATUREDIGEST_LENGTH && CryptoAlgorithm.match(RSA, digestBytes); } @Override public SignatureDigest resolveDigest(byte[] digestBytes) { - return null; + if (supportDigest(digestBytes)) { + return new SignatureDigest(digestBytes); + } else { + throw new CryptoException("digestBytes are invalid!"); + } } @Override public boolean supportCiphertext(byte[] ciphertextBytes) { - return false; + // 验证输入字节数组长度=密文分组的整数倍,字节数组的算法标识对应RSA算法 + return (ciphertextBytes.length % CIPHERTEXTBLOCK_SIZE == ALGORYTHM_CODE_SIZE) + && CryptoAlgorithm.match(RSA, ciphertextBytes); } @Override public AsymmetricCiphertext resolveCiphertext(byte[] ciphertextBytes) { - return null; + if (supportCiphertext(ciphertextBytes)) { + return new AsymmetricCiphertext(ciphertextBytes); + } else { + throw new CryptoException("ciphertextBytes are invalid!"); + } } @Override public CryptoAlgorithm getAlgorithm() { - return null; + return RSA; } @Override public AsymmetricKeypair generateKeypair() { - return null; + + AsymmetricCipherKeyPair keyPair = RSAUtils.generateKeyPair(); + RSAKeyParameters pubKey = (RSAKeyParameters) keyPair.getPublic(); + RSAPrivateCrtKeyParameters privKey = (RSAPrivateCrtKeyParameters) keyPair.getPrivate(); + + byte[] pubKeyBytes = RSAUtils.pubKey2Bytes_RawKey(pubKey); + byte[] privKeyBytes = RSAUtils.privKey2Bytes_RawKey(privKey); + + return new AsymmetricKeypair(new PubKey(RSA, pubKeyBytes), new PrivKey(RSA, privKeyBytes)); } } diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/AESUtils.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/AESUtils.java index 7620f1f7..e1b3eaf4 100644 --- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/AESUtils.java +++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/AESUtils.java @@ -1,10 +1,170 @@ package com.jd.blockchain.crypto.utils.classic; +import com.jd.blockchain.crypto.CryptoException; +import org.bouncycastle.crypto.CipherKeyGenerator; +import org.bouncycastle.crypto.KeyGenerationParameters; +import org.bouncycastle.crypto.engines.AESEngine; +import org.bouncycastle.crypto.modes.CBCBlockCipher; +import org.bouncycastle.crypto.paddings.PKCS7Padding; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.crypto.params.ParametersWithIV; + +import java.security.SecureRandom; +import java.util.Arrays; + /** * @author zhanglin33 * @title: AESUtils - * @description: AES/CBC/PKCS7Padding symmetric encryption algorithm + * @description: AES128/CBC/PKCS7Padding symmetric encryption algorithm * @date 2019-04-22, 09:37 */ public class AESUtils { + + // AES128 supports 128-bit(16 bytes) secret key + private static final int KEY_SIZE = 128 / 8; + // One block contains 16 bytes + private static final int BLOCK_SIZE = 16; + // Initial vector's size is 16 bytes + private static final int IV_SIZE = 16; + + /** + * key generation + * + * @return secret key + */ + public static byte[] generateKey(){ + + CipherKeyGenerator keyGenerator = new CipherKeyGenerator(); + + // To provide secure randomness and key length as input + // to prepare generate private key + keyGenerator.init(new KeyGenerationParameters(new SecureRandom(), KEY_SIZE * 8)); + + // To generate key + return keyGenerator.generateKey(); + } + + public static byte[] generateKey(byte[] seed){ + byte[] hash = SHA256Utils.hash(seed); + return Arrays.copyOf(hash, KEY_SIZE); + } + + + /** + * encryption + * + * @param plainBytes plaintext + * @param secretKey symmetric key + * @param iv initial vector + * @return ciphertext + */ + public static byte[] encrypt(byte[] plainBytes, byte[] secretKey, byte[] iv){ + + // To ensure that plaintext is not null + if (plainBytes == null) + { + throw new CryptoException("plaintext is null!"); + } + + if (secretKey.length != KEY_SIZE) + { + throw new CryptoException("secretKey's length is wrong!"); + } + + if (iv.length != IV_SIZE) + { + throw new CryptoException("iv's length is wrong!"); + } + + // To get the value padded into input + int padding = 16 - plainBytes.length % BLOCK_SIZE; + // The plaintext with padding value + byte[] plainBytesWithPadding = new byte[plainBytes.length + padding]; + System.arraycopy(plainBytes,0,plainBytesWithPadding,0,plainBytes.length); + // The padder adds PKCS7 padding to the input, which makes its length to + // become an integral multiple of 16 bytes + PKCS7Padding padder = new PKCS7Padding(); + // To add padding + padder.addPadding(plainBytesWithPadding, plainBytes.length); + + CBCBlockCipher encryptor = new CBCBlockCipher(new AESEngine()); + // To provide key and initialisation vector as input + encryptor.init(true,new ParametersWithIV(new KeyParameter(secretKey),iv)); + byte[] output = new byte[plainBytesWithPadding.length + IV_SIZE]; + // To encrypt the input_p in CBC mode + for(int i = 0 ; i < plainBytesWithPadding.length/BLOCK_SIZE; i++) { + encryptor.processBlock(plainBytesWithPadding, i * BLOCK_SIZE, output, (i + 1) * BLOCK_SIZE); + } + + // The IV locates on the first block of ciphertext + System.arraycopy(iv,0,output,0,BLOCK_SIZE); + return output; + } + + public static byte[] encrypt(byte[] plainBytes, byte[] secretKey){ + + byte[] iv = new byte[IV_SIZE]; + SecureRandom random = new SecureRandom(); + random.nextBytes(iv); + return encrypt(plainBytes,secretKey,iv); + } + + /** + * decryption + * + * @param cipherBytes ciphertext + * @param secretKey symmetric key + * @return plaintext + */ + public static byte[] decrypt(byte[] cipherBytes, byte[] secretKey){ + + // To ensure that the ciphertext is not null + if (cipherBytes == null) + { + throw new CryptoException("ciphertext is null!"); + } + + // To ensure that the ciphertext's length is integral multiples of 16 bytes + if (cipherBytes.length % BLOCK_SIZE != 0) + { + throw new CryptoException("ciphertext's length is wrong!"); + } + + if (secretKey.length != KEY_SIZE) + { + throw new CryptoException("secretKey's length is wrong!"); + } + + byte[] iv = new byte[IV_SIZE]; + System.arraycopy(cipherBytes,0,iv,0,BLOCK_SIZE); + + CBCBlockCipher decryptor = new CBCBlockCipher(new AESEngine()); + // To prepare the decryption + decryptor.init(false,new ParametersWithIV(new KeyParameter(secretKey),iv)); + byte[] outputWithPadding = new byte[cipherBytes.length-BLOCK_SIZE]; + // To decrypt the input in CBC mode + for(int i = 1 ; i < cipherBytes.length/BLOCK_SIZE ; i++) { + decryptor.processBlock(cipherBytes, i * BLOCK_SIZE, outputWithPadding, (i - 1) * BLOCK_SIZE); + } + + int p = outputWithPadding[outputWithPadding.length-1]; + // To ensure that the padding of output_p is valid + if(p > BLOCK_SIZE || p < 0x01) + { + throw new CryptoException("There no exists such padding!"); + + } + for(int i = 0 ; i < p ; i++) + { + if(outputWithPadding[outputWithPadding.length - i -1] != p) + { + throw new CryptoException("Padding is invalid!"); + } + } + + // To remove the padding from output and obtain plaintext + byte[] output = new byte[outputWithPadding.length - p]; + System.arraycopy(outputWithPadding, 0, output, 0, output.length); + return output; + } } diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RSAUtils.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RSAUtils.java index fd9598ce..3515a435 100644 --- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RSAUtils.java +++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RSAUtils.java @@ -31,8 +31,8 @@ import java.security.spec.X509EncodedKeySpec; /** * @author zhanglin33 * @title: RSAUtils - * @description: RSA2048 encryption(ECB) and signature algorithms with SHA256, - * and keys are output in both PKCS1v2 format and PKCS8 + * @description: RSA2048 encryption(RSA/ECB/PKCS1Padding) and signature(SHA256withRSA) algorithms, + * and keys are output in raw, PKCS1v2 and PKCS8 formats * @date 2019-03-25, 17:20 */ public class RSAUtils { @@ -48,6 +48,8 @@ public class RSAUtils { private static final int DQ_LENGTH = 1024 / 8; private static final int QINV_LENGTH = 1024 / 8; + private static final BigInteger PUBEXP_0X03 = BigInteger.valueOf(0x03); + private static final BigInteger VERSION_2PRIMES = BigInteger.valueOf(0); private static final AlgorithmIdentifier RSA_ALGORITHM_IDENTIFIER = @@ -69,11 +71,8 @@ public class RSAUtils { } public static AsymmetricCipherKeyPair generateKeyPair(SecureRandom random){ - AsymmetricCipherKeyPairGenerator kpGen = new RSAKeyPairGenerator(); - - BigInteger exponent = BigInteger.valueOf(0x11); - kpGen.init(new RSAKeyGenerationParameters(exponent, random, KEYSIZEBITS, CERTAINTY)); + kpGen.init(new RSAKeyGenerationParameters(PUBEXP_0X03, random, KEYSIZEBITS, CERTAINTY)); return kpGen.generateKeyPair(); } diff --git a/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/ECDSASignatureFunctionTest.java b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/ECDSASignatureFunctionTest.java new file mode 100644 index 00000000..030f6f47 --- /dev/null +++ b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/ECDSASignatureFunctionTest.java @@ -0,0 +1,352 @@ +package test.com.jd.blockchain.crypto.service.classic; + +import com.jd.blockchain.crypto.*; +import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; +import com.jd.blockchain.utils.io.BytesUtils; +import org.junit.Test; + +import java.util.Random; + +import static com.jd.blockchain.crypto.CryptoAlgorithm.ASYMMETRIC_KEY; +import static com.jd.blockchain.crypto.CryptoAlgorithm.SIGNATURE_ALGORITHM; +import static com.jd.blockchain.crypto.CryptoKeyType.PRIVATE; +import static com.jd.blockchain.crypto.CryptoKeyType.PUBLIC; +import static org.junit.Assert.*; + +/** + * @author zhanglin33 + * @title: ECDSASignatureFunctionTest + * @description: JunitTest for ECDSASignatureFunction in SPI mode + * @date 2019-04-23, 09:37 + */ +public class ECDSASignatureFunctionTest { + + @Test + public void getAlgorithmTest() { + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name()); + assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code()); + + algorithm = Crypto.getAlgorithm("eCDsA"); + assertNotNull(algorithm); + + assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name()); + assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code()); + + algorithm = Crypto.getAlgorithm("eedsa"); + assertNull(algorithm); + } + + @Test + public void generateKeyPairTest() { + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PubKey pubKey = keyPair.getPubKey(); + PrivKey privKey = keyPair.getPrivKey(); + + assertEquals(PUBLIC.CODE, pubKey.getKeyType().CODE); + assertEquals(65, pubKey.getRawKeyBytes().length); + assertEquals(PRIVATE.CODE, privKey.getKeyType().CODE); + assertEquals(32, privKey.getRawKeyBytes().length); + + assertEquals(algorithm.code(), pubKey.getAlgorithm()); + assertEquals(algorithm.code(), privKey.getAlgorithm()); + + assertEquals(2 + 1 + 65, pubKey.toBytes().length); + assertEquals(2 + 1 + 32, privKey.toBytes().length); + + byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); + byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE }; + byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE }; + byte[] rawPubKeyBytes = pubKey.getRawKeyBytes(); + byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); + assertArrayEquals(BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawPubKeyBytes), pubKey.toBytes()); + assertArrayEquals(BytesUtils.concat(algoBytes, privKeyTypeBytes, rawPrivKeyBytes), privKey.toBytes()); + } + + @Test + public void retrievePubKeyTest() { + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PubKey pubKey = keyPair.getPubKey(); + PrivKey privKey = keyPair.getPrivKey(); + + PubKey retrievedPubKey = signatureFunction.retrievePubKey(privKey); + + assertEquals(pubKey.getKeyType(), retrievedPubKey.getKeyType()); + assertEquals(pubKey.getRawKeyBytes().length, retrievedPubKey.getRawKeyBytes().length); + assertEquals(pubKey.getAlgorithm(), retrievedPubKey.getAlgorithm()); + assertArrayEquals(pubKey.toBytes(), retrievedPubKey.toBytes()); + } + + @Test + public void signTest() { + + byte[] data = new byte[1024]; + Random random = new Random(); + random.nextBytes(data); + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PrivKey privKey = keyPair.getPrivKey(); + SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); + + byte[] signatureBytes = signatureDigest.toBytes(); + + assertEquals(2 + 64, signatureBytes.length); + assertEquals(ClassicAlgorithm.ECDSA.code(), signatureDigest.getAlgorithm()); + assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 22 & 0x00FF)), + signatureDigest.getAlgorithm()); + + byte[] algoBytes = BytesUtils.toBytes(signatureDigest.getAlgorithm()); + byte[] rawSinatureBytes = signatureDigest.getRawDigest(); + assertArrayEquals(BytesUtils.concat(algoBytes, rawSinatureBytes), signatureBytes); + } + + @Test + public void verifyTest() { + byte[] data = new byte[1024]; + Random random = new Random(); + random.nextBytes(data); + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PubKey pubKey = keyPair.getPubKey(); + PrivKey privKey = keyPair.getPrivKey(); + SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); + + assertTrue(signatureFunction.verify(signatureDigest, pubKey, data)); + } + + @Test + public void supportPrivKeyTest() { + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PrivKey privKey = keyPair.getPrivKey(); + byte[] privKeyBytes = privKey.toBytes(); + + assertTrue(signatureFunction.supportPrivKey(privKeyBytes)); + + algorithm = Crypto.getAlgorithm("ripemd160"); + assertNotNull(algorithm); + byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); + byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE }; + byte[] rawKeyBytes = privKey.getRawKeyBytes(); + byte[] ripemd160PubKeyBytes = BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawKeyBytes); + + assertFalse(signatureFunction.supportPrivKey(ripemd160PubKeyBytes)); + } + + @Test + public void resolvePrivKeyTest() { + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PrivKey privKey = keyPair.getPrivKey(); + byte[] privKeyBytes = privKey.toBytes(); + + PrivKey resolvedPrivKey = signatureFunction.resolvePrivKey(privKeyBytes); + + assertEquals(PRIVATE.CODE, resolvedPrivKey.getKeyType().CODE); + assertEquals(32, resolvedPrivKey.getRawKeyBytes().length); + assertEquals(ClassicAlgorithm.ECDSA.code(), resolvedPrivKey.getAlgorithm()); + assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 22 & 0x00FF)), + resolvedPrivKey.getAlgorithm()); + assertArrayEquals(privKeyBytes, resolvedPrivKey.toBytes()); + + algorithm = Crypto.getAlgorithm("ripemd160"); + assertNotNull(algorithm); + byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); + byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE }; + byte[] rawKeyBytes = privKey.getRawKeyBytes(); + byte[] ripemd160PubKeyBytes = BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawKeyBytes); + + Class expectedException = CryptoException.class; + Exception actualEx = null; + try { + signatureFunction.resolvePrivKey(ripemd160PubKeyBytes); + } catch (Exception e) { + actualEx = e; + } + assertNotNull(actualEx); + assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); + } + + @Test + public void supportPubKeyTest() { + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PubKey pubKey = keyPair.getPubKey(); + byte[] pubKeyBytes = pubKey.toBytes(); + + assertTrue(signatureFunction.supportPubKey(pubKeyBytes)); + + algorithm = Crypto.getAlgorithm("ripemd160"); + assertNotNull(algorithm); + byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); + byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE }; + byte[] rawKeyBytes = pubKey.getRawKeyBytes(); + byte[] ripemd160PrivKeyBytes = BytesUtils.concat(algoBytes, privKeyTypeBytes, rawKeyBytes); + + assertFalse(signatureFunction.supportPubKey(ripemd160PrivKeyBytes)); + } + + @Test + public void resolvePubKeyTest() { + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PubKey pubKey = keyPair.getPubKey(); + byte[] pubKeyBytes = pubKey.toBytes(); + + PubKey resolvedPubKey = signatureFunction.resolvePubKey(pubKeyBytes); + + assertEquals(PUBLIC.CODE, resolvedPubKey.getKeyType().CODE); + assertEquals(65, resolvedPubKey.getRawKeyBytes().length); + assertEquals(ClassicAlgorithm.ECDSA.code(), resolvedPubKey.getAlgorithm()); + assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 22 & 0x00FF)), + resolvedPubKey.getAlgorithm()); + assertArrayEquals(pubKeyBytes, resolvedPubKey.toBytes()); + + algorithm = Crypto.getAlgorithm("ripemd160"); + assertNotNull(algorithm); + byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); + byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE }; + byte[] rawKeyBytes = pubKey.getRawKeyBytes(); + byte[] ripemd160PrivKeyBytes = BytesUtils.concat(algoBytes, privKeyTypeBytes, rawKeyBytes); + + Class expectedException = CryptoException.class; + Exception actualEx = null; + try { + signatureFunction.resolvePrivKey(ripemd160PrivKeyBytes); + } catch (Exception e) { + actualEx = e; + } + assertNotNull(actualEx); + assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); + } + + @Test + public void supportDigestTest() { + + byte[] data = new byte[1024]; + Random random = new Random(); + random.nextBytes(data); + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PrivKey privKey = keyPair.getPrivKey(); + + SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); + + byte[] signatureDigestBytes = signatureDigest.toBytes(); + assertTrue(signatureFunction.supportDigest(signatureDigestBytes)); + + algorithm = Crypto.getAlgorithm("ripemd160"); + assertNotNull(algorithm); + byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); + byte[] rawDigestBytes = signatureDigest.toBytes(); + byte[] ripemd160SignatureBytes = BytesUtils.concat(algoBytes, rawDigestBytes); + + assertFalse(signatureFunction.supportDigest(ripemd160SignatureBytes)); + } + + @Test + public void resolveDigestTest() { + + byte[] data = new byte[1024]; + Random random = new Random(); + random.nextBytes(data); + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("ECDSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PrivKey privKey = keyPair.getPrivKey(); + + SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); + + byte[] signatureDigestBytes = signatureDigest.toBytes(); + + SignatureDigest resolvedSignatureDigest = signatureFunction.resolveDigest(signatureDigestBytes); + + assertEquals(64, resolvedSignatureDigest.getRawDigest().length); + assertEquals(ClassicAlgorithm.ECDSA.code(), resolvedSignatureDigest.getAlgorithm()); + assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 22 & 0x00FF)), + resolvedSignatureDigest.getAlgorithm()); + assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes()); + + algorithm = Crypto.getAlgorithm("ripemd160"); + assertNotNull(algorithm); + byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); + byte[] rawDigestBytes = signatureDigest.getRawDigest(); + byte[] ripemd160SignatureDigestBytes = BytesUtils.concat(algoBytes, rawDigestBytes); + + Class expectedException = CryptoException.class; + Exception actualEx = null; + try { + signatureFunction.resolveDigest(ripemd160SignatureDigestBytes); + } catch (Exception e) { + actualEx = e; + } + assertNotNull(actualEx); + assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); + } +} diff --git a/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/RSACryptoFunctionTest.java b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/RSACryptoFunctionTest.java new file mode 100644 index 00000000..3eefed1c --- /dev/null +++ b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/RSACryptoFunctionTest.java @@ -0,0 +1,488 @@ +package test.com.jd.blockchain.crypto.service.classic; + +import com.jd.blockchain.crypto.*; +import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; +import com.jd.blockchain.utils.io.BytesUtils; +import org.junit.Test; + +import java.util.Random; + +import static com.jd.blockchain.crypto.CryptoAlgorithm.*; +import static com.jd.blockchain.crypto.CryptoKeyType.PRIVATE; +import static com.jd.blockchain.crypto.CryptoKeyType.PUBLIC; +import static org.junit.Assert.*; + +/** + * @author zhanglin33 + * @title: RSACryptoFunctionTest + * @description: JunitTest for RSACryptoFunction in SPI mode + * @date 2019-04-23, 15:30 + */ +public class RSACryptoFunctionTest { + + @Test + public void getAlgorithmTest() { + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name()); + assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code()); + + algorithm = Crypto.getAlgorithm("Rsa"); + assertNotNull(algorithm); + + assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name()); + assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code()); + + algorithm = Crypto.getAlgorithm("rsa2"); + assertNull(algorithm); + } + + @Test + public void generateKeyPairTest() { + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PubKey pubKey = keyPair.getPubKey(); + PrivKey privKey = keyPair.getPrivKey(); + + assertEquals(PUBLIC.CODE, pubKey.getKeyType().CODE); + assertEquals(257, pubKey.getRawKeyBytes().length); + assertEquals(PRIVATE.CODE, privKey.getKeyType().CODE); + assertEquals(1153, 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); + + byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); + byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE }; + byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE }; + byte[] rawPubKeyBytes = pubKey.getRawKeyBytes(); + byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); + assertArrayEquals(BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawPubKeyBytes), pubKey.toBytes()); + assertArrayEquals(BytesUtils.concat(algoBytes, privKeyTypeBytes, rawPrivKeyBytes), privKey.toBytes()); + } + + @Test + public void retrievePubKeyTest() { + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PubKey pubKey = keyPair.getPubKey(); + PrivKey privKey = keyPair.getPrivKey(); + + PubKey retrievedPubKey = signatureFunction.retrievePubKey(privKey); + + assertEquals(pubKey.getKeyType(), retrievedPubKey.getKeyType()); + assertEquals(pubKey.getRawKeyBytes().length, retrievedPubKey.getRawKeyBytes().length); + assertEquals(pubKey.getAlgorithm(), retrievedPubKey.getAlgorithm()); + assertArrayEquals(pubKey.toBytes(), retrievedPubKey.toBytes()); + } + + @Test + public void signTest() { + + byte[] data = new byte[1024]; + Random random = new Random(); + random.nextBytes(data); + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PrivKey privKey = keyPair.getPrivKey(); + SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); + + byte[] signatureBytes = signatureDigest.toBytes(); + + assertEquals(2 + 256, signatureBytes.length); + assertEquals(algorithm.code(), signatureDigest.getAlgorithm()); + + assertEquals(ClassicAlgorithm.RSA.code(), signatureDigest.getAlgorithm()); + assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)), + signatureDigest.getAlgorithm()); + + byte[] algoBytes = BytesUtils.toBytes(signatureDigest.getAlgorithm()); + byte[] rawSinatureBytes = signatureDigest.getRawDigest(); + assertArrayEquals(BytesUtils.concat(algoBytes, rawSinatureBytes), signatureBytes); + } + + @Test + public void verifyTest() { + byte[] data = new byte[1024]; + Random random = new Random(); + random.nextBytes(data); + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PubKey pubKey = keyPair.getPubKey(); + PrivKey privKey = keyPair.getPrivKey(); + SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); + + assertTrue(signatureFunction.verify(signatureDigest, pubKey, data)); + } + + @Test + public void encryptTest() { + + byte[] data = new byte[128]; + Random random = new Random(); + random.nextBytes(data); + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); + assertNotNull(algorithm); + + AsymmetricEncryptionFunction asymmetricEncryptionFunction = Crypto + .getAsymmetricEncryptionFunction(algorithm); + + AsymmetricKeypair keyPair = asymmetricEncryptionFunction.generateKeypair(); + + PubKey pubKey = keyPair.getPubKey(); + + Ciphertext ciphertext = asymmetricEncryptionFunction.encrypt(pubKey, data); + + byte[] ciphertextBytes = ciphertext.toBytes(); + assertEquals(2 + 256, ciphertextBytes.length); + assertEquals(ClassicAlgorithm.RSA.code(), ciphertext.getAlgorithm()); + + assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)), + ciphertext.getAlgorithm()); + + byte[] algoBytes = BytesUtils.toBytes(ciphertext.getAlgorithm()); + byte[] rawCiphertextBytes = ciphertext.getRawCiphertext(); + assertArrayEquals(BytesUtils.concat(algoBytes, rawCiphertextBytes), ciphertextBytes); + } + + @Test + public void decryptTest() { + + byte[] data = new byte[128]; + Random random = new Random(); + random.nextBytes(data); + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); + assertNotNull(algorithm); + + AsymmetricEncryptionFunction asymmetricEncryptionFunction = Crypto + .getAsymmetricEncryptionFunction(algorithm); + + AsymmetricKeypair keyPair = asymmetricEncryptionFunction.generateKeypair(); + + PubKey pubKey = keyPair.getPubKey(); + PrivKey privKey = keyPair.getPrivKey(); + + Ciphertext ciphertext = asymmetricEncryptionFunction.encrypt(pubKey, data); + + byte[] decryptedPlaintext = asymmetricEncryptionFunction.decrypt(privKey, ciphertext); + + assertArrayEquals(data, decryptedPlaintext); + } + + @Test + public void supportPrivKeyTest() { + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PrivKey privKey = keyPair.getPrivKey(); + byte[] privKeyBytes = privKey.toBytes(); + + assertTrue(signatureFunction.supportPrivKey(privKeyBytes)); + + algorithm = Crypto.getAlgorithm("ripemd160"); + assertNotNull(algorithm); + byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); + byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE }; + byte[] rawKeyBytes = privKey.getRawKeyBytes(); + byte[] ripemd160PubKeyBytes = BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawKeyBytes); + + assertFalse(signatureFunction.supportPrivKey(ripemd160PubKeyBytes)); + } + + @Test + public void resolvePrivKeyTest() { + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PrivKey privKey = keyPair.getPrivKey(); + byte[] privKeyBytes = privKey.toBytes(); + + PrivKey resolvedPrivKey = signatureFunction.resolvePrivKey(privKeyBytes); + + assertEquals(PRIVATE.CODE, resolvedPrivKey.getKeyType().CODE); + assertEquals(1153, resolvedPrivKey.getRawKeyBytes().length); + assertEquals(ClassicAlgorithm.RSA.code(), resolvedPrivKey.getAlgorithm()); + assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)), + resolvedPrivKey.getAlgorithm()); + assertArrayEquals(privKeyBytes, resolvedPrivKey.toBytes()); + + algorithm = Crypto.getAlgorithm("ripemd160"); + assertNotNull(algorithm); + byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); + byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE }; + byte[] rawKeyBytes = privKey.getRawKeyBytes(); + byte[] ripemd160PubKeyBytes = BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawKeyBytes); + + Class expectedException = CryptoException.class; + Exception actualEx = null; + try { + signatureFunction.resolvePrivKey(ripemd160PubKeyBytes); + } catch (Exception e) { + actualEx = e; + } + assertNotNull(actualEx); + assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); + } + + @Test + public void supportPubKeyTest() { + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PubKey pubKey = keyPair.getPubKey(); + byte[] pubKeyBytes = pubKey.toBytes(); + + assertTrue(signatureFunction.supportPubKey(pubKeyBytes)); + + algorithm = Crypto.getAlgorithm("ripemd160"); + assertNotNull(algorithm); + byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); + byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE }; + byte[] rawKeyBytes = pubKey.getRawKeyBytes(); + byte[] ripemd160PrivKeyBytes = BytesUtils.concat(algoBytes, privKeyTypeBytes, rawKeyBytes); + + assertFalse(signatureFunction.supportPubKey(ripemd160PrivKeyBytes)); + } + + @Test + public void resolvePubKeyTest() { + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PubKey pubKey = keyPair.getPubKey(); + byte[] pubKeyBytes = pubKey.toBytes(); + + PubKey resolvedPubKey = signatureFunction.resolvePubKey(pubKeyBytes); + + assertEquals(PUBLIC.CODE, resolvedPubKey.getKeyType().CODE); + assertEquals(257, resolvedPubKey.getRawKeyBytes().length); + assertEquals(ClassicAlgorithm.RSA.code(), resolvedPubKey.getAlgorithm()); + assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)), + resolvedPubKey.getAlgorithm()); + assertArrayEquals(pubKeyBytes, resolvedPubKey.toBytes()); + + algorithm = Crypto.getAlgorithm("ripemd160"); + assertNotNull(algorithm); + byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); + byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE }; + byte[] rawKeyBytes = pubKey.getRawKeyBytes(); + byte[] ripemd160PrivKeyBytes = BytesUtils.concat(algoBytes, privKeyTypeBytes, rawKeyBytes); + + Class expectedException = CryptoException.class; + Exception actualEx = null; + try { + signatureFunction.resolvePrivKey(ripemd160PrivKeyBytes); + } catch (Exception e) { + actualEx = e; + } + assertNotNull(actualEx); + assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); + } + + @Test + public void supportDigestTest() { + + byte[] data = new byte[1024]; + Random random = new Random(); + random.nextBytes(data); + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PrivKey privKey = keyPair.getPrivKey(); + + SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); + + byte[] signatureDigestBytes = signatureDigest.toBytes(); + assertTrue(signatureFunction.supportDigest(signatureDigestBytes)); + + algorithm = Crypto.getAlgorithm("ripemd160"); + assertNotNull(algorithm); + byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); + byte[] rawDigestBytes = signatureDigest.toBytes(); + byte[] ripemd160SignatureBytes = BytesUtils.concat(algoBytes, rawDigestBytes); + + assertFalse(signatureFunction.supportDigest(ripemd160SignatureBytes)); + } + + @Test + public void resolveDigestTest() { + + byte[] data = new byte[1024]; + Random random = new Random(); + random.nextBytes(data); + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); + assertNotNull(algorithm); + + SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); + + AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); + + PrivKey privKey = keyPair.getPrivKey(); + + SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); + + byte[] signatureDigestBytes = signatureDigest.toBytes(); + + SignatureDigest resolvedSignatureDigest = signatureFunction.resolveDigest(signatureDigestBytes); + + assertEquals(256, resolvedSignatureDigest.getRawDigest().length); + assertEquals(ClassicAlgorithm.RSA.code(), resolvedSignatureDigest.getAlgorithm()); + assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)), + resolvedSignatureDigest.getAlgorithm()); + assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes()); + + algorithm = Crypto.getAlgorithm("ripemd160"); + assertNotNull(algorithm); + byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); + byte[] rawDigestBytes = signatureDigest.getRawDigest(); + byte[] ripemd160SignatureDigestBytes = BytesUtils.concat(algoBytes, rawDigestBytes); + + Class expectedException = CryptoException.class; + Exception actualEx = null; + try { + signatureFunction.resolveDigest(ripemd160SignatureDigestBytes); + } catch (Exception e) { + actualEx = e; + } + assertNotNull(actualEx); + assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); + } + + @Test + public void supportCiphertextTest() { + + byte[] data = new byte[128]; + Random random = new Random(); + random.nextBytes(data); + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); + assertNotNull(algorithm); + + AsymmetricEncryptionFunction asymmetricEncryptionFunction = Crypto + .getAsymmetricEncryptionFunction(algorithm); + + AsymmetricKeypair keyPair = asymmetricEncryptionFunction.generateKeypair(); + + PubKey pubKey = keyPair.getPubKey(); + + Ciphertext ciphertext = asymmetricEncryptionFunction.encrypt(pubKey, data); + + byte[] ciphertextBytes = ciphertext.toBytes(); + + assertTrue(asymmetricEncryptionFunction.supportCiphertext(ciphertextBytes)); + + algorithm = Crypto.getAlgorithm("ripemd160"); + assertNotNull(algorithm); + byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); + byte[] rawCiphertextBytes = ciphertext.toBytes(); + byte[] ripemd160CiphertextBytes = BytesUtils.concat(algoBytes, rawCiphertextBytes); + + assertFalse(asymmetricEncryptionFunction.supportCiphertext(ripemd160CiphertextBytes)); + } + + @Test + public void resolveCiphertextTest() { + + byte[] data = new byte[128]; + Random random = new Random(); + random.nextBytes(data); + + CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); + assertNotNull(algorithm); + + AsymmetricEncryptionFunction asymmetricEncryptionFunction = Crypto + .getAsymmetricEncryptionFunction(algorithm); + + AsymmetricKeypair keyPair = asymmetricEncryptionFunction.generateKeypair(); + + PubKey pubKey = keyPair.getPubKey(); + + Ciphertext ciphertext = asymmetricEncryptionFunction.encrypt(pubKey, data); + + byte[] ciphertextBytes = ciphertext.toBytes(); + + Ciphertext resolvedCiphertext = asymmetricEncryptionFunction.resolveCiphertext(ciphertextBytes); + + assertEquals(256, resolvedCiphertext.getRawCiphertext().length); + assertEquals(ClassicAlgorithm.RSA.code(), resolvedCiphertext.getAlgorithm()); + assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)), + resolvedCiphertext.getAlgorithm()); + assertArrayEquals(ciphertextBytes, resolvedCiphertext.toBytes()); + + algorithm = Crypto.getAlgorithm("ripemd160"); + assertNotNull(algorithm); + byte[] algoBytes = CryptoAlgorithm.toBytes(algorithm); + byte[] rawCiphertextBytes = ciphertext.getRawCiphertext(); + byte[] ripemd160CiphertextBytes = BytesUtils.concat(algoBytes, rawCiphertextBytes); + + Class expectedException = CryptoException.class; + Exception actualEx = null; + try { + asymmetricEncryptionFunction.resolveCiphertext(ripemd160CiphertextBytes); + } catch (Exception e) { + actualEx = e; + } + assertNotNull(actualEx); + assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); + } + +} diff --git a/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/utils/classic/AESUtilsTest.java b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/utils/classic/AESUtilsTest.java new file mode 100644 index 00000000..145229bd --- /dev/null +++ b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/utils/classic/AESUtilsTest.java @@ -0,0 +1,100 @@ +package test.com.jd.blockchain.crypto.utils.classic; + +import com.jd.blockchain.crypto.utils.classic.AESUtils; +import com.jd.blockchain.utils.io.BytesUtils; +import org.bouncycastle.util.encoders.Hex; +import org.junit.Test; + +import java.util.Random; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +/** + * @author zhanglin33 + * @title: AESUtilsTest + * @description: Tests for methods in AESUtils + * @date 2019-04-22, 16:06 + */ +public class AESUtilsTest { + + @Test + public void generateKeyTest(){ + byte[] key = AESUtils.generateKey(); + assertEquals(16,key.length); + key = AESUtils.generateKey("abc".getBytes()); + assertArrayEquals( + Hex.decode("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad".substring(0,32)),key); + } + + + @Test + public void encryptTest(){ + String plaintext = "abc"; + String key = "1234567890123456"; + System.out.println(key.getBytes().length); + String iv = "1234567890123456"; + String expectedCiphertextIn2ndBlock = "f479efae2d41d23227f61e675fced95c"; + + byte[] ciphertext = AESUtils.encrypt(plaintext.getBytes(),key.getBytes(),iv.getBytes()); + byte[] expectedCiphertext = BytesUtils.concat(iv.getBytes(),Hex.decode(expectedCiphertextIn2ndBlock)); + assertArrayEquals(expectedCiphertext,ciphertext); + } + + + @Test + public void decryptTest(){ + + Random random = new Random(); + byte[] data = new byte[1024]; + random.nextBytes(data); + + byte[] key = AESUtils.generateKey(); + + byte[] ciphertext = AESUtils.encrypt(data,key); + byte[] plaintext = AESUtils.decrypt(ciphertext,key); + + assertArrayEquals(data,plaintext); + } +// +// +// @Test +// public void encryptingPerformance() { +// +// byte[] data = new byte[1000]; +// Random random = new Random(); +// random.nextBytes(data); +// +// byte[] aesCiphertext = null; +// +// int count = 100000; +// +// +// byte[] aesKey = AESUtils.generateKey(); +// +// System.out.println("=================== do AES encrypt test ==================="); +// for (int r = 0; r < 5; r++) { +// System.out.println("------------- round[" + r + "] --------------"); +// long startTS = System.currentTimeMillis(); +// for (int i = 0; i < count; i++) { +// aesCiphertext = AESUtils.encrypt(data, aesKey); +// } +// long elapsedTS = System.currentTimeMillis() - startTS; +// System.out.println(String.format("AES Encrypting Count=%s; Elapsed Times=%s; KBPS=%.2f", count, elapsedTS, +// (count * 1000.00D) / elapsedTS)); +// } +// +// +// System.out.println("=================== do AES decrypt test ==================="); +// for (int r = 0; r < 5; r++) { +// System.out.println("------------- round[" + r + "] --------------"); +// long startTS = System.currentTimeMillis(); +// for (int i = 0; i < count; i++) { +// AESUtils.decrypt(aesCiphertext, aesKey); +// } +// long elapsedTS = System.currentTimeMillis() - startTS; +// System.out.println(String.format("AES Decrypting Count=%s; Elapsed Times=%s; KBPS=%.2f", count, elapsedTS, +// (count * 1000.00D) / elapsedTS)); +// } +// } +} diff --git a/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/utils/classic/RSAUtilsTest.java b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/utils/classic/RSAUtilsTest.java index 97df0a2f..3e68c8c6 100644 --- a/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/utils/classic/RSAUtilsTest.java +++ b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/utils/classic/RSAUtilsTest.java @@ -42,6 +42,9 @@ public class RSAUtilsTest { RSAUtils.privKey2Bytes_RawKey(RSAUtils.bytes2PrivKey_RawKey(privKeyBytes_RawKey)); assertArrayEquals(privKeyBytes_RawKey,privKeyBytesConverted_RawKey); + System.out.println(pubKeyBytes_RawKey.length); + System.out.println(privKeyBytes_RawKey.length); + byte[] pubKeyBytes_PKCS1 = RSAUtils.pubKey2Bytes_PKCS1(pubKey); byte[] pubKeyBytesConverted_PKCS1 = RSAUtils.pubKey2Bytes_PKCS1(RSAUtils.bytes2PubKey_PKCS1(pubKeyBytes_PKCS1)); @@ -163,7 +166,7 @@ public class RSAUtilsTest { public void performanceTest(){ int count = 10000; - byte[] data = new byte[1024]; + byte[] data = new byte[128]; Random random = new Random(); random.nextBytes(data); @@ -172,6 +175,7 @@ public class RSAUtilsTest { AsymmetricKeyParameter pubKey = keyPair.getPublic(); byte[] signature = RSAUtils.sign(data,privKey); + byte[] ciphertext = RSAUtils.encrypt(data,pubKey); System.out.println("=================== do RSA sign test ==================="); @@ -179,7 +183,7 @@ public class RSAUtilsTest { System.out.println("------------- round[" + r + "] --------------"); long startTS = System.currentTimeMillis(); for (int i = 0; i < count; i++) { - RSAUtils.sign(data,privKey); + RSAUtils.sign(data,privKey); } long elapsedTS = System.currentTimeMillis() - startTS; System.out.println(String.format("RSA Signing Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, @@ -197,11 +201,37 @@ public class RSAUtilsTest { System.out.println(String.format("RSA Verifying Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, (count * 1000.00D) / elapsedTS)); } + + System.out.println("=================== do RSA encrypt test ==================="); + + for (int r = 0; r < 5; r++) { + System.out.println("------------- round[" + r + "] --------------"); + long startTS = System.currentTimeMillis(); + for (int i = 0; i < count; i++) { + RSAUtils.encrypt(data,pubKey); + } + long elapsedTS = System.currentTimeMillis() - startTS; + System.out.println(String.format("RSA Encrypting Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, + (count * 1000.00D) / elapsedTS)); + } + + System.out.println("=================== do RSA decrypt test ==================="); + for (int r = 0; r < 5; r++) { + System.out.println("------------- round[" + r + "] --------------"); + long startTS = System.currentTimeMillis(); + for (int i = 0; i < count; i++) { + RSAUtils.decrypt(ciphertext,privKey); + } + long elapsedTS = System.currentTimeMillis() - startTS; + System.out.println(String.format("RSA Decrypting Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, + (count * 1000.00D) / elapsedTS)); + } } @Test - public void consistencyTest(){ + public void encryptionConsistencyTest(){ + int count = 10000; byte[] data = new byte[222]; Random random = new Random(); random.nextBytes(data); @@ -226,30 +256,171 @@ public class RSAUtilsTest { Cipher cipher; byte[] ciphertext = null; - try { - cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); - cipher.init(Cipher.ENCRYPT_MODE, publicKey); - ciphertext = cipher.doFinal(data); - } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException - | IllegalBlockSizeException | BadPaddingException e) { - e.printStackTrace(); + byte[] plaintext = null; + + System.out.println("=================== do BouncyCastle-based RSA encrypt test ==================="); + for (int r = 0; r < 5; r++) { + System.out.println("------------- round[" + r + "] --------------"); + long startTS = System.currentTimeMillis(); + for (int i = 0; i < count; i++) { + ciphertext = RSAUtils.encrypt(data,pubKey); + } + long elapsedTS = System.currentTimeMillis() - startTS; + System.out.println(String.format("BouncyCastle-based RSA Encrypting Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, + (count * 1000.00D) / elapsedTS)); } assert ciphertext != null; - byte[] plaintext = RSAUtils.decrypt(ciphertext,privKey); + System.out.println("=================== do BouncyCastle-based RSA decrypt test ==================="); + for (int r = 0; r < 5; r++) { + System.out.println("------------- round[" + r + "] --------------"); + long startTS = System.currentTimeMillis(); + for (int i = 0; i < count; i++) { + plaintext = RSAUtils.decrypt(ciphertext,privKey); + } + long elapsedTS = System.currentTimeMillis() - startTS; + System.out.println(String.format("BouncyCastle-based RSA Decrypting Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, + (count * 1000.00D) / elapsedTS)); + } + + System.out.println("=================== do JDK-based RSA encrypt test ==================="); + for (int r = 0; r < 5; r++) { + System.out.println("------------- round[" + r + "] --------------"); + long startTS = System.currentTimeMillis(); + for (int i = 0; i < count; i++) { + try { + cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + ciphertext = cipher.doFinal(data); + } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException + | IllegalBlockSizeException | BadPaddingException e) { + e.printStackTrace(); + } + } + long elapsedTS = System.currentTimeMillis() - startTS; + System.out.println(String.format("JDK-based RSA Encrypting Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, + (count * 1000.00D) / elapsedTS)); + } + + System.out.println("=================== do JDK-based RSA decrypt test ==================="); + for (int r = 0; r < 5; r++) { + System.out.println("------------- round[" + r + "] --------------"); + long startTS = System.currentTimeMillis(); + for (int i = 0; i < count; i++) { + try { + cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + plaintext = cipher.doFinal(ciphertext); + } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException + | IllegalBlockSizeException | BadPaddingException e) { + e.printStackTrace(); + } + } + long elapsedTS = System.currentTimeMillis() - startTS; + System.out.println(String.format("JDK-based RSA Decrypting Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, + (count * 1000.00D) / elapsedTS)); + } + + + assertArrayEquals(data,plaintext); assertArrayEquals(data,plaintext); + } + + @Test + public void signatureConsistencyTest() { - ciphertext = RSAUtils.encrypt(data,pubKey); + int count = 10000; + byte[] data = new byte[222]; + Random random = new Random(); + random.nextBytes(data); + KeyPairGenerator keyPairGen = null; try { - cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); - cipher.init(Cipher.DECRYPT_MODE, privateKey); - plaintext = cipher.doFinal(ciphertext); - } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException - | IllegalBlockSizeException | BadPaddingException e) { + keyPairGen = KeyPairGenerator.getInstance("RSA"); + } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } + assert keyPairGen != null; + keyPairGen.initialize(2048, new SecureRandom()); + KeyPair keyPair = keyPairGen.generateKeyPair(); + RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); + RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); + + byte[] publicKeyBytes = publicKey.getEncoded(); + byte[] privateKeyBytes = privateKey.getEncoded(); + + byte[] signature = null; + boolean isValid = false; + + RSAKeyParameters pubKey = RSAUtils.bytes2PubKey_PKCS8(publicKeyBytes); + RSAPrivateCrtKeyParameters privKey = RSAUtils.bytes2PrivKey_PKCS8(privateKeyBytes); + + System.out.println("=================== do BouncyCastle-based RSA sign test ==================="); + for (int r = 0; r < 5; r++) { + System.out.println("------------- round[" + r + "] --------------"); + long startTS = System.currentTimeMillis(); + for (int i = 0; i < count; i++) { + signature = RSAUtils.sign(data,privKey); + } + long elapsedTS = System.currentTimeMillis() - startTS; + System.out.println(String.format("BouncyCastle-based RSA Signing Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, + (count * 1000.00D) / elapsedTS)); + } + + System.out.println("=================== do BouncyCastle-based RSA verify test ==================="); + for (int r = 0; r < 5; r++) { + System.out.println("------------- round[" + r + "] --------------"); + long startTS = System.currentTimeMillis(); + for (int i = 0; i < count; i++) { + isValid = RSAUtils.verify(data,pubKey,signature); + } + long elapsedTS = System.currentTimeMillis() - startTS; + System.out.println(String.format("BouncyCastle-based RSA Verifying Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, + (count * 1000.00D) / elapsedTS)); + } + + + + + System.out.println("=================== do JDK-based RSA sign test ==================="); + for (int r = 0; r < 5; r++) { + System.out.println("------------- round[" + r + "] --------------"); + long startTS = System.currentTimeMillis(); + for (int i = 0; i < count; i++) { + try { + Signature signer = Signature.getInstance("SHA256withRSA"); + signer.initSign(privateKey); + signer.update(data); + signature = signer.sign(); + } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { + e.printStackTrace(); + } + } + long elapsedTS = System.currentTimeMillis() - startTS; + System.out.println(String.format("JDK-based RSA Signing Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, + (count * 1000.00D) / elapsedTS)); + } + + System.out.println("=================== do JDK-based RSA verify test ==================="); + for (int r = 0; r < 5; r++) { + System.out.println("------------- round[" + r + "] --------------"); + long startTS = System.currentTimeMillis(); + for (int i = 0; i < count; i++) { + try { + Signature verifier = Signature.getInstance("SHA256withRSA"); + verifier.initVerify(publicKey); + verifier.update(data); + isValid = verifier.verify(signature); + } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { + e.printStackTrace(); + } + } + long elapsedTS = System.currentTimeMillis() - startTS; + System.out.println(String.format("JDK-based RSA Verifying Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, + (count * 1000.00D) / elapsedTS)); + } + + System.out.println(isValid); - assertArrayEquals(data,plaintext); } } diff --git a/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/service/sm/SM2CryptoFunction.java b/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/service/sm/SM2CryptoFunction.java index 8d5cba8a..344aac35 100644 --- a/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/service/sm/SM2CryptoFunction.java +++ b/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/service/sm/SM2CryptoFunction.java @@ -72,7 +72,7 @@ public class SM2CryptoFunction implements AsymmetricEncryptionFunction, Signatur throw new CryptoException("This key is not SM2 private key!"); } - // 验证密文数据的算法标识对应SM2签名算法,并且原始摘要长度为64字节 + // 验证密文数据的算法标识对应SM2算法,并且密文符合长度要求 if (ciphertext.getAlgorithm() != SM2.code() || rawCiphertextBytes.length < ECPOINT_SIZE + HASHDIGEST_SIZE) { throw new CryptoException("This is not SM2 ciphertext!"); @@ -89,14 +89,6 @@ public class SM2CryptoFunction implements AsymmetricEncryptionFunction, Signatur return new PubKey(SM2, rawPubKeyBytes); } -// @Override -// public byte[] retrievePubKey(byte[] privKeyBytes) { -// -// byte[] rawPrivKeyBytes = resolvePrivKey(privKeyBytes).getRawKeyBytes(); -// byte[] rawPubKeyBytes = SM2Utils.retrievePublicKey(rawPrivKeyBytes); -// return new PubKey(SM2, rawPubKeyBytes).toBytes(); -// } - @Override public boolean supportPrivKey(byte[] privKeyBytes) { // 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应SM2算法,并且密钥类型是私钥 @@ -109,7 +101,7 @@ public class SM2CryptoFunction implements AsymmetricEncryptionFunction, Signatur if (supportPrivKey(privKeyBytes)) { return new PrivKey(privKeyBytes); } else { - throw new CryptoException("privKeyBytes is invalid!"); + throw new CryptoException("privKeyBytes are invalid!"); } } @@ -125,7 +117,7 @@ public class SM2CryptoFunction implements AsymmetricEncryptionFunction, Signatur if (supportPubKey(pubKeyBytes)) { return new PubKey(pubKeyBytes); } else { - throw new CryptoException("pubKeyBytes is invalid!"); + throw new CryptoException("pubKeyBytes are invalid!"); } } @@ -141,7 +133,7 @@ public class SM2CryptoFunction implements AsymmetricEncryptionFunction, Signatur if (supportCiphertext(ciphertextBytes)) { return new AsymmetricCiphertext(ciphertextBytes); } else { - throw new CryptoException("ciphertextBytes is invalid!"); + throw new CryptoException("ciphertextBytes are invalid!"); } } @@ -200,7 +192,7 @@ public class SM2CryptoFunction implements AsymmetricEncryptionFunction, Signatur if (supportDigest(digestBytes)) { return new SignatureDigest(digestBytes); } else { - throw new CryptoException("digestBytes is invalid!"); + throw new CryptoException("digestBytes are invalid!"); } } diff --git a/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM4Utils.java b/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM4Utils.java index d2f17b64..323243d4 100644 --- a/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM4Utils.java +++ b/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM4Utils.java @@ -11,11 +11,12 @@ import org.bouncycastle.crypto.params.ParametersWithIV; import java.security.SecureRandom; +import java.util.Arrays; public class SM4Utils { - // SM4 supports 128-bit secret key - private static final int KEY_LENGTH = 128; + // SM4 supports 128-bit(16 bytes) secret key + private static final int KEY_SIZE = 128 / 8; // One block contains 16 bytes private static final int BLOCK_SIZE = 16; // Initial vector's size is 16 bytes @@ -33,12 +34,17 @@ public class SM4Utils { // To provide secure randomness and key length as input // to prepare generate private key - keyGenerator.init(new KeyGenerationParameters(new SecureRandom(), KEY_LENGTH)); + keyGenerator.init(new KeyGenerationParameters(new SecureRandom(), KEY_SIZE * 8)); // To generate key return keyGenerator.generateKey(); } + public static byte[] generateKey(byte[] seed){ + byte[] hash = SM3Utils.hash(seed); + return Arrays.copyOf(hash, KEY_SIZE); + } + /** * encryption @@ -56,6 +62,16 @@ public class SM4Utils { throw new CryptoException("plaintext is null!"); } + if (secretKey.length != KEY_SIZE) + { + throw new CryptoException("secretKey's length is wrong!"); + } + + if (iv.length != IV_SIZE) + { + throw new CryptoException("iv's length is wrong!"); + } + // To get the value padded into input int padding = 16 - plainBytes.length % BLOCK_SIZE; // The plaintext with padding value @@ -110,6 +126,11 @@ public class SM4Utils { throw new CryptoException("ciphertext's length is wrong!"); } + if (secretKey.length != KEY_SIZE) + { + throw new CryptoException("secretKey's length is wrong!"); + } + byte[] iv = new byte[IV_SIZE]; System.arraycopy(cipherBytes,0,iv,0,BLOCK_SIZE); diff --git a/source/crypto/crypto-sm/src/test/java/test/com/jd/blockchain/crypto/service/sm/SM2CyptoFunctionTest.java b/source/crypto/crypto-sm/src/test/java/test/com/jd/blockchain/crypto/service/sm/SM2CyptoFunctionTest.java index cb036dfb..d9e438f3 100644 --- a/source/crypto/crypto-sm/src/test/java/test/com/jd/blockchain/crypto/service/sm/SM2CyptoFunctionTest.java +++ b/source/crypto/crypto-sm/src/test/java/test/com/jd/blockchain/crypto/service/sm/SM2CyptoFunctionTest.java @@ -484,5 +484,4 @@ public class SM2CyptoFunctionTest { assertNotNull(actualEx); assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); } - }