@@ -23,13 +23,14 @@ public class ClassicCryptoService implements CryptoService { | |||||
public static final JVMSecureRandomFunction JVM_SECURE_RANDOM = new JVMSecureRandomFunction(); | 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<CryptoFunction> FUNCTIONS; | private static final Collection<CryptoFunction> FUNCTIONS; | ||||
static { | static { | ||||
List<CryptoFunction> funcs = Arrays.asList(AES, ED25519, RIPEMD160, SHA256, JVM_SECURE_RANDOM); | |||||
List<CryptoFunction> funcs = Arrays.asList(AES, ED25519, ECDSA, RSA, RIPEMD160, SHA256, JVM_SECURE_RANDOM); | |||||
FUNCTIONS = Collections.unmodifiableList(funcs); | FUNCTIONS = Collections.unmodifiableList(funcs); | ||||
} | } | ||||
@@ -1,60 +1,129 @@ | |||||
package com.jd.blockchain.crypto.service.classic; | 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 { | 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() { | ECDSASignatureFunction() { | ||||
} | } | ||||
@Override | @Override | ||||
public SignatureDigest sign(PrivKey privKey, byte[] data) { | 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 | @Override | ||||
public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) { | 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 | @Override | ||||
public PubKey retrievePubKey(PrivKey privKey) { | public PubKey retrievePubKey(PrivKey privKey) { | ||||
return null; | |||||
byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||||
byte[] rawPubKeyBytes = ECDSAUtils.retrievePublicKey(rawPrivKeyBytes); | |||||
return new PubKey(ECDSA, rawPubKeyBytes); | |||||
} | } | ||||
@Override | @Override | ||||
public boolean supportPrivKey(byte[] privKeyBytes) { | public boolean supportPrivKey(byte[] privKeyBytes) { | ||||
return false; | |||||
// 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应ECDSA签名算法,并且密钥类型是私钥 | |||||
return privKeyBytes.length == PRIVKEY_LENGTH && CryptoAlgorithm.match(ECDSA, privKeyBytes) | |||||
&& privKeyBytes[ALGORYTHM_CODE_SIZE] == PRIVATE.CODE; | |||||
} | } | ||||
@Override | @Override | ||||
public PrivKey resolvePrivKey(byte[] privKeyBytes) { | public PrivKey resolvePrivKey(byte[] privKeyBytes) { | ||||
return null; | |||||
if (supportPrivKey(privKeyBytes)) { | |||||
return new PrivKey(privKeyBytes); | |||||
} else { | |||||
throw new CryptoException("privKeyBytes are invalid!"); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
public boolean supportPubKey(byte[] pubKeyBytes) { | public boolean supportPubKey(byte[] pubKeyBytes) { | ||||
return false; | |||||
// 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应ECDSA签名算法,并且密钥类型是公钥 | |||||
return pubKeyBytes.length == PUBKEY_LENGTH && CryptoAlgorithm.match(ECDSA, pubKeyBytes) | |||||
&& pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE; | |||||
} | } | ||||
@Override | @Override | ||||
public PubKey resolvePubKey(byte[] pubKeyBytes) { | public PubKey resolvePubKey(byte[] pubKeyBytes) { | ||||
return null; | |||||
if (supportPubKey(pubKeyBytes)) { | |||||
return new PubKey(pubKeyBytes); | |||||
} else { | |||||
throw new CryptoException("pubKeyBytes are invalid!"); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
public boolean supportDigest(byte[] digestBytes) { | public boolean supportDigest(byte[] digestBytes) { | ||||
return false; | |||||
// 验证输入字节数组长度=算法标识长度+摘要长度,字节数组的算法标识对应ECDSA算法 | |||||
return digestBytes.length == SIGNATUREDIGEST_LENGTH && CryptoAlgorithm.match(ECDSA, digestBytes); | |||||
} | } | ||||
@Override | @Override | ||||
public SignatureDigest resolveDigest(byte[] digestBytes) { | public SignatureDigest resolveDigest(byte[] digestBytes) { | ||||
return null; | |||||
if (supportDigest(digestBytes)) { | |||||
return new SignatureDigest(digestBytes); | |||||
} else { | |||||
throw new CryptoException("digestBytes are invalid!"); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
@@ -64,6 +133,28 @@ public class ECDSASignatureFunction implements SignatureFunction { | |||||
@Override | @Override | ||||
public AsymmetricKeypair generateKeypair() { | 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; | |||||
} | } | ||||
} | } |
@@ -50,7 +50,6 @@ public class ED25519SignatureFunction implements SignatureFunction { | |||||
// 调用ED25519签名算法计算签名结果 | // 调用ED25519签名算法计算签名结果 | ||||
return new SignatureDigest(ED25519, ED25519Utils.sign(data, rawPrivKeyBytes)); | return new SignatureDigest(ED25519, ED25519Utils.sign(data, rawPrivKeyBytes)); | ||||
} | } | ||||
@Override | @Override | ||||
@@ -69,7 +68,7 @@ public class ED25519SignatureFunction implements SignatureFunction { | |||||
throw new CryptoException("This key is not ED25519 public key!"); | throw new CryptoException("This key is not ED25519 public key!"); | ||||
} | } | ||||
// 验证密文数据的算法标识对应ED25519签名算法,并且原始摘要长度为64字节 | |||||
// 验证签名数据的算法标识对应ED25519签名算法,并且原始摘要长度为64字节 | |||||
if (digest.getAlgorithm() != ED25519.code() || rawDigestBytes.length != SIGNATUREDIGEST_SIZE) { | if (digest.getAlgorithm() != ED25519.code() || rawDigestBytes.length != SIGNATUREDIGEST_SIZE) { | ||||
throw new CryptoException("This is not ED25519 signature digest!"); | throw new CryptoException("This is not ED25519 signature digest!"); | ||||
} | } | ||||
@@ -106,7 +105,6 @@ public class ED25519SignatureFunction implements SignatureFunction { | |||||
// 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应ED25519签名算法,并且密钥类型是公钥 | // 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应ED25519签名算法,并且密钥类型是公钥 | ||||
return pubKeyBytes.length == PUBKEY_LENGTH && CryptoAlgorithm.match(ED25519, pubKeyBytes) | return pubKeyBytes.length == PUBKEY_LENGTH && CryptoAlgorithm.match(ED25519, pubKeyBytes) | ||||
&& pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE; | && pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE; | ||||
} | } | ||||
@Override | @Override | ||||
@@ -140,6 +138,7 @@ public class ED25519SignatureFunction implements SignatureFunction { | |||||
@Override | @Override | ||||
public AsymmetricKeypair generateKeypair() { | public AsymmetricKeypair generateKeypair() { | ||||
// 调用ED25519算法的密钥生成算法生成公私钥对priKey和pubKey,返回密钥对 | // 调用ED25519算法的密钥生成算法生成公私钥对priKey和pubKey,返回密钥对 | ||||
AsymmetricCipherKeyPair keyPair = ED25519Utils.generateKeyPair(); | AsymmetricCipherKeyPair keyPair = ED25519Utils.generateKeyPair(); | ||||
Ed25519PrivateKeyParameters privKeyParams = (Ed25519PrivateKeyParameters) keyPair.getPrivate(); | Ed25519PrivateKeyParameters privKeyParams = (Ed25519PrivateKeyParameters) keyPair.getPrivate(); | ||||
@@ -148,6 +147,5 @@ public class ED25519SignatureFunction implements SignatureFunction { | |||||
byte[] privKeyBytes = privKeyParams.getEncoded(); | byte[] privKeyBytes = privKeyParams.getEncoded(); | ||||
byte[] pubKeyBytes = pubKeyParams.getEncoded(); | byte[] pubKeyBytes = pubKeyParams.getEncoded(); | ||||
return new AsymmetricKeypair(new PubKey(ED25519, pubKeyBytes), new PrivKey(ED25519, privKeyBytes)); | return new AsymmetricKeypair(new PubKey(ED25519, pubKeyBytes), new PrivKey(ED25519, privKeyBytes)); | ||||
} | } | ||||
} | } |
@@ -1,14 +1,15 @@ | |||||
package com.jd.blockchain.crypto.service.classic; | 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 | * @author zhanglin33 | ||||
@@ -17,78 +18,195 @@ import com.jd.blockchain.crypto.SignatureFunction; | |||||
* @date 2019-03-25, 17:28 | * @date 2019-03-25, 17:28 | ||||
*/ | */ | ||||
public class RSACryptoFunction implements AsymmetricEncryptionFunction, SignatureFunction { | 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 | @Override | ||||
public Ciphertext encrypt(PubKey pubKey, byte[] data) { | 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 | @Override | ||||
public byte[] decrypt(PrivKey privKey, Ciphertext ciphertext) { | 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 | @Override | ||||
public PubKey retrievePubKey(PrivKey privKey) { | public PubKey retrievePubKey(PrivKey privKey) { | ||||
return null; | |||||
byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||||
byte[] rawPubKeyBytes = RSAUtils.retrievePublicKey(rawPrivKeyBytes); | |||||
return new PubKey(RSA, rawPubKeyBytes); | |||||
} | } | ||||
@Override | @Override | ||||
public SignatureDigest sign(PrivKey privKey, byte[] data) { | 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 | @Override | ||||
public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) { | 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 | @Override | ||||
public boolean supportPrivKey(byte[] privKeyBytes) { | public boolean supportPrivKey(byte[] privKeyBytes) { | ||||
return false; | |||||
// 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应RSA算法,并且密钥类型是私钥 | |||||
return privKeyBytes.length == PRIVKEY_LENGTH && CryptoAlgorithm.match(RSA, privKeyBytes) | |||||
&& privKeyBytes[ALGORYTHM_CODE_SIZE] == PRIVATE.CODE; | |||||
} | } | ||||
@Override | @Override | ||||
public PrivKey resolvePrivKey(byte[] privKeyBytes) { | public PrivKey resolvePrivKey(byte[] privKeyBytes) { | ||||
return null; | |||||
if (supportPrivKey(privKeyBytes)) { | |||||
return new PrivKey(privKeyBytes); | |||||
} else { | |||||
throw new CryptoException("privKeyBytes are invalid!"); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
public boolean supportPubKey(byte[] pubKeyBytes) { | public boolean supportPubKey(byte[] pubKeyBytes) { | ||||
return false; | |||||
// 验证输入字节数组长度=算法标识长度+密钥类型长度+椭圆曲线点长度,密钥数据的算法标识对应RSA算法,并且密钥类型是公钥 | |||||
return pubKeyBytes.length == PUBKEY_LENGTH && CryptoAlgorithm.match(RSA, pubKeyBytes) | |||||
&& pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE; | |||||
} | } | ||||
@Override | @Override | ||||
public PubKey resolvePubKey(byte[] pubKeyBytes) { | public PubKey resolvePubKey(byte[] pubKeyBytes) { | ||||
return null; | |||||
if (supportPubKey(pubKeyBytes)) { | |||||
return new PubKey(pubKeyBytes); | |||||
} else { | |||||
throw new CryptoException("pubKeyBytes are invalid!"); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
public boolean supportDigest(byte[] digestBytes) { | public boolean supportDigest(byte[] digestBytes) { | ||||
return false; | |||||
// 验证输入字节数组长度=算法标识长度+签名长度,字节数组的算法标识对应RSA算法 | |||||
return digestBytes.length == SIGNATUREDIGEST_LENGTH && CryptoAlgorithm.match(RSA, digestBytes); | |||||
} | } | ||||
@Override | @Override | ||||
public SignatureDigest resolveDigest(byte[] digestBytes) { | public SignatureDigest resolveDigest(byte[] digestBytes) { | ||||
return null; | |||||
if (supportDigest(digestBytes)) { | |||||
return new SignatureDigest(digestBytes); | |||||
} else { | |||||
throw new CryptoException("digestBytes are invalid!"); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
public boolean supportCiphertext(byte[] ciphertextBytes) { | public boolean supportCiphertext(byte[] ciphertextBytes) { | ||||
return false; | |||||
// 验证输入字节数组长度=密文分组的整数倍,字节数组的算法标识对应RSA算法 | |||||
return (ciphertextBytes.length % CIPHERTEXTBLOCK_SIZE == ALGORYTHM_CODE_SIZE) | |||||
&& CryptoAlgorithm.match(RSA, ciphertextBytes); | |||||
} | } | ||||
@Override | @Override | ||||
public AsymmetricCiphertext resolveCiphertext(byte[] ciphertextBytes) { | public AsymmetricCiphertext resolveCiphertext(byte[] ciphertextBytes) { | ||||
return null; | |||||
if (supportCiphertext(ciphertextBytes)) { | |||||
return new AsymmetricCiphertext(ciphertextBytes); | |||||
} else { | |||||
throw new CryptoException("ciphertextBytes are invalid!"); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
public CryptoAlgorithm getAlgorithm() { | public CryptoAlgorithm getAlgorithm() { | ||||
return null; | |||||
return RSA; | |||||
} | } | ||||
@Override | @Override | ||||
public AsymmetricKeypair generateKeypair() { | 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)); | |||||
} | } | ||||
} | } |
@@ -1,10 +1,170 @@ | |||||
package com.jd.blockchain.crypto.utils.classic; | 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 | * @author zhanglin33 | ||||
* @title: AESUtils | * @title: AESUtils | ||||
* @description: AES/CBC/PKCS7Padding symmetric encryption algorithm | |||||
* @description: AES128/CBC/PKCS7Padding symmetric encryption algorithm | |||||
* @date 2019-04-22, 09:37 | * @date 2019-04-22, 09:37 | ||||
*/ | */ | ||||
public class AESUtils { | 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; | |||||
} | |||||
} | } |
@@ -31,8 +31,8 @@ import java.security.spec.X509EncodedKeySpec; | |||||
/** | /** | ||||
* @author zhanglin33 | * @author zhanglin33 | ||||
* @title: RSAUtils | * @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 | * @date 2019-03-25, 17:20 | ||||
*/ | */ | ||||
public class RSAUtils { | public class RSAUtils { | ||||
@@ -48,6 +48,8 @@ public class RSAUtils { | |||||
private static final int DQ_LENGTH = 1024 / 8; | private static final int DQ_LENGTH = 1024 / 8; | ||||
private static final int QINV_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 BigInteger VERSION_2PRIMES = BigInteger.valueOf(0); | ||||
private static final AlgorithmIdentifier RSA_ALGORITHM_IDENTIFIER = | private static final AlgorithmIdentifier RSA_ALGORITHM_IDENTIFIER = | ||||
@@ -69,11 +71,8 @@ public class RSAUtils { | |||||
} | } | ||||
public static AsymmetricCipherKeyPair generateKeyPair(SecureRandom random){ | public static AsymmetricCipherKeyPair generateKeyPair(SecureRandom random){ | ||||
AsymmetricCipherKeyPairGenerator kpGen = new RSAKeyPairGenerator(); | 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(); | return kpGen.generateKeyPair(); | ||||
} | } | ||||
@@ -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())); | |||||
} | |||||
} |
@@ -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())); | |||||
} | |||||
} |
@@ -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)); | |||||
// } | |||||
// } | |||||
} |
@@ -42,6 +42,9 @@ public class RSAUtilsTest { | |||||
RSAUtils.privKey2Bytes_RawKey(RSAUtils.bytes2PrivKey_RawKey(privKeyBytes_RawKey)); | RSAUtils.privKey2Bytes_RawKey(RSAUtils.bytes2PrivKey_RawKey(privKeyBytes_RawKey)); | ||||
assertArrayEquals(privKeyBytes_RawKey,privKeyBytesConverted_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[] pubKeyBytes_PKCS1 = RSAUtils.pubKey2Bytes_PKCS1(pubKey); | ||||
byte[] pubKeyBytesConverted_PKCS1 = | byte[] pubKeyBytesConverted_PKCS1 = | ||||
RSAUtils.pubKey2Bytes_PKCS1(RSAUtils.bytes2PubKey_PKCS1(pubKeyBytes_PKCS1)); | RSAUtils.pubKey2Bytes_PKCS1(RSAUtils.bytes2PubKey_PKCS1(pubKeyBytes_PKCS1)); | ||||
@@ -163,7 +166,7 @@ public class RSAUtilsTest { | |||||
public void performanceTest(){ | public void performanceTest(){ | ||||
int count = 10000; | int count = 10000; | ||||
byte[] data = new byte[1024]; | |||||
byte[] data = new byte[128]; | |||||
Random random = new Random(); | Random random = new Random(); | ||||
random.nextBytes(data); | random.nextBytes(data); | ||||
@@ -172,6 +175,7 @@ public class RSAUtilsTest { | |||||
AsymmetricKeyParameter pubKey = keyPair.getPublic(); | AsymmetricKeyParameter pubKey = keyPair.getPublic(); | ||||
byte[] signature = RSAUtils.sign(data,privKey); | byte[] signature = RSAUtils.sign(data,privKey); | ||||
byte[] ciphertext = RSAUtils.encrypt(data,pubKey); | |||||
System.out.println("=================== do RSA sign test ==================="); | System.out.println("=================== do RSA sign test ==================="); | ||||
@@ -179,7 +183,7 @@ public class RSAUtilsTest { | |||||
System.out.println("------------- round[" + r + "] --------------"); | System.out.println("------------- round[" + r + "] --------------"); | ||||
long startTS = System.currentTimeMillis(); | long startTS = System.currentTimeMillis(); | ||||
for (int i = 0; i < count; i++) { | for (int i = 0; i < count; i++) { | ||||
RSAUtils.sign(data,privKey); | |||||
RSAUtils.sign(data,privKey); | |||||
} | } | ||||
long elapsedTS = System.currentTimeMillis() - startTS; | long elapsedTS = System.currentTimeMillis() - startTS; | ||||
System.out.println(String.format("RSA Signing Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | 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, | System.out.println(String.format("RSA Verifying Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, | ||||
(count * 1000.00D) / 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 | @Test | ||||
public void consistencyTest(){ | |||||
public void encryptionConsistencyTest(){ | |||||
int count = 10000; | |||||
byte[] data = new byte[222]; | byte[] data = new byte[222]; | ||||
Random random = new Random(); | Random random = new Random(); | ||||
random.nextBytes(data); | random.nextBytes(data); | ||||
@@ -226,30 +256,171 @@ public class RSAUtilsTest { | |||||
Cipher cipher; | Cipher cipher; | ||||
byte[] ciphertext = null; | 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; | 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); | 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 { | 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(); | 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); | |||||
} | } | ||||
} | } |
@@ -72,7 +72,7 @@ public class SM2CryptoFunction implements AsymmetricEncryptionFunction, Signatur | |||||
throw new CryptoException("This key is not SM2 private key!"); | throw new CryptoException("This key is not SM2 private key!"); | ||||
} | } | ||||
// 验证密文数据的算法标识对应SM2签名算法,并且原始摘要长度为64字节 | |||||
// 验证密文数据的算法标识对应SM2算法,并且密文符合长度要求 | |||||
if (ciphertext.getAlgorithm() != SM2.code() | if (ciphertext.getAlgorithm() != SM2.code() | ||||
|| rawCiphertextBytes.length < ECPOINT_SIZE + HASHDIGEST_SIZE) { | || rawCiphertextBytes.length < ECPOINT_SIZE + HASHDIGEST_SIZE) { | ||||
throw new CryptoException("This is not SM2 ciphertext!"); | throw new CryptoException("This is not SM2 ciphertext!"); | ||||
@@ -89,14 +89,6 @@ public class SM2CryptoFunction implements AsymmetricEncryptionFunction, Signatur | |||||
return new PubKey(SM2, rawPubKeyBytes); | 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 | @Override | ||||
public boolean supportPrivKey(byte[] privKeyBytes) { | public boolean supportPrivKey(byte[] privKeyBytes) { | ||||
// 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应SM2算法,并且密钥类型是私钥 | // 验证输入字节数组长度=算法标识长度+密钥类型长度+密钥长度,密钥数据的算法标识对应SM2算法,并且密钥类型是私钥 | ||||
@@ -109,7 +101,7 @@ public class SM2CryptoFunction implements AsymmetricEncryptionFunction, Signatur | |||||
if (supportPrivKey(privKeyBytes)) { | if (supportPrivKey(privKeyBytes)) { | ||||
return new PrivKey(privKeyBytes); | return new PrivKey(privKeyBytes); | ||||
} else { | } 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)) { | if (supportPubKey(pubKeyBytes)) { | ||||
return new PubKey(pubKeyBytes); | return new PubKey(pubKeyBytes); | ||||
} else { | } 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)) { | if (supportCiphertext(ciphertextBytes)) { | ||||
return new AsymmetricCiphertext(ciphertextBytes); | return new AsymmetricCiphertext(ciphertextBytes); | ||||
} else { | } 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)) { | if (supportDigest(digestBytes)) { | ||||
return new SignatureDigest(digestBytes); | return new SignatureDigest(digestBytes); | ||||
} else { | } else { | ||||
throw new CryptoException("digestBytes is invalid!"); | |||||
throw new CryptoException("digestBytes are invalid!"); | |||||
} | } | ||||
} | } | ||||
@@ -11,11 +11,12 @@ import org.bouncycastle.crypto.params.ParametersWithIV; | |||||
import java.security.SecureRandom; | import java.security.SecureRandom; | ||||
import java.util.Arrays; | |||||
public class SM4Utils { | 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 | // One block contains 16 bytes | ||||
private static final int BLOCK_SIZE = 16; | private static final int BLOCK_SIZE = 16; | ||||
// Initial vector's size is 16 bytes | // Initial vector's size is 16 bytes | ||||
@@ -33,12 +34,17 @@ public class SM4Utils { | |||||
// To provide secure randomness and key length as input | // To provide secure randomness and key length as input | ||||
// to prepare generate private key | // 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 | // To generate key | ||||
return keyGenerator.generateKey(); | return keyGenerator.generateKey(); | ||||
} | } | ||||
public static byte[] generateKey(byte[] seed){ | |||||
byte[] hash = SM3Utils.hash(seed); | |||||
return Arrays.copyOf(hash, KEY_SIZE); | |||||
} | |||||
/** | /** | ||||
* encryption | * encryption | ||||
@@ -56,6 +62,16 @@ public class SM4Utils { | |||||
throw new CryptoException("plaintext is 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 | // To get the value padded into input | ||||
int padding = 16 - plainBytes.length % BLOCK_SIZE; | int padding = 16 - plainBytes.length % BLOCK_SIZE; | ||||
// The plaintext with padding value | // The plaintext with padding value | ||||
@@ -110,6 +126,11 @@ public class SM4Utils { | |||||
throw new CryptoException("ciphertext's length is wrong!"); | 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]; | byte[] iv = new byte[IV_SIZE]; | ||||
System.arraycopy(cipherBytes,0,iv,0,BLOCK_SIZE); | System.arraycopy(cipherBytes,0,iv,0,BLOCK_SIZE); | ||||
@@ -484,5 +484,4 @@ public class SM2CyptoFunctionTest { | |||||
assertNotNull(actualEx); | assertNotNull(actualEx); | ||||
assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); | assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); | ||||
} | } | ||||
} | } |