| @@ -68,6 +68,8 @@ public interface DataCodes { | |||
| // public static final int METADATA_PARTICIPANT_INFO = 0x640; | |||
| public static final int METADATA_CRYPTO_SETTING = 0x642; | |||
| public static final int METADATA_CRYPTO_SETTING_PROVIDER = 0x643; | |||
| // public static final int ACCOUNT = 0x700; | |||
| @@ -4,6 +4,7 @@ import java.security.AccessControlContext; | |||
| import java.security.AccessController; | |||
| import java.security.PrivilegedAction; | |||
| import java.util.Collection; | |||
| import java.util.Collections; | |||
| import java.util.HashMap; | |||
| import java.util.LinkedHashMap; | |||
| import java.util.Map; | |||
| @@ -48,32 +49,45 @@ public final class ProviderManager { | |||
| * @return | |||
| */ | |||
| public <S> S getService(Class<S> serviceClazz, String providerName) { | |||
| NamedProviders<S> providers = getServiceProvider(serviceClazz); | |||
| NamedProviders<S> providers = getNamedProviders(serviceClazz); | |||
| return providers.getService(providerName); | |||
| } | |||
| public <S> Provider<S> getProvider(Class<S> serviceClazz, String providerName) { | |||
| @SuppressWarnings("unchecked") | |||
| NamedProviders<S> providers = (NamedProviders<S>) serviceProviders.get(serviceClazz); | |||
| if (providers == null) { | |||
| return null; | |||
| } | |||
| return providers.getProvider(providerName); | |||
| } | |||
| public <S> Collection<Provider<S>> getAllProviders(Class<S> serviceClazz) { | |||
| NamedProviders<S> providers = getServiceProvider(serviceClazz); | |||
| @SuppressWarnings("unchecked") | |||
| NamedProviders<S> providers = (NamedProviders<S>) serviceProviders.get(serviceClazz); | |||
| if (providers == null) { | |||
| return Collections.emptyList(); | |||
| } | |||
| return providers.getProviders(); | |||
| } | |||
| public <S> S installProvider(Class<S> serviceClazz, String providerFullName) { | |||
| NamedProviders<S> providers = getServiceProvider(serviceClazz); | |||
| NamedProviders<S> providers = getNamedProviders(serviceClazz); | |||
| return providers.install(providerFullName); | |||
| } | |||
| public <S> S installProvider(Class<S> service, String providerFullName, ClassLoader classLoader) { | |||
| NamedProviders<S> providers = getServiceProvider(service); | |||
| NamedProviders<S> providers = getNamedProviders(service); | |||
| return providers.install(providerFullName, classLoader); | |||
| } | |||
| public <S> void installAllProviders(Class<S> serviceClazz, ClassLoader classLoader) { | |||
| NamedProviders<S> providers = getServiceProvider(serviceClazz); | |||
| NamedProviders<S> providers = getNamedProviders(serviceClazz); | |||
| providers.installAll(classLoader); | |||
| } | |||
| @SuppressWarnings("unchecked") | |||
| private <S> NamedProviders<S> getServiceProvider(Class<S> serviceClazz) { | |||
| private <S> NamedProviders<S> getNamedProviders(Class<S> serviceClazz) { | |||
| NamedProviders<S> providers = (NamedProviders<S>) serviceProviders.get(serviceClazz); | |||
| if (providers == null) { | |||
| synchronized (mutex) { | |||
| @@ -189,6 +203,11 @@ public final class ProviderManager { | |||
| public Collection<Provider<S>> getProviders() { | |||
| return namedProviders.values(); | |||
| } | |||
| public Provider<S> getProvider(String providerFullName) { | |||
| return namedProviders.get(providerFullName); | |||
| } | |||
| public S getService(String name) { | |||
| String fullName = shortNames.get(name); | |||
| @@ -40,7 +40,7 @@ public class BftsmartMessageService implements MessageService { | |||
| asyncFuture.complete(result); | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(); | |||
| throw new RuntimeException(e); | |||
| } finally { | |||
| asyncPeerProxyPool.returnObject(asynchServiceProxy); | |||
| @@ -5,6 +5,7 @@ import com.jd.blockchain.crypto.PrivKey; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import com.jd.blockchain.ledger.BlockchainKeypair; | |||
| import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||
| import com.jd.blockchain.utils.StringUtils; | |||
| import com.jd.blockchain.utils.codec.Base58Utils; | |||
| import com.jd.blockchain.utils.io.FileUtils; | |||
| import org.apache.maven.plugin.AbstractMojo; | |||
| @@ -1,10 +0,0 @@ | |||
| package com.jd.blockchain; | |||
| /** | |||
| * @Author zhaogw | |||
| * @Date 2018/11/26 20:46 | |||
| */ | |||
| public abstract class StringUtils { | |||
| public static boolean isEmpty(Object str) { | |||
| return str == null || "".equals(str); | |||
| } | |||
| } | |||
| @@ -1,9 +1,9 @@ | |||
| #项目源文件存放的位置; | |||
| #PROJECT_BASE_DIR | |||
| PROJECT_BASE_DIR=E:\\gitCode\\block\\prototype\\ | |||
| #合同使用的类库存放的位置,可能不在项目中,故采用全新的地址; | |||
| #LEDGER_BASE_CLASS_PATH | |||
| LEDGER_BASE_CLASS_PATH=E:\\gitCode\\block\\prototype\\libs\\ | |||
| #为了测试,临时添加的变量; | |||
| #deploy and execute the contract; | |||
| cParam=com.jd.blockchain.contract.AssetContract3 | |||
| sParam=E:\\gitCode\\block\\prototype\\source\\sdk\\contract-sample\\src\\main\\java\\ | |||
| eParam=utf-8 | |||
| @@ -1,80 +0,0 @@ | |||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | |||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |||
| <modelVersion>4.0.0</modelVersion> | |||
| <parent> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>contract</artifactId> | |||
| <version>0.9.0-SNAPSHOT</version> | |||
| </parent> | |||
| <artifactId>contract-tools</artifactId> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>contract-compiler</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>contract-jar</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>commons-io</groupId> | |||
| <artifactId>commons-io</artifactId> | |||
| <version>${commons-io.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>junit</groupId> | |||
| <artifactId>junit</artifactId> | |||
| <scope>test</scope> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.mockito</groupId> | |||
| <artifactId>mockito-core</artifactId> | |||
| <scope>test</scope> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.slf4j</groupId> | |||
| <artifactId>slf4j-log4j12</artifactId> | |||
| </dependency> | |||
| </dependencies> | |||
| <build> | |||
| <plugins> | |||
| <plugin> | |||
| <groupId>org.apache.maven.plugins</groupId> | |||
| <artifactId>maven-surefire-plugin</artifactId> | |||
| <version>2.5</version> | |||
| <configuration> | |||
| <skipTests>true</skipTests> | |||
| </configuration> | |||
| </plugin> | |||
| </plugins> | |||
| </build> | |||
| <!--<build>--> | |||
| <!--<plugins>--> | |||
| <!--<plugin>--> | |||
| <!--<groupId>org.apache.maven.plugins</groupId>--> | |||
| <!--<artifactId>maven-compiler-plugin</artifactId>--> | |||
| <!--<version>3.1</version>--> | |||
| <!--<configuration>--> | |||
| <!--<source>1.8</source>--> | |||
| <!--<target>1.8</target>--> | |||
| <!--<encoding>UTF-8</encoding>--> | |||
| <!--<compilerArgs>--> | |||
| <!--<!–<arg>-verbose</arg>–>--> | |||
| <!--<!–<arg>-Xlint:unchecked</arg>–>--> | |||
| <!--<!–<arg>-Xlint:deprecation</arg>–>--> | |||
| <!--<!–<arg>-bootclasspath</arg>–>--> | |||
| <!--<!–<arg>${env.JAVA_HOME}/jre/lib/rt.jar</arg>–>--> | |||
| <!--<arg>-extdirs</arg>--> | |||
| <!--<arg>${project.basedir}/../contract/contract-libs;$JAVA_HOME/jre/lib/ext</arg>--> | |||
| <!--</compilerArgs>--> | |||
| <!--</configuration>--> | |||
| <!--</plugin>--> | |||
| <!--</plugins>--> | |||
| <!--</build>--> | |||
| </project> | |||
| @@ -21,6 +21,13 @@ | |||
| <groupId>org.bouncycastle</groupId> | |||
| <artifactId>bcprov-jdk15on</artifactId> | |||
| </dependency> | |||
| <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on --> | |||
| <dependency> | |||
| <groupId>org.bouncycastle</groupId> | |||
| <artifactId>bcpkix-jdk15on</artifactId> | |||
| <version>1.61</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>binary-proto</artifactId> | |||
| @@ -19,7 +19,7 @@ import static org.junit.Assert.assertEquals; | |||
| */ | |||
| public class PaillierUtilsTest { | |||
| @Test | |||
| public void generateKeyPairTest() { | |||
| public void test() { | |||
| AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair(); | |||
| PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic(); | |||
| @@ -58,13 +58,6 @@ public class PaillierUtilsTest { | |||
| assertEquals(pInverseConverted, pInverse); | |||
| assertEquals(muPConverted, muP); | |||
| assertEquals(muQConverted, muQ); | |||
| } | |||
| @Test | |||
| public void encryptTest() { | |||
| AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair(); | |||
| PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic(); | |||
| byte[] pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams); | |||
| @@ -77,23 +70,15 @@ public class PaillierUtilsTest { | |||
| assertEquals(512,ciphertextFromParams.length); | |||
| assertEquals(512,ciphertextFromBytes.length); | |||
| } | |||
| @Test | |||
| public void decryptTest(){ | |||
| AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair(); | |||
| PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic(); | |||
| PaillierPrivateKeyParameters privKeyParams = (PaillierPrivateKeyParameters) keyPair.getPrivate(); | |||
| byte[] pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams); | |||
| byte[] privKeyBytes = PaillierUtils.privKey2Bytes(privKeyParams); | |||
| int input = 666; | |||
| byte[] data = intToByteArray(input); | |||
| byte[] inputBytes = intToByteArray(input); | |||
| byte[] ciphertextFromParams = PaillierUtils.encrypt(data,pubKeyParams); | |||
| byte[] ciphertextFromBytes = PaillierUtils.encrypt(data,pubKeyBytes); | |||
| ciphertextFromParams = PaillierUtils.encrypt(inputBytes,pubKeyParams); | |||
| ciphertextFromBytes = PaillierUtils.encrypt(inputBytes,pubKeyBytes); | |||
| byte[] plaintextFromParams = PaillierUtils.decrypt(ciphertextFromBytes,privKeyParams); | |||
| byte[] plaintextFromBytes = PaillierUtils.decrypt(ciphertextFromParams,privKeyBytes); | |||
| @@ -103,16 +88,9 @@ public class PaillierUtilsTest { | |||
| assertEquals(input,outputFromParams); | |||
| assertEquals(input,outputFromBytes); | |||
| } | |||
| @Test | |||
| public void addTest() { | |||
| AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair(); | |||
| PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic(); | |||
| PaillierPrivateKeyParameters privKeyParams = (PaillierPrivateKeyParameters) keyPair.getPrivate(); | |||
| byte[] pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams); | |||
| pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams); | |||
| int input1 = 600; | |||
| int input2 = 60; | |||
| @@ -139,26 +117,19 @@ public class PaillierUtilsTest { | |||
| output = byteArrayToInt(plaintext); | |||
| assertEquals(sum,output); | |||
| } | |||
| @Test | |||
| public void scalarMultiplyTest() { | |||
| AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair(); | |||
| PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic(); | |||
| PaillierPrivateKeyParameters privKeyParams = (PaillierPrivateKeyParameters) keyPair.getPrivate(); | |||
| byte[] pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams); | |||
| pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams); | |||
| int input = 111; | |||
| input = 111; | |||
| int scalar = 6; | |||
| byte[] data = intToByteArray(input); | |||
| data = intToByteArray(input); | |||
| byte[] ciphertext = PaillierUtils.encrypt(data,pubKeyParams); | |||
| byte[] ciphertextPowered = PaillierUtils.scalarMultiply(pubKeyBytes,ciphertext,scalar); | |||
| byte[] plaintextMultiplied = PaillierUtils.decrypt(ciphertextPowered,privKeyParams); | |||
| int output = byteArrayToInt(plaintextMultiplied); | |||
| output = byteArrayToInt(plaintextMultiplied); | |||
| assertEquals(input * scalar, output); | |||
| } | |||
| @@ -15,6 +15,12 @@ | |||
| <artifactId>crypto-framework</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on --> | |||
| <dependency> | |||
| <groupId>org.bouncycastle</groupId> | |||
| <artifactId>bcpkix-jdk15on</artifactId> | |||
| <version>1.61</version> | |||
| </dependency> | |||
| </dependencies> | |||
| </project> | |||
| @@ -21,11 +21,11 @@ public class RSACryptoFunction implements AsymmetricEncryptionFunction, Signatur | |||
| private static final CryptoAlgorithm RSA = ClassicAlgorithm.RSA; | |||
| // modulus.length = 256, publicExponent.length = 1 | |||
| private static final int PUBKEY_SIZE = 257; | |||
| // modulus.length = 256, publicExponent.length = 1, privateExponent.length = 256, p.length = 128, q.length =128, | |||
| // modulus.length = 256, publicExponent.length = 3 | |||
| private static final int PUBKEY_SIZE = 259; | |||
| // modulus.length = 256, publicExponent.length = 3, privateExponent.length = 256, p.length = 128, q.length =128, | |||
| // dP.length = 128, dQ.length = 128, qInv.length = 128 | |||
| private static final int PRIVKEY_SIZE = 1153; | |||
| private static final int PRIVKEY_SIZE = 1155; | |||
| private static final int SIGNATUREDIGEST_SIZE = 256; | |||
| private static final int CIPHERTEXTBLOCK_SIZE = 256; | |||
| @@ -60,6 +60,7 @@ public class RSAUtils { | |||
| private static final int QINV_LENGTH = 1024 / 8; | |||
| private static final BigInteger PUBEXP_0X03 = BigInteger.valueOf(0x03); | |||
| private static final BigInteger PUBEXP_0X010001 = BigInteger.valueOf(0x010001); | |||
| private static final BigInteger VERSION_2PRIMES = BigInteger.valueOf(0); | |||
| @@ -82,6 +83,21 @@ public class RSAUtils { | |||
| } | |||
| public static AsymmetricCipherKeyPair generateKeyPair(SecureRandom random){ | |||
| AsymmetricCipherKeyPairGenerator kpGen = new RSAKeyPairGenerator(); | |||
| kpGen.init(new RSAKeyGenerationParameters(PUBEXP_0X010001, random, KEYSIZEBITS, CERTAINTY)); | |||
| return kpGen.generateKeyPair(); | |||
| } | |||
| /** | |||
| * key pair generation with short public exponent, resulting in verifying and encrypting more efficiently | |||
| * | |||
| * @return key pair | |||
| */ | |||
| public static AsymmetricCipherKeyPair generateKeyPair_shortExp(){ | |||
| return generateKeyPair_shortExp(new SecureRandom()); | |||
| } | |||
| public static AsymmetricCipherKeyPair generateKeyPair_shortExp(SecureRandom random){ | |||
| AsymmetricCipherKeyPairGenerator kpGen = new RSAKeyPairGenerator(); | |||
| kpGen.init(new RSAKeyGenerationParameters(PUBEXP_0X03, random, KEYSIZEBITS, CERTAINTY)); | |||
| return kpGen.generateKeyPair(); | |||
| @@ -303,22 +319,16 @@ public class RSAUtils { | |||
| X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pubKeyBytes); | |||
| KeyFactory keyFactory = null; | |||
| try { | |||
| keyFactory = KeyFactory.getInstance("RSA"); | |||
| } catch (NoSuchAlgorithmException e) { | |||
| throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e); | |||
| } | |||
| KeyFactory keyFactory; | |||
| RSAPublicKey publicKey; | |||
| RSAPublicKey publicKey = null; | |||
| try { | |||
| keyFactory = KeyFactory.getInstance("RSA"); | |||
| publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec); | |||
| } catch (InvalidKeySpecException e) { | |||
| } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { | |||
| throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e); | |||
| } | |||
| assert publicKey != null; | |||
| BigInteger exponent = publicKey.getPublicExponent(); | |||
| BigInteger modulus = publicKey.getModulus(); | |||
| @@ -414,7 +424,7 @@ public class RSAUtils { | |||
| BigInteger qInv = privKey.getQInv(); | |||
| byte[] modulusBytes = bigInteger2Bytes(modulus,MODULUS_LENGTH); | |||
| byte[] pubExpBytes = pubExp.toByteArray(); | |||
| byte[] pubExpBytes = pubExp.toByteArray(); | |||
| byte[] privExpBytes = bigInteger2Bytes(privExp,PRIVEXP_LENGTH); | |||
| byte[] pBytes = bigInteger2Bytes(p,P_LENGTH); | |||
| byte[] qBytes = bigInteger2Bytes(q,Q_LENGTH); | |||
| @@ -446,22 +456,16 @@ public class RSAUtils { | |||
| PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyBytes); | |||
| KeyFactory keyFactory = null; | |||
| try { | |||
| keyFactory = KeyFactory.getInstance("RSA"); | |||
| } catch (NoSuchAlgorithmException e) { | |||
| throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e); | |||
| } | |||
| KeyFactory keyFactory; | |||
| RSAPrivateCrtKey privateKey; | |||
| try { | |||
| keyFactory = KeyFactory.getInstance("RSA"); | |||
| privateKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(keySpec); | |||
| } catch (InvalidKeySpecException e) { | |||
| } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { | |||
| throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e); | |||
| } | |||
| assert privateKey != null; | |||
| BigInteger modulus = privateKey.getModulus(); | |||
| BigInteger pubExp = privateKey.getPublicExponent(); | |||
| BigInteger privExp = privateKey.getPrivateExponent(); | |||
| @@ -524,7 +528,7 @@ public class RSAUtils { | |||
| result,0, length); | |||
| } else { | |||
| System.arraycopy(srcBytes,0, | |||
| result,length - srcLength, length); | |||
| result,length - srcLength, srcLength); | |||
| } | |||
| return result; | |||
| @@ -0,0 +1,49 @@ | |||
| package com.jd.blockchain.crypto.utils.classic; | |||
| import org.bouncycastle.crypto.params.AsymmetricKeyParameter; | |||
| import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil; | |||
| import org.bouncycastle.jce.spec.OpenSSHPublicKeySpec; | |||
| import org.bouncycastle.util.encoders.Base64; | |||
| /** | |||
| * @author zhanglin33 | |||
| * @title: SSHKeyParser | |||
| * @description: a parser for parsing asymmetric keys in Base64 format | |||
| * @date 2019-05-17, 17:52 | |||
| */ | |||
| public class SSHKeyParser { | |||
| private String pubKeyFormat; | |||
| private String pubKeyType; | |||
| public AsymmetricKeyParameter pubKeyParse(String pubKeyStr) { | |||
| byte[] pubKeyBytes; | |||
| if (pubKeyStr.startsWith("ssh") || pubKeyStr.startsWith("ecdsa")) { | |||
| String[] algoAndKeyAndLocal = pubKeyStr.split(" "); | |||
| pubKeyBytes = Base64.decode(algoAndKeyAndLocal[1]); | |||
| } else { | |||
| pubKeyBytes = Base64.decode(pubKeyStr); | |||
| } | |||
| OpenSSHPublicKeySpec pubKeySpec = new OpenSSHPublicKeySpec(pubKeyBytes); | |||
| pubKeyFormat = pubKeySpec.getFormat(); | |||
| pubKeyType = pubKeySpec.getType(); | |||
| return OpenSSHPublicKeyUtil.parsePublicKey(pubKeyBytes); | |||
| } | |||
| public String getPubKeyFormat() { | |||
| return pubKeyFormat; | |||
| } | |||
| public String getPubKeyType() { | |||
| return pubKeyType; | |||
| } | |||
| } | |||
| @@ -42,7 +42,7 @@ public class RSACryptoFunctionTest { | |||
| } | |||
| @Test | |||
| public void generateKeyPairTest() { | |||
| public void test() { | |||
| CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA"); | |||
| assertNotNull(algorithm); | |||
| @@ -55,15 +55,15 @@ public class RSACryptoFunctionTest { | |||
| PrivKey privKey = keyPair.getPrivKey(); | |||
| assertEquals(PUBLIC.CODE, pubKey.getKeyType().CODE); | |||
| assertEquals(257, pubKey.getRawKeyBytes().length); | |||
| assertEquals(259, pubKey.getRawKeyBytes().length); | |||
| assertEquals(PRIVATE.CODE, privKey.getKeyType().CODE); | |||
| assertEquals(1153, privKey.getRawKeyBytes().length); | |||
| assertEquals(1155, privKey.getRawKeyBytes().length); | |||
| assertEquals(algorithm.code(), pubKey.getAlgorithm()); | |||
| assertEquals(algorithm.code(), privKey.getAlgorithm()); | |||
| assertEquals(2 + 1 + 257, pubKey.toBytes().length); | |||
| assertEquals(2 + 1 + 1153, privKey.toBytes().length); | |||
| assertEquals(2 + 1 + 259, pubKey.toBytes().length); | |||
| assertEquals(2 + 1 + 1155, privKey.toBytes().length); | |||
| byte[] algoBytes = CryptoAlgorithm.getCodeBytes(algorithm); | |||
| byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE }; | |||
| @@ -72,20 +72,7 @@ public class RSACryptoFunctionTest { | |||
| 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); | |||
| @@ -93,23 +80,12 @@ public class RSACryptoFunctionTest { | |||
| 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]; | |||
| byte[] data = new byte[128]; | |||
| 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(); | |||
| @@ -121,48 +97,16 @@ public class RSACryptoFunctionTest { | |||
| 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(); | |||
| @@ -172,90 +116,32 @@ public class RSACryptoFunctionTest { | |||
| 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.getCodeBytes(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(1155, 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.getCodeBytes(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 { | |||
| @@ -265,64 +151,26 @@ public class RSACryptoFunctionTest { | |||
| } | |||
| 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.getCodeBytes(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(259, 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.getCodeBytes(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) { | |||
| @@ -330,57 +178,18 @@ public class RSACryptoFunctionTest { | |||
| } | |||
| 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.getCodeBytes(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); | |||
| @@ -392,12 +201,8 @@ public class RSACryptoFunctionTest { | |||
| algorithm = Crypto.getAlgorithm("ripemd160"); | |||
| assertNotNull(algorithm); | |||
| byte[] algoBytes = CryptoAlgorithm.getCodeBytes(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) { | |||
| @@ -405,77 +210,24 @@ public class RSACryptoFunctionTest { | |||
| } | |||
| 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.getCodeBytes(algorithm); | |||
| byte[] rawCiphertextBytes = ciphertext.toBytes(); | |||
| algoBytes = CryptoAlgorithm.getCodeBytes(algorithm); | |||
| 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.getCodeBytes(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) { | |||
| @@ -484,5 +236,4 @@ public class RSACryptoFunctionTest { | |||
| assertNotNull(actualEx); | |||
| assertTrue(expectedException.isAssignableFrom(actualEx.getClass())); | |||
| } | |||
| } | |||
| @@ -1,16 +1,22 @@ | |||
| package test.com.jd.blockchain.crypto.utils.classic; | |||
| import com.jd.blockchain.crypto.utils.classic.RSAUtils; | |||
| import org.bouncycastle.asn1.DERNull; | |||
| import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; | |||
| import org.bouncycastle.asn1.x509.AlgorithmIdentifier; | |||
| import org.bouncycastle.crypto.AsymmetricCipherKeyPair; | |||
| import org.bouncycastle.crypto.params.AsymmetricKeyParameter; | |||
| import org.bouncycastle.crypto.params.RSAKeyParameters; | |||
| import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; | |||
| import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; | |||
| import org.bouncycastle.util.encoders.Hex; | |||
| import org.junit.Test; | |||
| import javax.crypto.BadPaddingException; | |||
| import javax.crypto.Cipher; | |||
| import javax.crypto.IllegalBlockSizeException; | |||
| import javax.crypto.NoSuchPaddingException; | |||
| import java.io.IOException; | |||
| import java.security.*; | |||
| import java.security.interfaces.RSAPrivateKey; | |||
| import java.security.interfaces.RSAPublicKey; | |||
| @@ -27,10 +33,20 @@ import static org.junit.Assert.*; | |||
| public class RSAUtilsTest { | |||
| @Test | |||
| public void generateKeyPairTest(){ | |||
| public void generateKeyPairTest() { | |||
| AsymmetricCipherKeyPair kp = RSAUtils.generateKeyPair(); | |||
| RSAKeyParameters pubKey = (RSAKeyParameters) kp.getPublic(); | |||
| RSAPrivateCrtKeyParameters privKey = (RSAPrivateCrtKeyParameters) kp.getPrivate(); | |||
| keyPairTest(kp); | |||
| } | |||
| @Test | |||
| public void generateKeyPair_ShortExpTest() { | |||
| AsymmetricCipherKeyPair kp = RSAUtils.generateKeyPair_shortExp(); | |||
| keyPairTest(kp); | |||
| } | |||
| private void keyPairTest(AsymmetricCipherKeyPair keyPair) { | |||
| RSAKeyParameters pubKey = (RSAKeyParameters) keyPair.getPublic(); | |||
| RSAPrivateCrtKeyParameters privKey = (RSAPrivateCrtKeyParameters) keyPair.getPrivate(); | |||
| byte[] pubKeyBytes_RawKey = RSAUtils.pubKey2Bytes_RawKey(pubKey); | |||
| byte[] pubKeyBytesConverted_RawKey = | |||
| @@ -42,9 +58,6 @@ 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)); | |||
| @@ -67,7 +80,7 @@ public class RSAUtilsTest { | |||
| } | |||
| @Test | |||
| public void retrievePublicKeyTest(){ | |||
| public void test(){ | |||
| AsymmetricCipherKeyPair kp = RSAUtils.generateKeyPair(); | |||
| RSAKeyParameters pubKey = (RSAKeyParameters) kp.getPublic(); | |||
| @@ -78,38 +91,17 @@ public class RSAUtilsTest { | |||
| byte[] retrievedPubKeyBytes = RSAUtils.retrievePublicKey(privKeyBytes); | |||
| assertArrayEquals(pubKeyBytes,retrievedPubKeyBytes); | |||
| } | |||
| @Test | |||
| public void signTest(){ | |||
| byte[] data = new byte[1024]; | |||
| byte[] data = new byte[128]; | |||
| Random random = new Random(); | |||
| random.nextBytes(data); | |||
| AsymmetricCipherKeyPair keyPair = RSAUtils.generateKeyPair(); | |||
| AsymmetricKeyParameter privKey = keyPair.getPrivate(); | |||
| byte[] privKeyBytes = RSAUtils.privKey2Bytes_RawKey((RSAPrivateCrtKeyParameters) privKey); | |||
| byte[] signatureFromPrivKey = RSAUtils.sign(data, privKey); | |||
| byte[] signatureFromPrivKeyBytes = RSAUtils.sign(data, privKeyBytes); | |||
| assertNotNull(signatureFromPrivKey); | |||
| assertEquals(2048 / 8, signatureFromPrivKey.length); | |||
| assertArrayEquals(signatureFromPrivKeyBytes,signatureFromPrivKey); | |||
| } | |||
| @Test | |||
| public void verifyTest(){ | |||
| byte[] data = new byte[1024]; | |||
| Random random = new Random(); | |||
| random.nextBytes(data); | |||
| AsymmetricCipherKeyPair keyPair = RSAUtils.generateKeyPair(); | |||
| AsymmetricKeyParameter privKey = keyPair.getPrivate(); | |||
| AsymmetricKeyParameter pubKey = keyPair.getPublic(); | |||
| byte[] pubKeyBytes = RSAUtils.pubKey2Bytes_RawKey((RSAKeyParameters) pubKey); | |||
| byte[] signature = RSAUtils.sign(data,privKey); | |||
| @@ -118,47 +110,23 @@ public class RSAUtilsTest { | |||
| assertTrue(isValidFromPubKey); | |||
| assertTrue(isValidFromPubKeyBytes); | |||
| } | |||
| @Test | |||
| public void encryptTest(){ | |||
| byte[] data = new byte[246]; | |||
| Random random = new Random(); | |||
| random.nextBytes(data); | |||
| AsymmetricCipherKeyPair keyPair = RSAUtils.generateKeyPair(); | |||
| AsymmetricKeyParameter pubKey = keyPair.getPublic(); | |||
| byte[] pubKeyBytes = RSAUtils.pubKey2Bytes_RawKey((RSAKeyParameters) pubKey); | |||
| byte[] ciphertextFromPubKey = RSAUtils.encrypt(data,pubKey); | |||
| byte[] ciphertextFromPubKeyBytes = RSAUtils.encrypt(data,pubKeyBytes); | |||
| assertEquals(512,ciphertextFromPubKey.length); | |||
| assertEquals(512,ciphertextFromPubKeyBytes.length); | |||
| } | |||
| @Test | |||
| public void decryptTest(){ | |||
| assertEquals(256,ciphertextFromPubKey.length); | |||
| assertEquals(256,ciphertextFromPubKeyBytes.length); | |||
| AsymmetricCipherKeyPair keyPair = RSAUtils.generateKeyPair(); | |||
| AsymmetricKeyParameter pubKey = keyPair.getPublic(); | |||
| AsymmetricKeyParameter privKey = keyPair.getPrivate(); | |||
| byte[] privKeyBytes = RSAUtils.privKey2Bytes_RawKey((RSAPrivateCrtKeyParameters) privKey); | |||
| byte[] data; | |||
| for (int i = 1; i < 1024; i++) { | |||
| data = new byte[i]; | |||
| Random random = new Random(); | |||
| random.nextBytes(data); | |||
| byte[] ciphertext = RSAUtils.encrypt(data, pubKey); | |||
| data = new byte[1024]; | |||
| random.nextBytes(data); | |||
| byte[] ciphertext = RSAUtils.encrypt(data, pubKey); | |||
| byte[] plaintextFromPrivKey = RSAUtils.decrypt(ciphertext, privKey); | |||
| byte[] plaintextFromPrivKeyBytes = RSAUtils.decrypt(ciphertext, privKeyBytes); | |||
| byte[] plaintextFromPrivKey = RSAUtils.decrypt(ciphertext, privKey); | |||
| byte[] plaintextFromPrivKeyBytes = RSAUtils.decrypt(ciphertext, privKeyBytes); | |||
| assertArrayEquals(data, plaintextFromPrivKey); | |||
| assertArrayEquals(data, plaintextFromPrivKeyBytes); | |||
| } | |||
| assertArrayEquals(data, plaintextFromPrivKey); | |||
| assertArrayEquals(data, plaintextFromPrivKeyBytes); | |||
| } | |||
| @@ -0,0 +1,231 @@ | |||
| //package test.com.jd.blockchain.crypto.utils.classic; | |||
| // | |||
| //import com.jd.blockchain.crypto.utils.classic.SSHKeyParser; | |||
| //import org.bouncycastle.asn1.ASN1Sequence; | |||
| //import org.bouncycastle.crypto.params.RSAKeyParameters; | |||
| //import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; | |||
| //import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil; | |||
| //import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil; | |||
| //import org.bouncycastle.jce.spec.OpenSSHPrivateKeySpec; | |||
| //import org.bouncycastle.jce.spec.OpenSSHPublicKeySpec; | |||
| //import org.bouncycastle.util.Strings; | |||
| //import org.bouncycastle.util.encoders.Base64; | |||
| //import org.bouncycastle.util.encoders.Hex; | |||
| //import org.bouncycastle.util.io.pem.PemReader; | |||
| //import org.junit.Test; | |||
| // | |||
| //import java.io.IOException; | |||
| //import java.io.StringReader; | |||
| //import java.math.BigInteger; | |||
| // | |||
| //import static org.junit.Assert.assertEquals; | |||
| // | |||
| ///** | |||
| // * @author zhanglin33 | |||
| // * @title: SSHKeyUtilsTest | |||
| // * @description: Tests for methods in SSHKeyUtils | |||
| // * @date 2019-05-07, 15:14 | |||
| // */ | |||
| //public class SSHKeyUtilsTest { | |||
| // | |||
| // @Test | |||
| // public void parseRSAPublicKeyTest() { | |||
| // | |||
| // String pubKeyStr = "AAAAB3NzaC1yc2EAAAADAQABAAABAQCYwLN4EXy7g0Xugv4lQfoujbARi48gPSxVupt" + | |||
| // "GsSoGqsS00e9rA7v0qzFKa9Zhnw1WkjCnEXRYAMiCAJYkM/mGI8mb3qkcdNhGWZmPnopV+D46CTFB1" + | |||
| // "4yeR9mjoOPXs4pjX3zGveKx5Nx8jvdoFewbTCtdN0x1XWTjNT5bXqP/4gXkLENEU5tLsWVAOu0ME/N" + | |||
| // "e/9gMujAtDoolJ181a9P06bvEpIw5cLtUnsm5CtvBuiL7WBXxDJ/IASJrKNGBdK8xib1+Kb8tNLAT6" + | |||
| // "Dj25BwylqiRNhb5l1Ni4aKrE2FqSEc5Nx5+csQMEl9MBJ3pEsLHBNbohDL+jbwLguRVD6CJ"; | |||
| // | |||
| // BigInteger exponent = new BigInteger("010001",16); | |||
| // BigInteger modulus = new BigInteger("0098c0b378117cbb8345ee82fe2541fa2e8db0118b8f2" + | |||
| // "03d2c55ba9b46b12a06aac4b4d1ef6b03bbf4ab314a6bd6619f0d569230a711745800c88200962" + | |||
| // "433f98623c99bdea91c74d84659998f9e8a55f83e3a093141d78c9e47d9a3a0e3d7b38a635f7cc" + | |||
| // "6bde2b1e4dc7c8ef76815ec1b4c2b5d374c755d64e3353e5b5ea3ffe205e42c4344539b4bb1654" + | |||
| // "03aed0c13f35effd80cba302d0e8a25275f356bd3f4e9bbc4a48c3970bb549ec9b90adbc1ba22f" + | |||
| // "b5815f10c9fc801226b28d18174af3189bd7e29bf2d34b013e838f6e41c3296a8913616f997536" + | |||
| // "2e1a2ab13616a484739371e7e72c40c125f4c049de912c2c704d6e88432fe8dbc0b82e4550fa089",16); | |||
| // String pubKeyFormat = "OpenSSH"; | |||
| // String pubKeyType = "ssh-rsa"; | |||
| // | |||
| // SSHKeyParser parser = new SSHKeyParser(); | |||
| // | |||
| // RSAKeyParameters pubKey = (RSAKeyParameters) parser.pubKeyParse(pubKeyStr); | |||
| // BigInteger e = pubKey.getExponent(); | |||
| // BigInteger n = pubKey.getModulus(); | |||
| // assertEquals(exponent,e); | |||
| // assertEquals(modulus,n); | |||
| // assertEquals(pubKeyFormat,parser.getPubKeyFormat()); | |||
| // assertEquals(pubKeyType,parser.getPubKeyType()); | |||
| // | |||
| // String pubKeyStrWithHead = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCYwLN4EXy7g0Xugv4lQfou" + | |||
| // "jbARi48gPSxVuptGsSoGqsS00e9rA7v0qzFKa9Zhnw1WkjCnEXRYAMiCAJYkM/mGI8mb3qkcdNhGWZm" + | |||
| // "PnopV+D46CTFB14yeR9mjoOPXs4pjX3zGveKx5Nx8jvdoFewbTCtdN0x1XWTjNT5bXqP/4gXkLENEU5" + | |||
| // "tLsWVAOu0ME/Ne/9gMujAtDoolJ181a9P06bvEpIw5cLtUnsm5CtvBuiL7WBXxDJ/IASJrKNGBdK8xi" + | |||
| // "b1+Kb8tNLAT6Dj25BwylqiRNhb5l1Ni4aKrE2FqSEc5Nx5+csQMEl9MBJ3pEsLHBNbohDL+jbwLguRV" + | |||
| // "D6CJ zhanglin33@zhanglin33.local\n"; | |||
| // pubKey = (RSAKeyParameters) parser.pubKeyParse(pubKeyStrWithHead); | |||
| // e = pubKey.getExponent(); | |||
| // n = pubKey.getModulus(); | |||
| // assertEquals(exponent,e); | |||
| // assertEquals(modulus,n); | |||
| // assertEquals(pubKeyFormat,parser.getPubKeyFormat()); | |||
| // assertEquals(pubKeyType,parser.getPubKeyType()); | |||
| // } | |||
| // | |||
| // @Test | |||
| // public void parseRSAPrivateKeyTest() { | |||
| // | |||
| // String str2 = "-----BEGIN OPENSSH PRIVATE KEY-----\n" + | |||
| // "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\n" + | |||
| // "NhAAAAAwEAAQAAAQEAwFyeWgHFu/ZMvqWa28QUGlKMDV7vpbzT7kyA/4yuotfprZKHNeEy\n" + | |||
| // "GugleJ/Kv5kqHh8Km4IZcfNcerTYds+U5m/uX4bSYpEbXco3DQ2lYQbYo7PBWwPMq2aIdd\n" + | |||
| // "i7WxUAlt0z1ugLNimskPzJ7DNra+ax0Wh9RnMsjZkfuBZiKq7wbBm7NyJmpg2B7xo5cz+G\n" + | |||
| // "Lw9e0tDlvgeLe+n68WvYWWFP59mfP6Qoy+NwjQnnwrhJi2j4dEexO97KmgnJhL07lu4eCQ\n" + | |||
| // "fdv68Tai9+aeDNawe7nmFYf2eNjah2jW/DwOwA/ErXnvgjLSMsgc6WGKfokhytAOFDGgvH\n" + | |||
| // "KKNd6BMYZwAAA9A7JircOyYq3AAAAAdzc2gtcnNhAAABAQDAXJ5aAcW79ky+pZrbxBQaUo\n" + | |||
| // "wNXu+lvNPuTID/jK6i1+mtkoc14TIa6CV4n8q/mSoeHwqbghlx81x6tNh2z5Tmb+5fhtJi\n" + | |||
| // "kRtdyjcNDaVhBtijs8FbA8yrZoh12LtbFQCW3TPW6As2KayQ/MnsM2tr5rHRaH1GcyyNmR\n" + | |||
| // "+4FmIqrvBsGbs3ImamDYHvGjlzP4YvD17S0OW+B4t76frxa9hZYU/n2Z8/pCjL43CNCefC\n" + | |||
| // "uEmLaPh0R7E73sqaCcmEvTuW7h4JB92/rxNqL35p4M1rB7ueYVh/Z42NqHaNb8PA7AD8St\n" + | |||
| // "ee+CMtIyyBzpYYp+iSHK0A4UMaC8coo13oExhnAAAAAwEAAQAAAQAEEvIXnen+LR06/G7n\n" + | |||
| // "MKPsWss0jUouDG3AokYpI2WfdUsxreTHM1nIUBpbD6dPn4LQ2H91A7BeRXUz9BiRi5vvtX\n" + | |||
| // "cq9sQF6mTV+65mzF8wSuDTtr7lmpL/HlDNjiWJrEwy5cRvTMLQBtnsyC3OntgrlNs3QCtH\n" + | |||
| // "DrFm3lNZpr+1f62Vu43dbcTPvLwcc335cJ73BU5WsMGaouCAqVXsVsgfkA66u6+gQs8O3F\n" + | |||
| // "IQntdzS8vYpkzH8N9qqNZit7kbFCRUTI7CDLHquJmclzB8uVwO0pR5+Aross+YL3QxPZoJ\n" + | |||
| // "+LXLlCi27oSmYk3fx3uh0XwwO3JFDQpeCxOuEsZbOy8BAAAAgCsktFksS0BViRuLyzC2H7\n" + | |||
| // "X7Uonf+dr8e4Yn+RgR329KFh/ok28/KZndZHsUnhdmiIjPr+SplFZZMrV/uJDkGezUNWGf\n" + | |||
| // "8qn+eEglm7nYfVf2EXTVNhpg8yfPChx90ybc8GYlqpEqf7LiCuEBCPqPJgq6K7i6UKbwn2\n" + | |||
| // "SfqUOBcz5BAAAAgQDqszdiNv0cTvZ/Xg3qJPsHXqQuLBYoe2vhU+Pipt9HviruUD1y3Mso\n" + | |||
| // "rOL9QBwjE7szGnwVE00J0mLp+s309+kftADLXqMyqFYiy7S8GIWQw0YNB2m8yjq+phHbBm\n" + | |||
| // "/Gs2P4+s8yKTcVJvMTyWr02rpCHiLTKDHoXPJcJ8yVMTHFRwAAAIEA0dHB9fXiesEKfwcp\n" + | |||
| // "X11IHAV8pTd+7VN81oGwxtRg88U7H2rmQFCxSZah2O/OCCmYLH3PHT95qnMHHqzcsVvoIy\n" + | |||
| // "7AfnMpp4KYU0Ic3aFuRjZk2sDsYUniPcCpuCvs8Jb75sDwKDW2EM8MowiNylDnYMmfYj0l\n" + | |||
| // "gIhz1/p79hXEI+EAAAAbemhhbmdsaW4zM0B6aGFuZ2xpbjMzLmxvY2Fs\n" + | |||
| // "-----END OPENSSH PRIVATE KEY-----"; | |||
| // | |||
| // byte[] Bytes2 = null; | |||
| // try { | |||
| // Bytes2 = new PemReader(new StringReader(str2)).readPemObject().getContent(); | |||
| // } catch (IOException e1) { | |||
| // e1.printStackTrace(); | |||
| // } | |||
| // assert Bytes2 != null; | |||
| // System.out.println(Hex.toHexString(Bytes2)); | |||
| // | |||
| // String str3 = "-----BEGIN OPENSSH PRIVATE KEY-----\n" + | |||
| // "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\n" + | |||
| // "NhAAAAAwEAAQAAAQEAvummQZm1FUFc/cV5nQBeowhjX4vIU4kBmyPmXHMViX4ORvWvD1yi\n" + | |||
| // "oxcaawPpP9QconpzjdCrNbmw0oZNt9UKlmrOU34YTRD5LFlEVOYjr/21/SO5yDGog8xJBU\n" + | |||
| // "HQYnXY5L2q9EXKOF45e5P6gSGUovrhePEsaniuQN48GIObPCOFkEN0ZV2DqRsn3It1vY+D\n" + | |||
| // "GiSb5EaZ2sNkudyzYfgFxcCbqBXmDa1WeyX5xYh8wldBJLUH+pO4gPoTXXX4UI4yNdDmPD\n" + | |||
| // "BWFvPVIOdpfdBnDbEp1AoE5Jx/+tbwFBIEvTPOECtOUKDGIlXXIH0I4waHbwf6EnHD5+BR\n" + | |||
| // "N0XwrzSkuwAAA9DYV/7H2Ff+xwAAAAdzc2gtcnNhAAABAQC+6aZBmbUVQVz9xXmdAF6jCG\n" + | |||
| // "Nfi8hTiQGbI+ZccxWJfg5G9a8PXKKjFxprA+k/1ByienON0Ks1ubDShk231QqWas5TfhhN\n" + | |||
| // "EPksWURU5iOv/bX9I7nIMaiDzEkFQdBiddjkvar0Rco4Xjl7k/qBIZSi+uF48SxqeK5A3j\n" + | |||
| // "wYg5s8I4WQQ3RlXYOpGyfci3W9j4MaJJvkRpnaw2S53LNh+AXFwJuoFeYNrVZ7JfnFiHzC\n" + | |||
| // "V0EktQf6k7iA+hNddfhQjjI10OY8MFYW89Ug52l90GcNsSnUCgTknH/61vAUEgS9M84QK0\n" + | |||
| // "5QoMYiVdcgfQjjBodvB/oSccPn4FE3RfCvNKS7AAAAAwEAAQAAAQArRruxUy6BSvfRbtpK\n" + | |||
| // "hLLvMg+UsRMQHJaInHKzskLHkBOcckTkrpMPdUU/zPsqxOJY0nkvRIYK/7TdhCRJ77ker8\n" + | |||
| // "dllcfccGSLcRDUTfb5BgIjB94tS1Rvy/chgfHC4APyliwSg197t6BAKyM18m7HIyfJSqJO\n" + | |||
| // "4FxfyADHbc3aq654tu+eaUtD7TEN1bH6PKMDvwSioMLgKU43GQeDJZbqamBE9y+KVhVx9y\n" + | |||
| // "3DEHrOPkRkZIG33y9j7B/i0vl+WnwUTzmLGRR0U6J9wrzyANL8ODYaAvk4FvUED8hQ72jh\n" + | |||
| // "NpAXsSgf6COUE1sUnO5DOwN1zHBNHaSo73Qu7aKZtL4BAAAAgDBW3ItiqU9Ip34KtLaayK\n" + | |||
| // "/BkRDDwFNvAxpOw9alpfbLGF5xbVjRN4wy7HJ4eA+7JJnx6A6xYrzykbPP+dnUnfzYuxH8\n" + | |||
| // "MrihOkYipw1VaR6/0XH+apmE1SmotuYbl+bpl9dlZYUI0pJ8wldqoDCNlSOcLy77HnKwu9\n" + | |||
| // "GpJx9KmW9WAAAAgQDdnrwfVv5trAuZZIcw2vLRWhoDT196k/Ty1GP4zFpDttb8OyZ8Ygpx\n" + | |||
| // "oA5PhYyl5M1g/2oR/Rpp3vfKDVThfn/bCnMtAbUHMfvYK3Oufvq5JmzT1rgGr3MEek+JBR\n" + | |||
| // "O17I87m4GE7iM1LzCUs2G/fKt2uoVXdniv0Vn0iCiZZc7JmwAAAIEA3IdsccarkUfFcQ2c\n" + | |||
| // "4TdHrx/RGmoTAO6k1xOHXZjWPmerinuOspIJL/ymWfqIxABCjub3UHyP7ap+1+AAnk+TMU\n" + | |||
| // "eR3tLEp9tRM6n0Td56DnQ9Q+RZhPqR486/teZ33cMBMHg52aIs/3AzMpK9xTFCRgqsKa6e\n" + | |||
| // "ednMB4Q1txvHU2EAAAAbemhhbmdsaW4zM0B6aGFuZ2xpbjMzLmxvY2Fs\n" + | |||
| // "-----END OPENSSH PRIVATE KEY-----"; | |||
| // | |||
| // byte[] Bytes3 = null; | |||
| // try { | |||
| // Bytes3 = new PemReader(new StringReader(str3)).readPemObject().getContent(); | |||
| // } catch (IOException e1) { | |||
| // e1.printStackTrace(); | |||
| // } | |||
| // assert Bytes3 != null; | |||
| // System.out.println(Hex.toHexString(Bytes3)); | |||
| //// System.out.println(Hex.toHexString(Base64.decode("oNE9iA4ZyuZLbpEL7B29NaxGi4puT2Y5RDaMoEkoAKI"))); | |||
| //// String test = "1ac477fa"; | |||
| //// byte[] testBytes = Hex.decode(test); | |||
| //// | |||
| //// System.out.println(Base64.toBase64String(testBytes)); | |||
| // | |||
| // byte[] AUTH_MAGIC = Strings.toByteArray("openssh-key-v1\0"); | |||
| // System.out.println(Hex.toHexString(AUTH_MAGIC)); | |||
| // System.out.println(Base64.toBase64String(AUTH_MAGIC)); | |||
| // String privKeyStr = "-----BEGIN OPENSSH PRIVATE KEY-----\n" + | |||
| // "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\n" + | |||
| // "NhAAAAAwEAAQAAAQEAmMCzeBF8u4NF7oL+JUH6Lo2wEYuPID0sVbqbRrEqBqrEtNHvawO7\n" + | |||
| // "9KsxSmvWYZ8NVpIwpxF0WADIggCWJDP5hiPJm96pHHTYRlmZj56KVfg+OgkxQdeMnkfZo6\n" + | |||
| // "Dj17OKY198xr3iseTcfI73aBXsG0wrXTdMdV1k4zU+W16j/+IF5CxDRFObS7FlQDrtDBPz\n" + | |||
| // "Xv/YDLowLQ6KJSdfNWvT9Om7xKSMOXC7VJ7JuQrbwboi+1gV8QyfyAEiayjRgXSvMYm9fi\n" + | |||
| // "m/LTSwE+g49uQcMpaokTYW+ZdTYuGiqxNhakhHOTcefnLEDBJfTASd6RLCxwTW6IQy/o28\n" + | |||
| // "C4LkVQ+giQAAA9AaxHf6GsR3+gAAAAdzc2gtcnNhAAABAQCYwLN4EXy7g0Xugv4lQfoujb\n" + | |||
| // "ARi48gPSxVuptGsSoGqsS00e9rA7v0qzFKa9Zhnw1WkjCnEXRYAMiCAJYkM/mGI8mb3qkc\n" + | |||
| // "dNhGWZmPnopV+D46CTFB14yeR9mjoOPXs4pjX3zGveKx5Nx8jvdoFewbTCtdN0x1XWTjNT\n" + | |||
| // "5bXqP/4gXkLENEU5tLsWVAOu0ME/Ne/9gMujAtDoolJ181a9P06bvEpIw5cLtUnsm5CtvB\n" + | |||
| // "uiL7WBXxDJ/IASJrKNGBdK8xib1+Kb8tNLAT6Dj25BwylqiRNhb5l1Ni4aKrE2FqSEc5Nx\n" + | |||
| // "5+csQMEl9MBJ3pEsLHBNbohDL+jbwLguRVD6CJAAAAAwEAAQAAAQARfhfPSylei9TpUGTs\n" + | |||
| // "PVb6F82u5K16QqceFiWL/ePTKaEnF9d0CNRwW15kqF6/hShQ3qLlrvEE1uofQRPwh2cuvl\n" + | |||
| // "BrIh95m8PcoowcT0qGN8xgdwcGBDodMhsxSs5suCnD4X53f+1C8/Nv7CtW5xPHuHxKy3dd\n" + | |||
| // "BVn1TvaaHgdn2PwJVKtZp+WVG3/UHr25nFHd8mYgpeHZqK9AW16N0UEMXMM1u8ZCubVOoS\n" + | |||
| // "IGuMAXpTug0xA+BXHo17FcDGKSzcXFzh+urIz5glRp5zFioHBqxNmkKfQkG6C7UxnPGyS/\n" + | |||
| // "/J+3lL2lvl0G8kO/5EDFMBhTMEy1NeR2b629S4G1qUxVAAAAgHDwE9kPiVETcxSzI4wotT\n" + | |||
| // "1Ee9nKVVD3oGdRqefvX7EUR8bvdv4nCqHPNBx8C6l8zo7fsQD81YL85F4eWbtrdxEijRHX\n" + | |||
| // "5m7J/muh/laY1Hq43WCkZGboO4fZ2HHi7oN096FqrKRpvbQGQi1FLbcISUdsitwrs6ywn3\n" + | |||
| // "fNx3q+X3V6AAAAgQDJRo9v+0QvldI33cpJKPKiaop5QvfIDzMatD3vLA1qqycgIi4KOtb5\n" + | |||
| // "+LP/jgIpCYah/sk+JpKNz/vsZmZmrfaVu9D3Le2LLBgMpEoSO8jOe9WGI4Ew75C7w7AZCa\n" + | |||
| // "SyUnHIVX/9D8Y5tx4cKx6Im9AGbNF35XZoKO4KCk5VMTXhnwAAAIEAwkjKIpTYdeAQVTRf\n" + | |||
| // "C13kg84Bu5n4WkiLnp1WOCg2GN5RekqprINtpjIMZoB9Fv292Np99La8yvmRoy5qzNHGdm\n" + | |||
| // "Q6AMku8jP123jF2J+wDvF714VtZHNvdCYBGJS+rZ81xtJfHhKtZqRAVtbPertOWZeuRm9V\n" + | |||
| // "o+/rEuEzgGYGXNcAAAAbemhhbmdsaW4zM0B6aGFuZ2xpbjMzLmxvY2Fs\n" + | |||
| // "-----END OPENSSH PRIVATE KEY-----"; | |||
| // | |||
| // byte[] privKeyBytes = null; | |||
| // try { | |||
| // privKeyBytes = new PemReader(new StringReader(privKeyStr)).readPemObject().getContent(); | |||
| // } catch (IOException e1) { | |||
| // e1.printStackTrace(); | |||
| // } | |||
| // | |||
| // assert privKeyBytes != null; | |||
| // System.out.println(Hex.toHexString(privKeyBytes)); | |||
| // | |||
| // | |||
| // OpenSSHPrivateKeySpec privKeySpec = new OpenSSHPrivateKeySpec(privKeyBytes); | |||
| // | |||
| // String privKeyFormat = privKeySpec.getFormat(); | |||
| // System.out.println(privKeyFormat); | |||
| // | |||
| // RSAKeyParameters privKey = (RSAKeyParameters) OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(privKeyBytes); | |||
| // | |||
| //// BigInteger e = privKey.getPublicExponent(); | |||
| //// BigInteger n = privKey.getModulus(); | |||
| //// | |||
| //// BigInteger d = privKey.getExponent(); | |||
| //// BigInteger p = privKey.getP(); | |||
| //// BigInteger q = privKey.getQ(); | |||
| //// BigInteger dP = privKey.getDP(); | |||
| //// BigInteger dQ = privKey.getDQ(); | |||
| //// BigInteger qInv = privKey.getQInv(); | |||
| // | |||
| //// System.out.println(Hex.toHexString(e.toByteArray())); | |||
| //// System.out.println(Hex.toHexString(n.toByteArray())); | |||
| //// | |||
| //// System.out.println(Hex.toHexString(d.toByteArray())); | |||
| //// System.out.println(Hex.toHexString(p.toByteArray())); | |||
| //// System.out.println(Hex.toHexString(q.toByteArray())); | |||
| //// System.out.println(Hex.toHexString(dP.toByteArray())); | |||
| //// System.out.println(Hex.toHexString(dQ.toByteArray())); | |||
| //// System.out.println(Hex.toHexString(qInv.toByteArray())); | |||
| // | |||
| // | |||
| // | |||
| // } | |||
| // | |||
| //} | |||
| @@ -106,6 +106,44 @@ public final class Crypto { | |||
| private Crypto() { | |||
| } | |||
| public static CryptoProvider[] getProviders() { | |||
| Collection<Provider<CryptoService>> providers = pm.getAllProviders(CryptoService.class); | |||
| CryptoProvider[] infos = new CryptoProvider[providers.size()]; | |||
| int i = 0; | |||
| for (Provider<CryptoService> pd : providers) { | |||
| CryptoProviderInfo info = getProviderInfo(pd); | |||
| infos[i] = info; | |||
| } | |||
| return infos; | |||
| } | |||
| private static CryptoProviderInfo getProviderInfo(Provider<CryptoService> pd) { | |||
| Collection<CryptoFunction> functions = pd.getService().getFunctions(); | |||
| CryptoAlgorithm[] algorithms = new CryptoAlgorithm[functions.size()]; | |||
| int i = 0; | |||
| for (CryptoFunction function : functions) { | |||
| algorithms[i] = function.getAlgorithm(); | |||
| i++; | |||
| } | |||
| return new CryptoProviderInfo(pd.getFullName(), algorithms); | |||
| } | |||
| /** | |||
| * 返回指定名称的密码服务提供者;如果不存在,则返回 null ; | |||
| * | |||
| * @param providerFullName | |||
| * @return | |||
| */ | |||
| public static CryptoProvider getProvider(String providerFullName) { | |||
| Provider<CryptoService> pd = pm.getProvider(CryptoService.class, providerFullName); | |||
| if (pd == null) { | |||
| throw new CryptoException("Crypto service provider named [" + providerFullName + "] does not exist!"); | |||
| } | |||
| return getProviderInfo(pd); | |||
| } | |||
| public static Collection<CryptoAlgorithm> getAllAlgorithms() { | |||
| return algorithms.values(); | |||
| } | |||
| @@ -9,7 +9,7 @@ import com.jd.blockchain.binaryproto.PrimitiveType; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| //@DataContract(code = DataCodes.CRYPTO_ALGORITHM) | |||
| @DataContract(code = DataCodes.CRYPTO_ALGORITHM) | |||
| public interface CryptoAlgorithm { | |||
| /** | |||
| @@ -63,7 +63,7 @@ public interface CryptoAlgorithm { | |||
| * {@link #EXT_ALGORITHM}) 5 种); 接下来4位标识密钥类型(包括:{@link #SYMMETRIC_KEY}, | |||
| * {@link #ASYMMETRIC_KEY}); 最后8位是算法唯一ID; | |||
| */ | |||
| // @DataField(primitiveType = PrimitiveType.INT16, order = 0) | |||
| @DataField(order = 0, primitiveType = PrimitiveType.INT16) | |||
| short code(); | |||
| /** | |||
| @@ -75,7 +75,13 @@ public interface CryptoAlgorithm { | |||
| * | |||
| * @return | |||
| */ | |||
| @DataField(order = 1, primitiveType = PrimitiveType.TEXT) | |||
| String name(); | |||
| public static String getString(CryptoAlgorithm algorithm) { | |||
| return String.format("%s[%s]", algorithm.name(), (algorithm.code() & 0xFFFF)); | |||
| } | |||
| /** | |||
| * | |||
| @@ -23,16 +23,14 @@ public final class CryptoAlgorithmDefinition implements CryptoAlgorithm { | |||
| @Override | |||
| public String toString() { | |||
| return name + "[" + (code & 0xFFFF) + "]"; | |||
| return CryptoAlgorithm.getString(this); | |||
| } | |||
| /** | |||
| * 声明一项哈希算法; | |||
| * | |||
| * @param name | |||
| * 算法名称; | |||
| * @param uid | |||
| * 算法ID;需要在同类算法中保持唯一性; | |||
| * @param name 算法名称; | |||
| * @param uid 算法ID;需要在同类算法中保持唯一性; | |||
| * @return | |||
| */ | |||
| public static CryptoAlgorithm defineHash(String name, byte uid) { | |||
| @@ -43,10 +41,8 @@ public final class CryptoAlgorithmDefinition implements CryptoAlgorithm { | |||
| /** | |||
| * 声明一项非对称密码算法; | |||
| * | |||
| * @param name | |||
| * 算法名称; | |||
| * @param uid | |||
| * 算法ID;需要在同类算法中保持唯一性; | |||
| * @param name 算法名称; | |||
| * @param uid 算法ID;需要在同类算法中保持唯一性; | |||
| * @return | |||
| */ | |||
| public static CryptoAlgorithm defineSignature(String name, boolean encryptable, byte uid) { | |||
| @@ -62,10 +58,8 @@ public final class CryptoAlgorithmDefinition implements CryptoAlgorithm { | |||
| /** | |||
| * 声明一项非对称加密算法; | |||
| * | |||
| * @param name | |||
| * 算法名称; | |||
| * @param uid | |||
| * 算法ID;需要在同类算法中保持唯一性; | |||
| * @param name 算法名称; | |||
| * @param uid 算法ID;需要在同类算法中保持唯一性; | |||
| * @return | |||
| */ | |||
| public static CryptoAlgorithm defineAsymmetricEncryption(String name, byte uid) { | |||
| @@ -76,10 +70,8 @@ public final class CryptoAlgorithmDefinition implements CryptoAlgorithm { | |||
| /** | |||
| * 声明一项对称密码算法; | |||
| * | |||
| * @param name | |||
| * 算法名称; | |||
| * @param uid | |||
| * 算法ID;需要在同类算法中保持唯一性; | |||
| * @param name 算法名称; | |||
| * @param uid 算法ID;需要在同类算法中保持唯一性; | |||
| * @return | |||
| */ | |||
| public static CryptoAlgorithm defineSymmetricEncryption(String name, byte uid) { | |||
| @@ -90,10 +82,8 @@ public final class CryptoAlgorithmDefinition implements CryptoAlgorithm { | |||
| /** | |||
| * 声明一项随机数算法; | |||
| * | |||
| * @param name | |||
| * 算法名称; | |||
| * @param uid | |||
| * 算法ID;需要在同类算法中保持唯一性; | |||
| * @param name 算法名称; | |||
| * @param uid 算法ID;需要在同类算法中保持唯一性; | |||
| * @return | |||
| */ | |||
| public static CryptoAlgorithm defineRandom(String name, byte uid) { | |||
| @@ -104,10 +94,8 @@ public final class CryptoAlgorithmDefinition implements CryptoAlgorithm { | |||
| /** | |||
| * 声明一项扩展的密码算法; | |||
| * | |||
| * @param name | |||
| * 算法名称; | |||
| * @param uid | |||
| * 算法ID;需要在同类算法中保持唯一性; | |||
| * @param name 算法名称; | |||
| * @param uid 算法ID;需要在同类算法中保持唯一性; | |||
| * @return | |||
| */ | |||
| public static CryptoAlgorithm definExt(String name, byte uid) { | |||
| @@ -0,0 +1,17 @@ | |||
| package com.jd.blockchain.crypto; | |||
| import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.binaryproto.DataField; | |||
| import com.jd.blockchain.binaryproto.PrimitiveType; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| @DataContract(code = DataCodes.METADATA_CRYPTO_SETTING_PROVIDER) | |||
| public interface CryptoProvider { | |||
| @DataField(order = 0, primitiveType = PrimitiveType.TEXT) | |||
| String getName(); | |||
| @DataField(order = 1, list = true, refContract = true) | |||
| CryptoAlgorithm[] getAlgorithms(); | |||
| } | |||
| @@ -0,0 +1,24 @@ | |||
| package com.jd.blockchain.crypto; | |||
| class CryptoProviderInfo implements CryptoProvider { | |||
| private String name; | |||
| private CryptoAlgorithm[] algorithms; | |||
| public CryptoProviderInfo(String name, CryptoAlgorithm[] algorithms) { | |||
| this.name = name; | |||
| this.algorithms = algorithms; | |||
| } | |||
| @Override | |||
| public String getName() { | |||
| return name; | |||
| } | |||
| @Override | |||
| public CryptoAlgorithm[] getAlgorithms() { | |||
| return algorithms.clone(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,34 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | |||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |||
| <parent> | |||
| <artifactId>crypto</artifactId> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <version>0.9.0-SNAPSHOT</version> | |||
| </parent> | |||
| <modelVersion>4.0.0</modelVersion> | |||
| <artifactId>crypto-pki</artifactId> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>crypto-framework</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.bouncycastle</groupId> | |||
| <artifactId>bcprov-jdk15on</artifactId> | |||
| <version>1.61</version> | |||
| </dependency> | |||
| <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on --> | |||
| <dependency> | |||
| <groupId>org.bouncycastle</groupId> | |||
| <artifactId>bcpkix-jdk15on</artifactId> | |||
| <version>1.61</version> | |||
| </dependency> | |||
| </dependencies> | |||
| </project> | |||
| @@ -0,0 +1,26 @@ | |||
| package com.jd.blockchain.crypto.service.pki; | |||
| import com.jd.blockchain.crypto.CryptoAlgorithm; | |||
| import com.jd.blockchain.crypto.CryptoAlgorithmDefinition; | |||
| /** | |||
| * @author zhanglin33 | |||
| * @title: PKIAlgorithm | |||
| * @description: TODO | |||
| * @date 2019-05-15, 16:34 | |||
| */ | |||
| public class PKIAlgorithm { | |||
| public static final CryptoAlgorithm SHA1WITHRSA2048 = CryptoAlgorithmDefinition.defineSignature("SHA1WITHRSA2048", | |||
| false, (byte) 31); | |||
| public static final CryptoAlgorithm SHA1WITHRSA4096 = CryptoAlgorithmDefinition.defineSignature("SHA1WITHRSA4096", | |||
| false, (byte) 32); | |||
| public static final CryptoAlgorithm SM3WITHSM2 = CryptoAlgorithmDefinition.defineSignature("SM3WITHSM2", | |||
| false, (byte) 33); | |||
| private PKIAlgorithm() { | |||
| } | |||
| } | |||
| @@ -0,0 +1,38 @@ | |||
| package com.jd.blockchain.crypto.service.pki; | |||
| import com.jd.blockchain.crypto.CryptoFunction; | |||
| import com.jd.blockchain.crypto.CryptoService; | |||
| import com.jd.blockchain.provider.NamedProvider; | |||
| import java.util.Arrays; | |||
| import java.util.Collection; | |||
| import java.util.Collections; | |||
| import java.util.List; | |||
| /** | |||
| * @author zhanglin33 | |||
| * @title: PKICryptoService | |||
| * @description: TODO | |||
| * @date 2019-05-15, 16:35 | |||
| */ | |||
| @NamedProvider("PKI-SOFTWARE") | |||
| public class PKICryptoService implements CryptoService { | |||
| public static final SHA1WITHRSA2048SignatureFunction SHA1WITHRSA2048 = new SHA1WITHRSA2048SignatureFunction(); | |||
| public static final SHA1WITHRSA4096SignatureFunction SHA1WITHRSA4096 = new SHA1WITHRSA4096SignatureFunction(); | |||
| public static final SM3WITHSM2SignatureFunction SM3WITHSM2 = new SM3WITHSM2SignatureFunction(); | |||
| private static final Collection<CryptoFunction> FUNCTIONS; | |||
| static { | |||
| List<CryptoFunction> funcs = Arrays.asList(SHA1WITHRSA2048, SHA1WITHRSA4096, SM3WITHSM2); | |||
| FUNCTIONS = Collections.unmodifiableList(funcs); | |||
| } | |||
| @Override | |||
| public Collection<CryptoFunction> getFunctions() { | |||
| return FUNCTIONS; | |||
| } | |||
| } | |||
| @@ -0,0 +1,220 @@ | |||
| package com.jd.blockchain.crypto.service.pki; | |||
| import com.jd.blockchain.crypto.*; | |||
| import org.bouncycastle.asn1.DERNull; | |||
| import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; | |||
| import org.bouncycastle.asn1.x509.AlgorithmIdentifier; | |||
| import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; | |||
| import org.bouncycastle.jce.provider.BouncyCastleProvider; | |||
| import java.math.BigInteger; | |||
| import java.security.*; | |||
| import java.security.interfaces.RSAPrivateCrtKey; | |||
| import java.security.interfaces.RSAPublicKey; | |||
| import java.security.spec.InvalidKeySpecException; | |||
| import java.security.spec.PKCS8EncodedKeySpec; | |||
| import java.security.spec.X509EncodedKeySpec; | |||
| import static com.jd.blockchain.crypto.BaseCryptoKey.KEY_TYPE_BYTES; | |||
| import static com.jd.blockchain.crypto.CryptoBytes.ALGORYTHM_CODE_SIZE; | |||
| import static com.jd.blockchain.crypto.CryptoKeyType.PRIVATE; | |||
| import static com.jd.blockchain.crypto.CryptoKeyType.PUBLIC; | |||
| import static com.jd.blockchain.crypto.service.pki.PKIAlgorithm.SHA1WITHRSA2048; | |||
| /** | |||
| * @author zhanglin33 | |||
| * @title: SHA1WITHRSA2048SignatureFunction | |||
| * @description: TODO | |||
| * @date 2019-05-15, 16:37 | |||
| */ | |||
| public class SHA1WITHRSA2048SignatureFunction implements SignatureFunction { | |||
| private static final int RAW_PUBKEY_SIZE = 259; | |||
| private static final int RAW_PRIVKEY_SIZE = 1155; | |||
| private static final int RAW_SIGNATUREDIGEST_SIZE = 256; | |||
| private static final AlgorithmIdentifier RSA_ALGORITHM_IDENTIFIER = | |||
| new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE); | |||
| @Override | |||
| public SignatureDigest sign(PrivKey privKey, byte[] data) { | |||
| byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||
| if (rawPrivKeyBytes.length < RAW_PRIVKEY_SIZE) { | |||
| throw new CryptoException("This key has wrong format!"); | |||
| } | |||
| if (privKey.getAlgorithm() != SHA1WITHRSA2048.code()) { | |||
| throw new CryptoException("This key is not SHA1WITHRSA2048 private key!"); | |||
| } | |||
| PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(rawPrivKeyBytes); | |||
| KeyFactory keyFactory; | |||
| RSAPrivateCrtKey rawPrivKey; | |||
| Signature signer; | |||
| byte[] signature; | |||
| try { | |||
| keyFactory = KeyFactory.getInstance("RSA"); | |||
| rawPrivKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(keySpec); | |||
| signer = Signature.getInstance("SHA1withRSA"); | |||
| signer.initSign(rawPrivKey); | |||
| signer.update(data); | |||
| signature = signer.sign(); | |||
| } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | InvalidKeySpecException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| return new SignatureDigest(SHA1WITHRSA2048, signature); | |||
| } | |||
| @Override | |||
| public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) { | |||
| byte[] rawPubKeyBytes = pubKey.getRawKeyBytes(); | |||
| byte[] rawDigestBytes = digest.getRawDigest(); | |||
| if (rawPubKeyBytes.length < RAW_PUBKEY_SIZE) { | |||
| throw new CryptoException("This key has wrong format!"); | |||
| } | |||
| if (pubKey.getAlgorithm() != SHA1WITHRSA2048.code()) { | |||
| throw new CryptoException("This key is not SHA1WITHRSA2048 public key!"); | |||
| } | |||
| if (digest.getAlgorithm() != SHA1WITHRSA2048.code() || rawDigestBytes.length != RAW_SIGNATUREDIGEST_SIZE) { | |||
| throw new CryptoException("This is not SHA1WITHRSA2048 signature digest!"); | |||
| } | |||
| X509EncodedKeySpec keySpec = new X509EncodedKeySpec(rawPubKeyBytes); | |||
| KeyFactory keyFactory; | |||
| RSAPublicKey rawPubKey; | |||
| Signature verifier; | |||
| boolean isValid; | |||
| try { | |||
| keyFactory = KeyFactory.getInstance("RSA"); | |||
| rawPubKey = (RSAPublicKey) keyFactory.generatePublic(keySpec); | |||
| verifier = Signature.getInstance("SHA1withRSA"); | |||
| verifier.initVerify(rawPubKey); | |||
| verifier.update(data); | |||
| isValid = verifier.verify(rawDigestBytes); | |||
| } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | InvalidKeySpecException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| return isValid; | |||
| } | |||
| @Override | |||
| public boolean supportPubKey(byte[] pubKeyBytes) { | |||
| return pubKeyBytes.length > (ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + RAW_PUBKEY_SIZE) | |||
| && CryptoAlgorithm.match(SHA1WITHRSA2048, pubKeyBytes) | |||
| && pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE; | |||
| } | |||
| @Override | |||
| public PubKey resolvePubKey(byte[] pubKeyBytes) { | |||
| if (supportPubKey(pubKeyBytes)) { | |||
| return new PubKey(pubKeyBytes); | |||
| } else { | |||
| throw new CryptoException("pubKeyBytes are invalid!"); | |||
| } | |||
| } | |||
| @Override | |||
| public boolean supportPrivKey(byte[] privKeyBytes) { | |||
| return privKeyBytes.length > (ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + RAW_PRIVKEY_SIZE) | |||
| && CryptoAlgorithm.match(SHA1WITHRSA2048, privKeyBytes) | |||
| && privKeyBytes[ALGORYTHM_CODE_SIZE] == PRIVATE.CODE; | |||
| } | |||
| @Override | |||
| public PrivKey resolvePrivKey(byte[] privKeyBytes) { | |||
| if (supportPrivKey(privKeyBytes)) { | |||
| return new PrivKey(privKeyBytes); | |||
| } else { | |||
| throw new CryptoException("privKeyBytes are invalid!"); | |||
| } | |||
| } | |||
| @Override | |||
| public PubKey retrievePubKey(PrivKey privKey) { | |||
| byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||
| if (rawPrivKeyBytes.length < RAW_PRIVKEY_SIZE) { | |||
| throw new CryptoException("This key has wrong format!"); | |||
| } | |||
| if (privKey.getAlgorithm() != SHA1WITHRSA2048.code()) { | |||
| throw new CryptoException("This key is not SHA1WITHRSA2048 private key!"); | |||
| } | |||
| PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(rawPrivKeyBytes); | |||
| KeyFactory keyFactory; | |||
| RSAPrivateCrtKey rawPrivKey; | |||
| byte[] rawPubKeyBytes; | |||
| try { | |||
| keyFactory = KeyFactory.getInstance("RSA"); | |||
| rawPrivKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(keySpec); | |||
| BigInteger modulus = rawPrivKey.getModulus(); | |||
| BigInteger exponent = rawPrivKey.getPublicExponent(); | |||
| rawPubKeyBytes = KeyUtil.getEncodedSubjectPublicKeyInfo(RSA_ALGORITHM_IDENTIFIER, | |||
| new org.bouncycastle.asn1.pkcs.RSAPublicKey(modulus, exponent)); | |||
| } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| return new PubKey(SHA1WITHRSA2048, rawPubKeyBytes); | |||
| } | |||
| @Override | |||
| public boolean supportDigest(byte[] digestBytes) { | |||
| return digestBytes.length == (RAW_SIGNATUREDIGEST_SIZE + ALGORYTHM_CODE_SIZE) | |||
| && CryptoAlgorithm.match(SHA1WITHRSA2048, digestBytes); | |||
| } | |||
| @Override | |||
| public SignatureDigest resolveDigest(byte[] digestBytes) { | |||
| if (supportDigest(digestBytes)) { | |||
| return new SignatureDigest(digestBytes); | |||
| } else { | |||
| throw new CryptoException("digestBytes are invalid!"); | |||
| } | |||
| } | |||
| @Override | |||
| public AsymmetricKeypair generateKeypair() { | |||
| Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); | |||
| KeyPairGenerator generator; | |||
| PublicKey pubKey; | |||
| PrivateKey privKey; | |||
| try { | |||
| generator = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME); | |||
| generator.initialize(2048); | |||
| KeyPair keyPair = generator.generateKeyPair(); | |||
| pubKey = keyPair.getPublic(); | |||
| privKey = keyPair.getPrivate(); | |||
| } catch (NoSuchAlgorithmException | NoSuchProviderException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| byte[] pubKeyBytes = pubKey.getEncoded(); | |||
| byte[] privKeyBytes = privKey.getEncoded(); | |||
| return new AsymmetricKeypair(new PubKey(SHA1WITHRSA2048, pubKeyBytes), | |||
| new PrivKey(SHA1WITHRSA2048, privKeyBytes)); | |||
| } | |||
| @Override | |||
| public CryptoAlgorithm getAlgorithm() { | |||
| return SHA1WITHRSA2048; | |||
| } | |||
| } | |||
| @@ -0,0 +1,220 @@ | |||
| package com.jd.blockchain.crypto.service.pki; | |||
| import com.jd.blockchain.crypto.*; | |||
| import org.bouncycastle.asn1.DERNull; | |||
| import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; | |||
| import org.bouncycastle.asn1.x509.AlgorithmIdentifier; | |||
| import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; | |||
| import org.bouncycastle.jce.provider.BouncyCastleProvider; | |||
| import java.math.BigInteger; | |||
| import java.security.*; | |||
| import java.security.interfaces.RSAPrivateCrtKey; | |||
| import java.security.interfaces.RSAPublicKey; | |||
| import java.security.spec.InvalidKeySpecException; | |||
| import java.security.spec.PKCS8EncodedKeySpec; | |||
| import java.security.spec.X509EncodedKeySpec; | |||
| import static com.jd.blockchain.crypto.BaseCryptoKey.KEY_TYPE_BYTES; | |||
| import static com.jd.blockchain.crypto.CryptoBytes.ALGORYTHM_CODE_SIZE; | |||
| import static com.jd.blockchain.crypto.CryptoKeyType.PRIVATE; | |||
| import static com.jd.blockchain.crypto.CryptoKeyType.PUBLIC; | |||
| import static com.jd.blockchain.crypto.service.pki.PKIAlgorithm.SHA1WITHRSA4096; | |||
| /** | |||
| * @author zhanglin33 | |||
| * @title: SHA1WITHRSA4096SignatureFunction | |||
| * @description: TODO | |||
| * @date 2019-05-15, 17:13 | |||
| */ | |||
| public class SHA1WITHRSA4096SignatureFunction implements SignatureFunction { | |||
| private static final int RAW_PUBKEY_SIZE = 515; | |||
| private static final int RAW_PRIVKEY_SIZE = 2307; | |||
| private static final int RAW_SIGNATUREDIGEST_SIZE = 512; | |||
| private static final AlgorithmIdentifier RSA_ALGORITHM_IDENTIFIER = | |||
| new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE); | |||
| @Override | |||
| public SignatureDigest sign(PrivKey privKey, byte[] data) { | |||
| byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||
| if (rawPrivKeyBytes.length < RAW_PRIVKEY_SIZE) { | |||
| throw new CryptoException("This key has wrong format!"); | |||
| } | |||
| if (privKey.getAlgorithm() != SHA1WITHRSA4096.code()) { | |||
| throw new CryptoException("This key is not SHA1WITHRSA4096 private key!"); | |||
| } | |||
| PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(rawPrivKeyBytes); | |||
| KeyFactory keyFactory; | |||
| RSAPrivateCrtKey rawPrivKey; | |||
| Signature signer; | |||
| byte[] signature; | |||
| try { | |||
| keyFactory = KeyFactory.getInstance("RSA"); | |||
| rawPrivKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(keySpec); | |||
| signer = Signature.getInstance("SHA1withRSA"); | |||
| signer.initSign(rawPrivKey); | |||
| signer.update(data); | |||
| signature = signer.sign(); | |||
| } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | InvalidKeySpecException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| return new SignatureDigest(SHA1WITHRSA4096, signature); | |||
| } | |||
| @Override | |||
| public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) { | |||
| byte[] rawPubKeyBytes = pubKey.getRawKeyBytes(); | |||
| byte[] rawDigestBytes = digest.getRawDigest(); | |||
| if (rawPubKeyBytes.length < RAW_PUBKEY_SIZE) { | |||
| throw new CryptoException("This key has wrong format!"); | |||
| } | |||
| if (pubKey.getAlgorithm() != SHA1WITHRSA4096.code()) { | |||
| throw new CryptoException("This key is not SHA1WITHRSA4096 public key!"); | |||
| } | |||
| if (digest.getAlgorithm() != SHA1WITHRSA4096.code() || rawDigestBytes.length != RAW_SIGNATUREDIGEST_SIZE) { | |||
| throw new CryptoException("This is not SHA1WITHRSA4096 signature digest!"); | |||
| } | |||
| X509EncodedKeySpec keySpec = new X509EncodedKeySpec(rawPubKeyBytes); | |||
| KeyFactory keyFactory; | |||
| RSAPublicKey rawPubKey; | |||
| Signature verifier; | |||
| boolean isValid; | |||
| try { | |||
| keyFactory = KeyFactory.getInstance("RSA"); | |||
| rawPubKey = (RSAPublicKey) keyFactory.generatePublic(keySpec); | |||
| verifier = Signature.getInstance("SHA1withRSA"); | |||
| verifier.initVerify(rawPubKey); | |||
| verifier.update(data); | |||
| isValid = verifier.verify(rawDigestBytes); | |||
| } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | InvalidKeySpecException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| return isValid; | |||
| } | |||
| @Override | |||
| public boolean supportPubKey(byte[] pubKeyBytes) { | |||
| return pubKeyBytes.length > (ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + RAW_PUBKEY_SIZE) | |||
| && CryptoAlgorithm.match(SHA1WITHRSA4096, pubKeyBytes) | |||
| && pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE; | |||
| } | |||
| @Override | |||
| public PubKey resolvePubKey(byte[] pubKeyBytes) { | |||
| if (supportPubKey(pubKeyBytes)) { | |||
| return new PubKey(pubKeyBytes); | |||
| } else { | |||
| throw new CryptoException("pubKeyBytes are invalid!"); | |||
| } | |||
| } | |||
| @Override | |||
| public boolean supportPrivKey(byte[] privKeyBytes) { | |||
| return privKeyBytes.length > (ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + RAW_PRIVKEY_SIZE) | |||
| && CryptoAlgorithm.match(SHA1WITHRSA4096, privKeyBytes) | |||
| && privKeyBytes[ALGORYTHM_CODE_SIZE] == PRIVATE.CODE; | |||
| } | |||
| @Override | |||
| public PrivKey resolvePrivKey(byte[] privKeyBytes) { | |||
| if (supportPrivKey(privKeyBytes)) { | |||
| return new PrivKey(privKeyBytes); | |||
| } else { | |||
| throw new CryptoException("privKeyBytes are invalid!"); | |||
| } | |||
| } | |||
| @Override | |||
| public PubKey retrievePubKey(PrivKey privKey) { | |||
| byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||
| if (rawPrivKeyBytes.length < RAW_PRIVKEY_SIZE) { | |||
| throw new CryptoException("This key has wrong format!"); | |||
| } | |||
| if (privKey.getAlgorithm() != SHA1WITHRSA4096.code()) { | |||
| throw new CryptoException("This key is not SHA1WITHRSA4096 private key!"); | |||
| } | |||
| PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(rawPrivKeyBytes); | |||
| KeyFactory keyFactory; | |||
| RSAPrivateCrtKey rawPrivKey; | |||
| byte[] rawPubKeyBytes; | |||
| try { | |||
| keyFactory = KeyFactory.getInstance("RSA"); | |||
| rawPrivKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(keySpec); | |||
| BigInteger modulus = rawPrivKey.getModulus(); | |||
| BigInteger exponent = rawPrivKey.getPublicExponent(); | |||
| rawPubKeyBytes = KeyUtil.getEncodedSubjectPublicKeyInfo(RSA_ALGORITHM_IDENTIFIER, | |||
| new org.bouncycastle.asn1.pkcs.RSAPublicKey(modulus, exponent)); | |||
| } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| return new PubKey(SHA1WITHRSA4096, rawPubKeyBytes); | |||
| } | |||
| @Override | |||
| public boolean supportDigest(byte[] digestBytes) { | |||
| return digestBytes.length == (RAW_SIGNATUREDIGEST_SIZE + ALGORYTHM_CODE_SIZE) | |||
| && CryptoAlgorithm.match(SHA1WITHRSA4096, digestBytes); | |||
| } | |||
| @Override | |||
| public SignatureDigest resolveDigest(byte[] digestBytes) { | |||
| if (supportDigest(digestBytes)) { | |||
| return new SignatureDigest(digestBytes); | |||
| } else { | |||
| throw new CryptoException("digestBytes are invalid!"); | |||
| } | |||
| } | |||
| @Override | |||
| public AsymmetricKeypair generateKeypair() { | |||
| Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); | |||
| KeyPairGenerator generator; | |||
| PublicKey pubKey; | |||
| PrivateKey privKey; | |||
| try { | |||
| generator = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME); | |||
| generator.initialize(4096); | |||
| KeyPair keyPair = generator.generateKeyPair(); | |||
| pubKey = keyPair.getPublic(); | |||
| privKey = keyPair.getPrivate(); | |||
| } catch (NoSuchAlgorithmException | NoSuchProviderException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| byte[] pubKeyBytes = pubKey.getEncoded(); | |||
| byte[] privKeyBytes = privKey.getEncoded(); | |||
| return new AsymmetricKeypair(new PubKey(SHA1WITHRSA4096, pubKeyBytes), | |||
| new PrivKey(SHA1WITHRSA4096, privKeyBytes)); | |||
| } | |||
| @Override | |||
| public CryptoAlgorithm getAlgorithm() { | |||
| return SHA1WITHRSA4096; | |||
| } | |||
| } | |||
| @@ -0,0 +1,236 @@ | |||
| package com.jd.blockchain.crypto.service.pki; | |||
| import com.jd.blockchain.crypto.*; | |||
| import org.bouncycastle.asn1.gm.GMObjectIdentifiers; | |||
| import org.bouncycastle.asn1.x509.AlgorithmIdentifier; | |||
| import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; | |||
| import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; | |||
| import org.bouncycastle.jce.provider.BouncyCastleProvider; | |||
| import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; | |||
| import org.bouncycastle.math.ec.ECPoint; | |||
| import org.bouncycastle.math.ec.custom.gm.SM2P256V1Curve; | |||
| import java.math.BigInteger; | |||
| import java.security.*; | |||
| import java.security.interfaces.ECPrivateKey; | |||
| import java.security.interfaces.ECPublicKey; | |||
| import java.security.spec.InvalidKeySpecException; | |||
| import java.security.spec.PKCS8EncodedKeySpec; | |||
| import java.security.spec.X509EncodedKeySpec; | |||
| import static com.jd.blockchain.crypto.BaseCryptoKey.KEY_TYPE_BYTES; | |||
| import static com.jd.blockchain.crypto.CryptoBytes.ALGORYTHM_CODE_SIZE; | |||
| import static com.jd.blockchain.crypto.CryptoKeyType.PRIVATE; | |||
| import static com.jd.blockchain.crypto.CryptoKeyType.PUBLIC; | |||
| import static com.jd.blockchain.crypto.service.pki.PKIAlgorithm.SM3WITHSM2; | |||
| /** | |||
| * @author zhanglin33 | |||
| * @title: SM3WITHSM2SignatureFunction | |||
| * @description: TODO | |||
| * @date 2019-05-15, 16:39 | |||
| */ | |||
| public class SM3WITHSM2SignatureFunction implements SignatureFunction { | |||
| private static final int RAW_PUBKEY_SIZE = 65; | |||
| private static final int RAW_PRIVKEY_SIZE = 32 + 65; | |||
| private static final int RAW_SIGNATUREDIGEST_SIZE = 64; | |||
| private static final SM2P256V1Curve CURVE = new SM2P256V1Curve(); | |||
| private static final BigInteger GX = new BigInteger("32C4AE2C1F1981195F9904466A39C994" + | |||
| "8FE30BBFF2660BE1715A4589334C74C7", 16); | |||
| private static final BigInteger GY = new BigInteger("BC3736A2F4F6779C59BDCEE36B692153" + | |||
| "D0A9877CC62A474002DF32E52139F0A0", 16); | |||
| private static final ECPoint G = CURVE.createPoint(GX, GY); | |||
| private static final AlgorithmIdentifier SM2_ALGORITHM_IDENTIFIER = new AlgorithmIdentifier( | |||
| X9ObjectIdentifiers.id_ecPublicKey, GMObjectIdentifiers.sm2p256v1); | |||
| @Override | |||
| public SignatureDigest sign(PrivKey privKey, byte[] data) { | |||
| Security.addProvider(new BouncyCastleProvider()); | |||
| byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||
| if (rawPrivKeyBytes.length < RAW_PRIVKEY_SIZE) { | |||
| throw new CryptoException("This key has wrong format!"); | |||
| } | |||
| if (privKey.getAlgorithm() != SM3WITHSM2.code()) { | |||
| throw new CryptoException("This key is not SM3WITHSM2 private key!"); | |||
| } | |||
| PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(rawPrivKeyBytes); | |||
| KeyFactory keyFactory; | |||
| ECPrivateKey rawPrivKey; | |||
| Signature signer; | |||
| byte[] signature; | |||
| try { | |||
| keyFactory = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME); | |||
| rawPrivKey = (ECPrivateKey) keyFactory.generatePrivate(keySpec); | |||
| signer = Signature.getInstance("SM3withSM2", BouncyCastleProvider.PROVIDER_NAME); | |||
| signer.initSign(rawPrivKey); | |||
| signer.update(data); | |||
| signature = signer.sign(); | |||
| } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | | |||
| InvalidKeySpecException | NoSuchProviderException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| return new SignatureDigest(SM3WITHSM2, signature); | |||
| } | |||
| @Override | |||
| public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) { | |||
| Security.addProvider(new BouncyCastleProvider()); | |||
| byte[] rawPubKeyBytes = pubKey.getRawKeyBytes(); | |||
| byte[] rawDigestBytes = digest.getRawDigest(); | |||
| if (rawPubKeyBytes.length < RAW_PUBKEY_SIZE) { | |||
| throw new CryptoException("This key has wrong format!"); | |||
| } | |||
| if (pubKey.getAlgorithm() != SM3WITHSM2.code()) { | |||
| throw new CryptoException("This key is not SM3WITHSM2 public key!"); | |||
| } | |||
| if (digest.getAlgorithm() != SM3WITHSM2.code() || rawDigestBytes.length < RAW_SIGNATUREDIGEST_SIZE) { | |||
| throw new CryptoException("This is not SM3WITHSM2 signature digest!"); | |||
| } | |||
| X509EncodedKeySpec keySpec = new X509EncodedKeySpec(rawPubKeyBytes); | |||
| KeyFactory keyFactory; | |||
| ECPublicKey rawPubKey; | |||
| Signature verifier; | |||
| boolean isValid; | |||
| try { | |||
| keyFactory = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME); | |||
| rawPubKey = (ECPublicKey) keyFactory.generatePublic(keySpec); | |||
| verifier = Signature.getInstance("SM3withSM2", BouncyCastleProvider.PROVIDER_NAME); | |||
| verifier.initVerify(rawPubKey); | |||
| verifier.update(data); | |||
| isValid = verifier.verify(rawDigestBytes); | |||
| } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | InvalidKeySpecException | |||
| | NoSuchProviderException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| return isValid; | |||
| } | |||
| @Override | |||
| public boolean supportPubKey(byte[] pubKeyBytes) { | |||
| return pubKeyBytes.length > (ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + RAW_PUBKEY_SIZE) | |||
| && CryptoAlgorithm.match(SM3WITHSM2, pubKeyBytes) | |||
| && pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE; | |||
| } | |||
| @Override | |||
| public PubKey resolvePubKey(byte[] pubKeyBytes) { | |||
| if (supportPubKey(pubKeyBytes)) { | |||
| return new PubKey(pubKeyBytes); | |||
| } else { | |||
| throw new CryptoException("pubKeyBytes are invalid!"); | |||
| } | |||
| } | |||
| @Override | |||
| public boolean supportPrivKey(byte[] privKeyBytes) { | |||
| return privKeyBytes.length > (ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + RAW_PRIVKEY_SIZE) | |||
| && CryptoAlgorithm.match(SM3WITHSM2, privKeyBytes) | |||
| && privKeyBytes[ALGORYTHM_CODE_SIZE] == PRIVATE.CODE; | |||
| } | |||
| @Override | |||
| public PrivKey resolvePrivKey(byte[] privKeyBytes) { | |||
| if (supportPrivKey(privKeyBytes)) { | |||
| return new PrivKey(privKeyBytes); | |||
| } else { | |||
| throw new CryptoException("privKeyBytes are invalid!"); | |||
| } | |||
| } | |||
| @Override | |||
| public PubKey retrievePubKey(PrivKey privKey) { | |||
| byte[] rawPrivKeyBytes = privKey.getRawKeyBytes(); | |||
| if (rawPrivKeyBytes.length < RAW_PRIVKEY_SIZE) { | |||
| throw new CryptoException("This key has wrong format!"); | |||
| } | |||
| if (privKey.getAlgorithm() != SM3WITHSM2.code()) { | |||
| throw new CryptoException("This key is not SM3WITHSM2 private key!"); | |||
| } | |||
| PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(rawPrivKeyBytes); | |||
| KeyFactory keyFactory; | |||
| ECPrivateKey rawPrivKey; | |||
| byte[] rawPubKeyBytes; | |||
| try { | |||
| keyFactory = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME); | |||
| rawPrivKey = (ECPrivateKey) keyFactory.generatePrivate(keySpec); | |||
| BigInteger d = rawPrivKey.getS(); | |||
| ECPoint Q = G.multiply(d).normalize(); | |||
| rawPubKeyBytes = KeyUtil.getEncodedSubjectPublicKeyInfo(SM2_ALGORITHM_IDENTIFIER, | |||
| Q.getEncoded(false)); | |||
| } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| return new PubKey(SM3WITHSM2, rawPubKeyBytes); | |||
| } | |||
| @Override | |||
| public boolean supportDigest(byte[] digestBytes) { | |||
| return digestBytes.length > (RAW_SIGNATUREDIGEST_SIZE + ALGORYTHM_CODE_SIZE) | |||
| && CryptoAlgorithm.match(SM3WITHSM2, digestBytes); | |||
| } | |||
| @Override | |||
| public SignatureDigest resolveDigest(byte[] digestBytes) { | |||
| if (supportDigest(digestBytes)) { | |||
| return new SignatureDigest(digestBytes); | |||
| } else { | |||
| throw new CryptoException("digestBytes are invalid!"); | |||
| } | |||
| } | |||
| @Override | |||
| public AsymmetricKeypair generateKeypair() { | |||
| Security.addProvider(new BouncyCastleProvider()); | |||
| KeyPairGenerator generator; | |||
| PublicKey pubKey; | |||
| PrivateKey privKey; | |||
| try { | |||
| generator = KeyPairGenerator.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME); | |||
| generator.initialize(new ECNamedCurveGenParameterSpec("sm2p256v1")); | |||
| KeyPair keyPair = generator.generateKeyPair(); | |||
| pubKey = keyPair.getPublic(); | |||
| privKey = keyPair.getPrivate(); | |||
| } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| byte[] pubKeyBytes = pubKey.getEncoded(); | |||
| byte[] privKeyBytes = privKey.getEncoded(); | |||
| return new AsymmetricKeypair(new PubKey(SM3WITHSM2, pubKeyBytes), | |||
| new PrivKey(SM3WITHSM2, privKeyBytes)); | |||
| } | |||
| @Override | |||
| public CryptoAlgorithm getAlgorithm() { | |||
| return SM3WITHSM2; | |||
| } | |||
| } | |||
| @@ -0,0 +1,129 @@ | |||
| package com.jd.blockchain.crypto.utils; | |||
| import com.jd.blockchain.crypto.CryptoException; | |||
| import org.bouncycastle.asn1.x500.X500Name; | |||
| import org.bouncycastle.asn1.x500.X500NameBuilder; | |||
| import org.bouncycastle.asn1.x500.style.BCStrictStyle; | |||
| import org.bouncycastle.asn1.x500.style.BCStyle; | |||
| import org.bouncycastle.jce.provider.BouncyCastleProvider; | |||
| import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; | |||
| import org.bouncycastle.operator.OperatorCreationException; | |||
| import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; | |||
| import org.bouncycastle.pkcs.PKCS10CertificationRequest; | |||
| import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder; | |||
| import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder; | |||
| import org.bouncycastle.util.encoders.Base64; | |||
| import java.io.IOException; | |||
| import java.security.*; | |||
| /** | |||
| * @author zhanglin33 | |||
| * @title: CSRBuilder | |||
| * @description: A builder for certificate signing request, supporting rsa and sm2 | |||
| * @date 2019-05-10, 15:10 | |||
| */ | |||
| public class CSRBuilder { | |||
| private String BC = BouncyCastleProvider.PROVIDER_NAME; | |||
| private PublicKey pubKey; | |||
| private PrivateKey privKey; | |||
| private String algoName; | |||
| public void init() { | |||
| Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); | |||
| algoName = "SHA1withRSA"; | |||
| KeyPairGenerator generator; | |||
| try { | |||
| generator = KeyPairGenerator.getInstance("RSA", BC); | |||
| generator.initialize(2048); | |||
| KeyPair keyPair = generator.generateKeyPair(); | |||
| pubKey = keyPair.getPublic(); | |||
| privKey = keyPair.getPrivate(); | |||
| } catch (NoSuchAlgorithmException | NoSuchProviderException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| } | |||
| public void init(String algoName, int KeyLength) { | |||
| Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); | |||
| this.algoName = algoName; | |||
| KeyPairGenerator generator; | |||
| KeyPair keyPair; | |||
| String[] hashAndSignature = algoName.split("with"); | |||
| try { | |||
| switch (hashAndSignature[1]) { | |||
| case "RSA": { | |||
| generator = KeyPairGenerator.getInstance("RSA", BC); | |||
| generator.initialize(KeyLength); | |||
| keyPair = generator.generateKeyPair(); | |||
| pubKey = keyPair.getPublic(); | |||
| privKey = keyPair.getPrivate(); | |||
| break; | |||
| } | |||
| case "SM2": { | |||
| generator = KeyPairGenerator.getInstance("EC", BC); | |||
| if (KeyLength != 256) { | |||
| throw new CryptoException("SM3withSM2 with unsupported key length [" + | |||
| KeyLength +"] in CSR!"); | |||
| } | |||
| generator.initialize(new ECNamedCurveGenParameterSpec("sm2p256v1")); | |||
| keyPair = generator.generateKeyPair(); | |||
| pubKey = keyPair.getPublic(); | |||
| privKey = keyPair.getPrivate(); | |||
| break; | |||
| } | |||
| default: throw new CryptoException("Unsupported algorithm [" + algoName + "] with key length [" + | |||
| KeyLength +"] in CSR!"); | |||
| } | |||
| } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| } | |||
| public String buildRequest(String countryName, String stateName, String cityName, | |||
| String organizationName, String departmentName, String domainName, | |||
| String emailName) { | |||
| String result; | |||
| X500NameBuilder nameBuilder = new X500NameBuilder(BCStrictStyle.INSTANCE); | |||
| nameBuilder.addRDN(BCStyle.C, countryName); // a country name, and China is short as CN | |||
| nameBuilder.addRDN(BCStyle.ST, stateName); // a state or province name | |||
| nameBuilder.addRDN(BCStyle.L, cityName); // a city name | |||
| nameBuilder.addRDN(BCStyle.O, organizationName); // an organization or corporation name | |||
| nameBuilder.addRDN(BCStyle.OU, departmentName); // a division of your organization name | |||
| nameBuilder.addRDN(BCStyle.CN, domainName); // a fully qualified domain name | |||
| nameBuilder.addRDN(BCStyle.E, emailName); // an email address | |||
| try { | |||
| X500Name x500Name = nameBuilder.build(); | |||
| PKCS10CertificationRequestBuilder requestBuilder | |||
| = new JcaPKCS10CertificationRequestBuilder(x500Name, pubKey); | |||
| PKCS10CertificationRequest request | |||
| = requestBuilder.build(new JcaContentSignerBuilder(algoName).setProvider(BC).build(privKey)); | |||
| byte[] csrBytes = request.getEncoded(); | |||
| result = Base64.toBase64String(csrBytes); | |||
| } catch (OperatorCreationException | IOException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| return result; | |||
| } | |||
| public PublicKey getPubKey() { | |||
| return pubKey; | |||
| } | |||
| public PrivateKey getPrivKey() { | |||
| return privKey; | |||
| } | |||
| } | |||
| @@ -0,0 +1,131 @@ | |||
| package com.jd.blockchain.crypto.utils; | |||
| import com.jd.blockchain.crypto.CryptoException; | |||
| import org.bouncycastle.jce.provider.BouncyCastleProvider; | |||
| import org.bouncycastle.util.encoders.Base64; | |||
| import org.bouncycastle.util.io.pem.PemReader; | |||
| import javax.security.auth.x500.X500Principal; | |||
| import java.io.ByteArrayInputStream; | |||
| import java.io.IOException; | |||
| import java.io.StringReader; | |||
| import java.security.*; | |||
| import java.security.cert.*; | |||
| import java.util.Date; | |||
| /** | |||
| * @author zhanglin33 | |||
| * @title: CertParser | |||
| * @description: A parser for standard certificate, along with validation process | |||
| * @date 2019-05-10, 15:17 | |||
| */ | |||
| public class CertParser { | |||
| private PublicKey pubKey; | |||
| private String sigAlgName; | |||
| private String userName; | |||
| private String issuerName; | |||
| private Date startTime; | |||
| private Date endTime; | |||
| public void parse(String userCertificate, String issuerCertificate) { | |||
| X509Certificate issuerCert = parseWithoutValidationProcess(issuerCertificate); | |||
| // ensure that the certificate is within the validity period | |||
| try { | |||
| issuerCert.checkValidity(); | |||
| } catch (CertificateExpiredException | CertificateNotYetValidException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| PublicKey issuerPubKey = issuerCert.getPublicKey(); | |||
| X500Principal issuerPrincipal = issuerCert.getSubjectX500Principal(); | |||
| X509Certificate userCert = parseWithoutValidationProcess(userCertificate); | |||
| // check consistency between issuer's names in userCertificate and issuerCertificate | |||
| if (!userCert.getIssuerX500Principal().equals(issuerPrincipal)) { | |||
| throw new CryptoException("Issuer in the targeted certificate is not " + | |||
| "compliance with the parent certificate!"); | |||
| } | |||
| try { | |||
| userCert.checkValidity(); | |||
| } catch (CertificateExpiredException | CertificateNotYetValidException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| // verify the signature in certificate with issuer's public key | |||
| try { | |||
| userCert.verify(issuerPubKey); | |||
| } catch (CertificateException | NoSuchAlgorithmException | |||
| | InvalidKeyException | NoSuchProviderException | SignatureException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| startTime = userCert.getNotBefore(); | |||
| endTime = userCert.getNotAfter(); | |||
| pubKey = userCert.getPublicKey(); | |||
| sigAlgName = userCert.getSigAlgName(); | |||
| issuerName = userCert.getIssuerX500Principal().getName(); | |||
| userName = userCert.getSubjectX500Principal().getName(); | |||
| } | |||
| // certificate string in Base64 format | |||
| public X509Certificate parseWithoutValidationProcess(String certificate) { | |||
| Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); | |||
| byte[] certificateBytes; | |||
| String BEGIN = "-----BEGIN CERTIFICATE-----"; | |||
| String END = "-----END CERTIFICATE-----"; | |||
| if (!certificate.startsWith(BEGIN)) { | |||
| certificate = certificate.replaceAll("\\n", ""); | |||
| certificate = certificate.replaceAll(END, ""); | |||
| certificateBytes = Base64.decode(certificate); | |||
| } else { | |||
| try { | |||
| certificateBytes = new PemReader(new StringReader(certificate)).readPemObject().getContent(); | |||
| } catch (IOException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| } | |||
| ByteArrayInputStream bytesIn = new ByteArrayInputStream(certificateBytes); | |||
| CertificateFactory factory; | |||
| X509Certificate cert; | |||
| try { | |||
| factory = CertificateFactory.getInstance("X509", BouncyCastleProvider.PROVIDER_NAME); | |||
| cert = (X509Certificate) factory.generateCertificate(bytesIn); | |||
| } catch (CertificateException | NoSuchProviderException e) { | |||
| throw new CryptoException(e.getMessage(), e); | |||
| } | |||
| return cert; | |||
| } | |||
| public PublicKey getPubKey() { | |||
| return pubKey; | |||
| } | |||
| public String getSigAlgName() { | |||
| return sigAlgName; | |||
| } | |||
| public String getUserName() { | |||
| return userName; | |||
| } | |||
| public String getIssuerName() { | |||
| return issuerName; | |||
| } | |||
| public Date getStartTime() { | |||
| return startTime; | |||
| } | |||
| public Date getEndTime() { | |||
| return endTime; | |||
| } | |||
| } | |||
| @@ -0,0 +1 @@ | |||
| com.jd.blockchain.crypto.service.pki.PKICryptoService | |||
| @@ -0,0 +1,128 @@ | |||
| package com.jd.blockchain.crypto.service.pki; | |||
| import com.jd.blockchain.crypto.*; | |||
| 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: SHA1WITHRSA2048SignatureFunctionTest | |||
| * @description: TODO | |||
| * @date 2019-05-16, 10:49 | |||
| */ | |||
| public class SHA1WITHRSA2048SignatureFunctionTest { | |||
| @Test | |||
| public void getAlgorithmTest() { | |||
| CryptoAlgorithm algorithm = Crypto.getAlgorithm("SHA1WITHRSA2048"); | |||
| assertNotNull(algorithm); | |||
| SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||
| assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name()); | |||
| assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code()); | |||
| algorithm = Crypto.getAlgorithm("SHA1withRsa2048"); | |||
| assertNotNull(algorithm); | |||
| assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name()); | |||
| assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code()); | |||
| algorithm = Crypto.getAlgorithm("rsa2048"); | |||
| assertNull(algorithm); | |||
| } | |||
| @Test | |||
| public void test() { | |||
| // generateKeyPairTest | |||
| CryptoAlgorithm algorithm = Crypto.getAlgorithm("SHA1WITHRSA2048"); | |||
| 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); | |||
| assertTrue(pubKey.getRawKeyBytes().length > 259); | |||
| assertEquals(PRIVATE.CODE, privKey.getKeyType().CODE); | |||
| assertTrue(privKey.getRawKeyBytes().length > 1155); | |||
| assertEquals(algorithm.code(), pubKey.getAlgorithm()); | |||
| assertEquals(algorithm.code(), privKey.getAlgorithm()); | |||
| byte[] algoBytes = CryptoAlgorithm.getCodeBytes(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()); | |||
| // retrievePubKeyTest | |||
| 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()); | |||
| // signTest | |||
| byte[] data = new byte[1024]; | |||
| Random random = new Random(); | |||
| random.nextBytes(data); | |||
| SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); | |||
| byte[] signatureBytes = signatureDigest.toBytes(); | |||
| assertEquals(2 + 256, signatureBytes.length); | |||
| assertEquals(algorithm.code(), signatureDigest.getAlgorithm()); | |||
| assertEquals(PKIAlgorithm.SHA1WITHRSA2048.code(), signatureDigest.getAlgorithm()); | |||
| assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 31 & 0x00FF)), | |||
| signatureDigest.getAlgorithm()); | |||
| byte[] rawSinatureBytes = signatureDigest.getRawDigest(); | |||
| assertArrayEquals(BytesUtils.concat(algoBytes, rawSinatureBytes), signatureBytes); | |||
| // verifyTest | |||
| assertTrue(signatureFunction.verify(signatureDigest, pubKey, data)); | |||
| // supportPrivKeyTest | |||
| byte[] privKeyBytes = privKey.toBytes(); | |||
| assertTrue(signatureFunction.supportPrivKey(privKeyBytes)); | |||
| // resolvePrivKeyTest | |||
| PrivKey resolvedPrivKey = signatureFunction.resolvePrivKey(privKeyBytes); | |||
| assertEquals(PRIVATE.CODE, resolvedPrivKey.getKeyType().CODE); | |||
| assertEquals(PKIAlgorithm.SHA1WITHRSA2048.code(), resolvedPrivKey.getAlgorithm()); | |||
| assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 31 & 0x00FF)), | |||
| resolvedPrivKey.getAlgorithm()); | |||
| assertArrayEquals(privKeyBytes, resolvedPrivKey.toBytes()); | |||
| // supportPubKeyTest | |||
| byte[] pubKeyBytes = pubKey.toBytes(); | |||
| assertTrue(signatureFunction.supportPubKey(pubKeyBytes)); | |||
| // resolvedPubKeyTest | |||
| PubKey resolvedPubKey = signatureFunction.resolvePubKey(pubKeyBytes); | |||
| assertEquals(PUBLIC.CODE, resolvedPubKey.getKeyType().CODE); | |||
| assertEquals(PKIAlgorithm.SHA1WITHRSA2048.code(), resolvedPubKey.getAlgorithm()); | |||
| assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 31 & 0x00FF)), | |||
| resolvedPubKey.getAlgorithm()); | |||
| assertArrayEquals(pubKeyBytes, resolvedPubKey.toBytes()); | |||
| //supportDigestTest | |||
| byte[] signatureDigestBytes = signatureDigest.toBytes(); | |||
| assertTrue(signatureFunction.supportDigest(signatureDigestBytes)); | |||
| // resolveDigestTest | |||
| SignatureDigest resolvedSignatureDigest = signatureFunction.resolveDigest(signatureDigestBytes); | |||
| assertEquals(256, resolvedSignatureDigest.getRawDigest().length); | |||
| assertEquals(PKIAlgorithm.SHA1WITHRSA2048.code(), resolvedSignatureDigest.getAlgorithm()); | |||
| assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 31 & 0x00FF)), | |||
| resolvedSignatureDigest.getAlgorithm()); | |||
| assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes()); | |||
| } | |||
| } | |||
| @@ -0,0 +1,128 @@ | |||
| package com.jd.blockchain.crypto.service.pki; | |||
| import com.jd.blockchain.crypto.*; | |||
| 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: SHA1WITHRSA4096SignatureFunctionTest | |||
| * @description: TODO | |||
| * @date 2019-05-16, 10:49 | |||
| */ | |||
| public class SHA1WITHRSA4096SignatureFunctionTest { | |||
| @Test | |||
| public void getAlgorithmTest() { | |||
| CryptoAlgorithm algorithm = Crypto.getAlgorithm("SHA1WITHRSA4096"); | |||
| assertNotNull(algorithm); | |||
| SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||
| assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name()); | |||
| assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code()); | |||
| algorithm = Crypto.getAlgorithm("SHA1withRsa4096"); | |||
| assertNotNull(algorithm); | |||
| assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name()); | |||
| assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code()); | |||
| algorithm = Crypto.getAlgorithm("rsa2048"); | |||
| assertNull(algorithm); | |||
| } | |||
| //@Test | |||
| public void generateKeyPairTest() { | |||
| CryptoAlgorithm algorithm = Crypto.getAlgorithm("SHA1WITHRSA4096"); | |||
| assertNotNull(algorithm); | |||
| AsymmetricKeypair keyPair = Crypto.getSignatureFunction(algorithm).generateKeypair(); | |||
| PubKey pubKey = keyPair.getPubKey(); | |||
| PrivKey privKey = keyPair.getPrivKey(); | |||
| assertEquals(PUBLIC.CODE, pubKey.getKeyType().CODE); | |||
| assertTrue(pubKey.getRawKeyBytes().length > 515); | |||
| assertEquals(PRIVATE.CODE, privKey.getKeyType().CODE); | |||
| assertTrue(privKey.getRawKeyBytes().length > 2307); | |||
| assertEquals(algorithm.code(), pubKey.getAlgorithm()); | |||
| assertEquals(algorithm.code(), privKey.getAlgorithm()); | |||
| byte[] algoBytes = CryptoAlgorithm.getCodeBytes(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()); | |||
| // retrievePubKeyTest | |||
| SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||
| 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()); | |||
| // signAndVerifyTest | |||
| byte[] data = new byte[1024]; | |||
| Random random = new Random(); | |||
| random.nextBytes(data); | |||
| SignatureDigest signatureDigest = signatureFunction.sign(privKey, data); | |||
| byte[] signatureBytes = signatureDigest.toBytes(); | |||
| assertEquals(2 + 512, signatureBytes.length); | |||
| assertEquals(algorithm.code(), signatureDigest.getAlgorithm()); | |||
| assertEquals(PKIAlgorithm.SHA1WITHRSA4096.code(), signatureDigest.getAlgorithm()); | |||
| assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 32 & 0x00FF)), | |||
| signatureDigest.getAlgorithm()); | |||
| algoBytes = BytesUtils.toBytes(signatureDigest.getAlgorithm()); | |||
| byte[] rawSinatureBytes = signatureDigest.getRawDigest(); | |||
| assertArrayEquals(BytesUtils.concat(algoBytes, rawSinatureBytes), signatureBytes); | |||
| assertTrue(signatureFunction.verify(signatureDigest, pubKey, data)); | |||
| // supportAndResolvePrivKeyTest | |||
| byte[] privKeyBytes = privKey.toBytes(); | |||
| assertTrue(signatureFunction.supportPrivKey(privKeyBytes)); | |||
| PrivKey resolvedPrivKey = signatureFunction.resolvePrivKey(privKeyBytes); | |||
| assertEquals(PRIVATE.CODE, resolvedPrivKey.getKeyType().CODE); | |||
| assertEquals(PKIAlgorithm.SHA1WITHRSA4096.code(), resolvedPrivKey.getAlgorithm()); | |||
| assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 32 & 0x00FF)), | |||
| resolvedPrivKey.getAlgorithm()); | |||
| assertArrayEquals(privKeyBytes, resolvedPrivKey.toBytes()); | |||
| // supportAndResolvePubKeyTest | |||
| byte[] pubKeyBytes = pubKey.toBytes(); | |||
| assertTrue(signatureFunction.supportPubKey(pubKeyBytes)); | |||
| PubKey resolvedPubKey = signatureFunction.resolvePubKey(pubKeyBytes); | |||
| assertEquals(PUBLIC.CODE, resolvedPubKey.getKeyType().CODE); | |||
| assertEquals(PKIAlgorithm.SHA1WITHRSA4096.code(), resolvedPubKey.getAlgorithm()); | |||
| assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 32 & 0x00FF)), | |||
| resolvedPubKey.getAlgorithm()); | |||
| assertArrayEquals(pubKeyBytes, resolvedPubKey.toBytes()); | |||
| // supportAndResolveDigestTest | |||
| byte[] signatureDigestBytes = signatureDigest.toBytes(); | |||
| assertTrue(signatureFunction.supportDigest(signatureDigestBytes)); | |||
| SignatureDigest resolvedSignatureDigest = signatureFunction.resolveDigest(signatureDigestBytes); | |||
| assertEquals(512, resolvedSignatureDigest.getRawDigest().length); | |||
| assertEquals(PKIAlgorithm.SHA1WITHRSA4096.code(), resolvedSignatureDigest.getAlgorithm()); | |||
| assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 32 & 0x00FF)), | |||
| resolvedSignatureDigest.getAlgorithm()); | |||
| assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes()); | |||
| } | |||
| } | |||
| @@ -0,0 +1,273 @@ | |||
| package com.jd.blockchain.crypto.service.pki; | |||
| import com.jd.blockchain.crypto.*; | |||
| 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: SM3WITHSM2SignatureFunctionTest | |||
| * @description: TODO | |||
| * @date 2019-05-16, 17:04 | |||
| */ | |||
| public class SM3WITHSM2SignatureFunctionTest { | |||
| @Test | |||
| public void getAlgorithmTest() { | |||
| CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2"); | |||
| assertNotNull(algorithm); | |||
| SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||
| assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name()); | |||
| assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code()); | |||
| algorithm = Crypto.getAlgorithm("sm3withsm2"); | |||
| assertNotNull(algorithm); | |||
| assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name()); | |||
| assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code()); | |||
| algorithm = Crypto.getAlgorithm("sm3withs"); | |||
| assertNull(algorithm); | |||
| } | |||
| @Test | |||
| public void generateKeyPairTest() { | |||
| CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2"); | |||
| 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); | |||
| assertTrue(pubKey.getRawKeyBytes().length > 32); | |||
| assertEquals(PRIVATE.CODE, privKey.getKeyType().CODE); | |||
| assertTrue(privKey.getRawKeyBytes().length > 65 + 32); | |||
| assertEquals(algorithm.code(), pubKey.getAlgorithm()); | |||
| assertEquals(algorithm.code(), privKey.getAlgorithm()); | |||
| byte[] algoBytes = CryptoAlgorithm.getCodeBytes(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("SM3WITHSM2"); | |||
| 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("SM3WITHSM2"); | |||
| 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(); | |||
| assertTrue(signatureBytes.length > 2 + 64); | |||
| assertEquals(algorithm.code(), signatureDigest.getAlgorithm()); | |||
| assertEquals(PKIAlgorithm.SM3WITHSM2.code(), signatureDigest.getAlgorithm()); | |||
| assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 33 & 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("SM3WITHSM2"); | |||
| 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); | |||
| System.out.println(signatureDigest.getRawDigest().length); | |||
| assertTrue(signatureFunction.verify(signatureDigest, pubKey, data)); | |||
| } | |||
| @Test | |||
| public void supportPrivKeyTest() { | |||
| CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2"); | |||
| assertNotNull(algorithm); | |||
| SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||
| AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||
| PrivKey privKey = keyPair.getPrivKey(); | |||
| byte[] privKeyBytes = privKey.toBytes(); | |||
| assertTrue(signatureFunction.supportPrivKey(privKeyBytes)); | |||
| } | |||
| @Test | |||
| public void resolvePrivKeyTest() { | |||
| CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2"); | |||
| 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(PKIAlgorithm.SM3WITHSM2.code(), resolvedPrivKey.getAlgorithm()); | |||
| assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 33 & 0x00FF)), | |||
| resolvedPrivKey.getAlgorithm()); | |||
| assertArrayEquals(privKeyBytes, resolvedPrivKey.toBytes()); | |||
| } | |||
| @Test | |||
| public void supportPubKeyTest() { | |||
| CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2"); | |||
| assertNotNull(algorithm); | |||
| SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm); | |||
| AsymmetricKeypair keyPair = signatureFunction.generateKeypair(); | |||
| PubKey pubKey = keyPair.getPubKey(); | |||
| byte[] pubKeyBytes = pubKey.toBytes(); | |||
| assertTrue(signatureFunction.supportPubKey(pubKeyBytes)); | |||
| } | |||
| @Test | |||
| public void resolvePubKeyTest() { | |||
| CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2"); | |||
| 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(PKIAlgorithm.SM3WITHSM2.code(), resolvedPubKey.getAlgorithm()); | |||
| assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 33 & 0x00FF)), | |||
| resolvedPubKey.getAlgorithm()); | |||
| assertArrayEquals(pubKeyBytes, resolvedPubKey.toBytes()); | |||
| } | |||
| @Test | |||
| public void supportDigestTest() { | |||
| byte[] data = new byte[1024]; | |||
| Random random = new Random(); | |||
| random.nextBytes(data); | |||
| CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2"); | |||
| 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)); | |||
| } | |||
| @Test | |||
| public void resolveDigestTest() { | |||
| byte[] data = new byte[1024]; | |||
| Random random = new Random(); | |||
| random.nextBytes(data); | |||
| CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2"); | |||
| 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); | |||
| assertTrue(resolvedSignatureDigest.getRawDigest().length > 64); | |||
| assertEquals(PKIAlgorithm.SM3WITHSM2.code(), resolvedSignatureDigest.getAlgorithm()); | |||
| assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 33 & 0x00FF)), | |||
| resolvedSignatureDigest.getAlgorithm()); | |||
| assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes()); | |||
| } | |||
| } | |||
| @@ -0,0 +1,396 @@ | |||
| package com.jd.blockchain.crypto.utils; | |||
| import org.bouncycastle.asn1.ASN1Encoding; | |||
| import org.bouncycastle.asn1.DERSet; | |||
| import org.bouncycastle.asn1.pkcs.CertificationRequestInfo; | |||
| import org.bouncycastle.asn1.x500.RDN; | |||
| import org.bouncycastle.asn1.x500.style.BCStyle; | |||
| import org.bouncycastle.pkcs.PKCS10CertificationRequest; | |||
| import org.bouncycastle.util.encoders.Base64; | |||
| import org.junit.Test; | |||
| import java.io.IOException; | |||
| import java.security.*; | |||
| import static org.junit.Assert.*; | |||
| /** | |||
| * @author zhanglin33 | |||
| * @title: CSRBuilderTest | |||
| * @description: TODO | |||
| * @date 2019-05-10, 17:22 | |||
| */ | |||
| public class CSRBuilderTest { | |||
| @Test | |||
| public void defaultCSRTest(){ | |||
| String countryName = "CN"; | |||
| String stateName = "Beijing"; | |||
| String cityName = "Beijing"; | |||
| String organizationName = "JD.com"; | |||
| String departmentName = "Blockchain Department"; | |||
| String domainName = "ledger.jd.com"; | |||
| String emailName = "zhanglin33@jd.com"; | |||
| CSRBuilder builder = new CSRBuilder(); | |||
| builder.init(); | |||
| String csr = builder.buildRequest(countryName,stateName,cityName, | |||
| organizationName,departmentName,domainName, | |||
| emailName); | |||
| PublicKey pubKey = builder.getPubKey(); | |||
| PrivateKey privKey = builder.getPrivKey(); | |||
| byte[] crsBytes = Base64.decode(csr); | |||
| PKCS10CertificationRequest request = null; | |||
| try { | |||
| request = new PKCS10CertificationRequest(crsBytes); | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| assertNotNull(request); | |||
| assertEquals("1.2.840.113549.1.1.5",request.getSignatureAlgorithm().getAlgorithm().getId()); | |||
| byte[] pubKeyBytes = new byte[0]; | |||
| try { | |||
| pubKeyBytes = request.getSubjectPublicKeyInfo().getEncoded(); | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| assertArrayEquals(pubKeyBytes,pubKey.getEncoded()); | |||
| RDN[] rdns = request.getSubject().getRDNs(); | |||
| assertEquals(BCStyle.C, rdns[0].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.ST, rdns[1].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.L, rdns[2].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.O, rdns[3].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.OU, rdns[4].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.CN, rdns[5].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.E, rdns[6].getFirst().getType().toASN1Primitive()); | |||
| assertEquals("CN", rdns[0].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("Beijing", rdns[1].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("Beijing", rdns[2].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("JD.com", rdns[3].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("Blockchain Department", rdns[4].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("ledger.jd.com", rdns[5].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("zhanglin33@jd.com", rdns[6].getFirst().getValue().toASN1Primitive().toString()); | |||
| byte[] signature = request.getSignature(); | |||
| CertificationRequestInfo requestInfo = new CertificationRequestInfo(request.getSubject(),request.getSubjectPublicKeyInfo(),new DERSet()); | |||
| byte[] message = new byte[0]; | |||
| try { | |||
| message = requestInfo.getEncoded(ASN1Encoding.DER); | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| Signature signer; | |||
| byte[] result = new byte[0]; | |||
| try { | |||
| signer = Signature.getInstance("SHA1withRSA"); | |||
| signer.initSign(privKey); | |||
| signer.update(message); | |||
| result = signer.sign(); | |||
| } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| assertArrayEquals(result,signature); | |||
| Signature verifier; | |||
| boolean isValid = false; | |||
| try { | |||
| verifier = Signature.getInstance("SHA1withRSA"); | |||
| verifier.initVerify(pubKey); | |||
| verifier.update(message); | |||
| isValid = verifier.verify(signature); | |||
| } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| assertTrue(isValid); | |||
| } | |||
| @Test | |||
| public void SHA1withRSA2048CSRTest(){ | |||
| String countryName = "CN"; | |||
| String stateName = "Beijing"; | |||
| String cityName = "Beijing"; | |||
| String organizationName = "JD.com"; | |||
| String departmentName = "Blockchain Department"; | |||
| String domainName = "ledger.jd.com"; | |||
| String emailName = "zhanglin33@jd.com"; | |||
| CSRBuilder builder = new CSRBuilder(); | |||
| builder.init("SHA1withRSA",2048); | |||
| String csr = builder.buildRequest(countryName,stateName,cityName, | |||
| organizationName,departmentName,domainName, | |||
| emailName); | |||
| PublicKey pubKey = builder.getPubKey(); | |||
| PrivateKey privKey = builder.getPrivKey(); | |||
| byte[] crsBytes = Base64.decode(csr); | |||
| PKCS10CertificationRequest request = null; | |||
| try { | |||
| request = new PKCS10CertificationRequest(crsBytes); | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| assertNotNull(request); | |||
| assertEquals("1.2.840.113549.1.1.5",request.getSignatureAlgorithm().getAlgorithm().getId()); | |||
| byte[] pubKeyBytes = new byte[0]; | |||
| try { | |||
| pubKeyBytes = request.getSubjectPublicKeyInfo().getEncoded(); | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| assertArrayEquals(pubKeyBytes,pubKey.getEncoded()); | |||
| RDN[] rdns = request.getSubject().getRDNs(); | |||
| assertEquals(BCStyle.C, rdns[0].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.ST, rdns[1].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.L, rdns[2].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.O, rdns[3].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.OU, rdns[4].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.CN, rdns[5].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.E, rdns[6].getFirst().getType().toASN1Primitive()); | |||
| assertEquals("CN", rdns[0].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("Beijing", rdns[1].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("Beijing", rdns[2].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("JD.com", rdns[3].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("Blockchain Department", rdns[4].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("ledger.jd.com", rdns[5].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("zhanglin33@jd.com", rdns[6].getFirst().getValue().toASN1Primitive().toString()); | |||
| byte[] signature = request.getSignature(); | |||
| CertificationRequestInfo requestInfo = new CertificationRequestInfo(request.getSubject(),request.getSubjectPublicKeyInfo(),new DERSet()); | |||
| byte[] message = new byte[0]; | |||
| try { | |||
| message = requestInfo.getEncoded(ASN1Encoding.DER); | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| Signature signer; | |||
| byte[] result = new byte[0]; | |||
| try { | |||
| signer = Signature.getInstance("SHA1withRSA"); | |||
| signer.initSign(privKey); | |||
| signer.update(message); | |||
| result = signer.sign(); | |||
| } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| assertArrayEquals(result,signature); | |||
| Signature verifier; | |||
| boolean isValid = false; | |||
| try { | |||
| verifier = Signature.getInstance("SHA1withRSA"); | |||
| verifier.initVerify(pubKey); | |||
| verifier.update(message); | |||
| isValid = verifier.verify(signature); | |||
| } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| assertTrue(isValid); | |||
| } | |||
| // @Test | |||
| public void SHA1withRSA4096CSRTest(){ | |||
| String countryName = "CN"; | |||
| String stateName = "Beijing"; | |||
| String cityName = "Beijing"; | |||
| String organizationName = "JD.com"; | |||
| String departmentName = "Blockchain Department"; | |||
| String domainName = "ledger.jd.com"; | |||
| String emailName = "zhanglin33@jd.com"; | |||
| CSRBuilder builder = new CSRBuilder(); | |||
| builder.init("SHA1withRSA",4096); | |||
| String csr = builder.buildRequest(countryName,stateName,cityName, | |||
| organizationName,departmentName,domainName, | |||
| emailName); | |||
| PublicKey pubKey = builder.getPubKey(); | |||
| PrivateKey privKey = builder.getPrivKey(); | |||
| byte[] crsBytes = Base64.decode(csr); | |||
| PKCS10CertificationRequest request = null; | |||
| try { | |||
| request = new PKCS10CertificationRequest(crsBytes); | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| assertNotNull(request); | |||
| assertEquals("1.2.840.113549.1.1.5",request.getSignatureAlgorithm().getAlgorithm().getId()); | |||
| byte[] pubKeyBytes = new byte[0]; | |||
| try { | |||
| pubKeyBytes = request.getSubjectPublicKeyInfo().getEncoded(); | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| assertArrayEquals(pubKeyBytes,pubKey.getEncoded()); | |||
| RDN[] rdns = request.getSubject().getRDNs(); | |||
| assertEquals(BCStyle.C, rdns[0].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.ST, rdns[1].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.L, rdns[2].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.O, rdns[3].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.OU, rdns[4].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.CN, rdns[5].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.E, rdns[6].getFirst().getType().toASN1Primitive()); | |||
| assertEquals("CN", rdns[0].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("Beijing", rdns[1].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("Beijing", rdns[2].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("JD.com", rdns[3].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("Blockchain Department", rdns[4].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("ledger.jd.com", rdns[5].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("zhanglin33@jd.com", rdns[6].getFirst().getValue().toASN1Primitive().toString()); | |||
| byte[] signature = request.getSignature(); | |||
| CertificationRequestInfo requestInfo = new CertificationRequestInfo(request.getSubject(),request.getSubjectPublicKeyInfo(),new DERSet()); | |||
| byte[] message = new byte[0]; | |||
| try { | |||
| message = requestInfo.getEncoded(ASN1Encoding.DER); | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| Signature signer; | |||
| byte[] result = new byte[0]; | |||
| try { | |||
| signer = Signature.getInstance("SHA1withRSA"); | |||
| signer.initSign(privKey); | |||
| signer.update(message); | |||
| result = signer.sign(); | |||
| } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| assertArrayEquals(result,signature); | |||
| Signature verifier; | |||
| boolean isValid = false; | |||
| try { | |||
| verifier = Signature.getInstance("SHA1withRSA"); | |||
| verifier.initVerify(pubKey); | |||
| verifier.update(message); | |||
| isValid = verifier.verify(signature); | |||
| } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| assertTrue(isValid); | |||
| } | |||
| @Test | |||
| public void SM3withSM2CSRTest(){ | |||
| String countryName = "CN"; | |||
| String stateName = "Beijing"; | |||
| String cityName = "Beijing"; | |||
| String organizationName = "JD.com"; | |||
| String departmentName = "Blockchain Department"; | |||
| String domainName = "ledger.jd.com"; | |||
| String emailName = "zhanglin33@jd.com"; | |||
| CSRBuilder builder = new CSRBuilder(); | |||
| builder.init("SM3withSM2",256); | |||
| String csr = builder.buildRequest(countryName,stateName,cityName, | |||
| organizationName,departmentName,domainName, | |||
| emailName); | |||
| System.out.println(csr); | |||
| PublicKey pubKey = builder.getPubKey(); | |||
| PrivateKey privKey = builder.getPrivKey(); | |||
| byte[] crsBytes = Base64.decode(csr); | |||
| PKCS10CertificationRequest request = null; | |||
| try { | |||
| request = new PKCS10CertificationRequest(crsBytes); | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| assertNotNull(request); | |||
| assertEquals("1.2.156.10197.1.501",request.getSignatureAlgorithm().getAlgorithm().getId()); | |||
| byte[] pubKeyBytes = new byte[0]; | |||
| try { | |||
| pubKeyBytes = request.getSubjectPublicKeyInfo().getEncoded(); | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| assertArrayEquals(pubKeyBytes,pubKey.getEncoded()); | |||
| RDN[] rdns = request.getSubject().getRDNs(); | |||
| assertEquals(BCStyle.C, rdns[0].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.ST, rdns[1].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.L, rdns[2].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.O, rdns[3].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.OU, rdns[4].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.CN, rdns[5].getFirst().getType().toASN1Primitive()); | |||
| assertEquals(BCStyle.E, rdns[6].getFirst().getType().toASN1Primitive()); | |||
| assertEquals("CN", rdns[0].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("Beijing", rdns[1].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("Beijing", rdns[2].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("JD.com", rdns[3].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("Blockchain Department", rdns[4].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("ledger.jd.com", rdns[5].getFirst().getValue().toASN1Primitive().toString()); | |||
| assertEquals("zhanglin33@jd.com", rdns[6].getFirst().getValue().toASN1Primitive().toString()); | |||
| byte[] signature = request.getSignature(); | |||
| CertificationRequestInfo requestInfo = new CertificationRequestInfo(request.getSubject(),request.getSubjectPublicKeyInfo(),new DERSet()); | |||
| byte[] message = new byte[0]; | |||
| try { | |||
| message = requestInfo.getEncoded(ASN1Encoding.DER); | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| Signature signer; | |||
| byte[] result = new byte[0]; | |||
| try { | |||
| signer = Signature.getInstance("SM3withSM2"); | |||
| signer.initSign(privKey); | |||
| signer.update(message); | |||
| result = signer.sign(); | |||
| } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| Signature verifier; | |||
| boolean isValid = false; | |||
| try { | |||
| verifier = Signature.getInstance("SM3withSM2"); | |||
| verifier.initVerify(pubKey); | |||
| verifier.update(message); | |||
| isValid = verifier.verify(signature); | |||
| } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| assertTrue(isValid); | |||
| try { | |||
| verifier = Signature.getInstance("SM3withSM2"); | |||
| verifier.initVerify(pubKey); | |||
| verifier.update(message); | |||
| isValid = verifier.verify(result); | |||
| } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| assertTrue(isValid); | |||
| } | |||
| } | |||
| @@ -0,0 +1,146 @@ | |||
| package com.jd.blockchain.crypto.utils; | |||
| import org.junit.Test; | |||
| import static org.junit.Assert.assertEquals; | |||
| /** | |||
| * @author zhanglin33 | |||
| * @title: CertParserTest | |||
| * @description: TODO | |||
| * @date 2019-05-13, 10:05 | |||
| */ | |||
| public class CertParserTest { | |||
| @Test | |||
| public void parseSHA1WITHRSA2048Test() { | |||
| CertParser parser = new CertParser(); | |||
| String issuerCert = | |||
| "-----BEGIN CERTIFICATE-----\n" + | |||
| "MIIDzzCCAregAwIBAgIKUalCR1Mt5ZSK8jANBgkqhkiG9w0BAQUFADBZMQswCQYD\n" + | |||
| "VQQGEwJDTjEwMC4GA1UEChMnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24g\n" + | |||
| "QXV0aG9yaXR5MRgwFgYDVQQDEw9DRkNBIFRFU1QgQ1MgQ0EwHhcNMTIwODI5MDU1\n" + | |||
| "NDM2WhcNMzIwODI0MDU1NDM2WjBZMQswCQYDVQQGEwJDTjEwMC4GA1UEChMnQ2hp\n" + | |||
| "bmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRgwFgYDVQQDEw9D\n" + | |||
| "RkNBIFRFU1QgT0NBMTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8\n" + | |||
| "jn0n8Fp6hcRdACdn1+Y6GAkC6KGgNdKyHPrmsdmhCjnd/i4qUFwnG8cp3D4lFw1G\n" + | |||
| "jmjSO5yVYbik/NbS6lbNpRgTK3fDfMFvLJpRIC+IFhG9SdAC2hwjsH9qTpL9cK2M\n" + | |||
| "bSdrC6pBdDgnbzaM9AGBF4Y6vXhj5nah4ZMsBvDp19LzXjlGuTPLuAgv9ZlWknsd\n" + | |||
| "RN70PIAmvomd10uqX4GIJ4Jq/FdKXOLZ2DNK/NhRyN6Yq71L3ham6tutXeZow5t5\n" + | |||
| "0254AnUlo1u6SeH9F8itER653o/oMLFwp+63qXAcqrHUlOQPX+JI8fkumSqZ4F2F\n" + | |||
| "t/HfVMnqdtFNCnh5+eIBAgMBAAGjgZgwgZUwHwYDVR0jBBgwFoAUdN7FjQp9EBqq\n" + | |||
| "aYNbTSHOhpvMcTgwDAYDVR0TBAUwAwEB/zA4BgNVHR8EMTAvMC2gK6AphidodHRw\n" + | |||
| "Oi8vMjEwLjc0LjQyLjMvdGVzdHJjYS9SU0EvY3JsMS5jcmwwCwYDVR0PBAQDAgEG\n" + | |||
| "MB0GA1UdDgQWBBT8C7xEmg4xoYOpgYcnHgVCxr9W+DANBgkqhkiG9w0BAQUFAAOC\n" + | |||
| "AQEAb7W0K9fZPA+JPw6lRiMDaUJ0oh052yEXreMBfoPulxkBj439qombDiFggRLc\n" + | |||
| "3g8wIEKzMOzOKXTWtnzYwN3y/JQSuJb/M1QqOEEM2PZwCxI4AkBuH6jg03RjlkHg\n" + | |||
| "/kTtuIFp9ItBCC2/KkKlp0ENfn4XgVg2KtAjZ7lpyVU0LPnhEqqUVY/xthjlCSa7\n" + | |||
| "/XHNStRxsfCTIBUWJ8n2FZyQhfV/UkMNHDBIiJR0v6C4Ai0/290WvbPEIAq+03Si\n" + | |||
| "fsHzBeA0C8lP5VzfAr6wWePaZMCpStpLaoXNcAqReKxQllElOqAhRxC5VKH+rnIQ\n" + | |||
| "OMRZvB7FRyE9IfwKApngcZbA5g==\n" + | |||
| "-----END CERTIFICATE-----"; | |||
| String userCert = "MIIEQDCCAyigAwIBAgIFICdVYzEwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEYMBYGA1UEAxMPQ0ZDQSBURVNUIE9DQTExMB4XDTE5MDUxMDExMjAyNFoXDTIxMDUxMDExMjAyNFowcjELMAkGA1UEBhMCQ04xGDAWBgNVBAoTD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECxMITG9jYWwgUkExFTATBgNVBAsTDEluZGl2aWR1YWwtMTEfMB0GA1UEAxQWMDUxQGFhYWFhQFpIMDkzNTgwMjhAMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJx3F2WD1dJPzK/nRHO7d1TJ1hTjzGTmv0PQ7ECsJAh3U3BtnGTpCB+b4+JMI4LO8nHkKIBQ3P9XnF+Bf1iXdWNAQ4aWCxa2nV7lCp4w0GliPu/EMgIfmsSDUtgqbM3cr8sR8r9m1xG3gt2TIQJ+jT7sAiguU/kyNzpjaccOUIgUFa8IDFq9UeB76MXtCuhlERRZQCl47e+9w7ZoxmE7e6IZORxPp7rQWVBHlR9ntWjJfNDTm3gMP5ehP+yIZnKx1LudxkBLQxpMmspzOyH1zqx5nkKe49AfWWpDxxRvYkriyYC3aE81qLsU/bhLwNEKOju7BGDF/mhJLZUedojM0gMCAwEAAaOB9TCB8jAfBgNVHSMEGDAWgBT8C7xEmg4xoYOpgYcnHgVCxr9W+DBIBgNVHSAEQTA/MD0GCGCBHIbvKgECMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2ZjYS5jb20uY24vdXMvdXMtMTUuaHRtMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly8yMTAuNzQuNDIuMy9PQ0ExMS9SU0EvY3JsMjU2OTMuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQU5oKGaQs7Jt5Gfbt1XhFTWAySEKswHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBBQUAA4IBAQAlmPRaImZV51iKjtpMKuyLMw7dX8L0lY3tl+pVZZSxHuwsN4GCCtV0Ej50up+/6EbfL4NUTiuHVAjCroKKvb+94CrdEwdnQGM5IbGSjT78nQpeASXbIWuUwA+ImjvZOzvq/0b56AzonNzBxOMGko/bj5smM6X8jrgJ0NQppo2KNSVNC4JbuoNWI4FM94SE4DUi9H7EYl4JdOtDaDtCsq49o/A1CZyYrmoOPCgxpQQXmuB3lGq/jyoOlW2aW8uee/hYG1JJcSHLBjF0WBwdxssgbBotA5f1PebiIMSbFgjk57bd4M80hhU/rI4Hkn9pcp5R7NsX95TtyDIg90LboBnW"; | |||
| parser.parse(userCert, issuerCert); | |||
| assertEquals("SHA1WITHRSA",parser.getSigAlgName()); | |||
| } | |||
| @Test | |||
| public void parseSHA1WITHRSA4096Test() { | |||
| CertParser parser = new CertParser(); | |||
| String issuerCert = | |||
| "-----BEGIN CERTIFICATE-----\n" + | |||
| "MIIDzzCCAregAwIBAgIKUalCR1Mt5ZSK8jANBgkqhkiG9w0BAQUFADBZMQswCQYD\n" + | |||
| "VQQGEwJDTjEwMC4GA1UEChMnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24g\n" + | |||
| "QXV0aG9yaXR5MRgwFgYDVQQDEw9DRkNBIFRFU1QgQ1MgQ0EwHhcNMTIwODI5MDU1\n" + | |||
| "NDM2WhcNMzIwODI0MDU1NDM2WjBZMQswCQYDVQQGEwJDTjEwMC4GA1UEChMnQ2hp\n" + | |||
| "bmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRgwFgYDVQQDEw9D\n" + | |||
| "RkNBIFRFU1QgT0NBMTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8\n" + | |||
| "jn0n8Fp6hcRdACdn1+Y6GAkC6KGgNdKyHPrmsdmhCjnd/i4qUFwnG8cp3D4lFw1G\n" + | |||
| "jmjSO5yVYbik/NbS6lbNpRgTK3fDfMFvLJpRIC+IFhG9SdAC2hwjsH9qTpL9cK2M\n" + | |||
| "bSdrC6pBdDgnbzaM9AGBF4Y6vXhj5nah4ZMsBvDp19LzXjlGuTPLuAgv9ZlWknsd\n" + | |||
| "RN70PIAmvomd10uqX4GIJ4Jq/FdKXOLZ2DNK/NhRyN6Yq71L3ham6tutXeZow5t5\n" + | |||
| "0254AnUlo1u6SeH9F8itER653o/oMLFwp+63qXAcqrHUlOQPX+JI8fkumSqZ4F2F\n" + | |||
| "t/HfVMnqdtFNCnh5+eIBAgMBAAGjgZgwgZUwHwYDVR0jBBgwFoAUdN7FjQp9EBqq\n" + | |||
| "aYNbTSHOhpvMcTgwDAYDVR0TBAUwAwEB/zA4BgNVHR8EMTAvMC2gK6AphidodHRw\n" + | |||
| "Oi8vMjEwLjc0LjQyLjMvdGVzdHJjYS9SU0EvY3JsMS5jcmwwCwYDVR0PBAQDAgEG\n" + | |||
| "MB0GA1UdDgQWBBT8C7xEmg4xoYOpgYcnHgVCxr9W+DANBgkqhkiG9w0BAQUFAAOC\n" + | |||
| "AQEAb7W0K9fZPA+JPw6lRiMDaUJ0oh052yEXreMBfoPulxkBj439qombDiFggRLc\n" + | |||
| "3g8wIEKzMOzOKXTWtnzYwN3y/JQSuJb/M1QqOEEM2PZwCxI4AkBuH6jg03RjlkHg\n" + | |||
| "/kTtuIFp9ItBCC2/KkKlp0ENfn4XgVg2KtAjZ7lpyVU0LPnhEqqUVY/xthjlCSa7\n" + | |||
| "/XHNStRxsfCTIBUWJ8n2FZyQhfV/UkMNHDBIiJR0v6C4Ai0/290WvbPEIAq+03Si\n" + | |||
| "fsHzBeA0C8lP5VzfAr6wWePaZMCpStpLaoXNcAqReKxQllElOqAhRxC5VKH+rnIQ\n" + | |||
| "OMRZvB7FRyE9IfwKApngcZbA5g==\n" + | |||
| "-----END CERTIFICATE-----"; | |||
| String userCert = "MIIFRjCCBC6gAwIBAgIFICdWiDMwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEYMBYGA1UEAxMPQ0ZDQSBURVNUIE9DQTExMB4XDTE5MDUxNjA3MDcyMloXDTIxMDUxNjA3MDcyMloweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoTD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECxMITG9jYWwgUkExFTATBgNVBAsTDEluZGl2aWR1YWwtMTElMCMGA1UEAxQcMDUxQHpoYW5nbGluIUBaMTg2MTIyMjkyOTVAMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL0rTOxd8rsjPtFJ0aGVh9bZPy5Xo0SADaP7BbJsG4+ykLQMZHg9hTf/6fv1OsD2HEKFoMpIkW2gwCJW2nvicHcVql/shCoktc6ZBW6Dr/DxOgbO9tpoGxZ50xdI4Q0NsrxqtbCldW4ozPHdjgRJ83i1KSFh7evNrVByN/mB+jchrVGLWyJ1uIRgUUgpRZmZPoOHaizVJqrqWJGGk6xbDLR2gUQ1hTzetQaz1OeKtelHDk9FY08XSmNGssSMpuSjrxn78S888VW5WIxyo4cwrXSXFk3J7LNTy70Oga16HZjJD/vLTM6a4riPa8+uivPinKxK38/++nlBPNwhx6n46uYkd9Zvw+SJiJgpnuPJLtMZpKpJx7V1BDVEydKPUthilTdsmJtkBFSlFw0G1aKfuciBGzzJ3SKngJF/JqJAWIonVAFBGb6Gokp1Sw+T4KqXrdbjxYxiyyjZ++8O1vydgFAkx/NjsuwJnpKETiRKFJmY7YawcUvC4ixF7XQc0luFWRDYcbxOppir+ieMqhGXyaFhLUuB4WXv+rFxfa3NmkBW8q5TPzt/PwWcXpITsYTZYla/E/grB+OeZLYgjigT5YlgytPHG6Gt1ySCCd8WXFWpkBbQfXzqcvtU27RCcAUgfXk5NLb7NZCQg7heGjgzOdYJCPsa1d3m7l04+VIKGCZdAgMBAAGjgfUwgfIwHwYDVR0jBBgwFoAU/Au8RJoOMaGDqYGHJx4FQsa/VvgwSAYDVR0gBEEwPzA9BghggRyG7yoBAjAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE1Lmh0bTA6BgNVHR8EMzAxMC+gLaArhilodHRwOi8vMjEwLjc0LjQyLjMvT0NBMTEvUlNBL2NybDI1NzE3LmNybDALBgNVHQ8EBAMCA+gwHQYDVR0OBBYEFMjh6AzDCuNkD+pqQfiS6bqPGpI4MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDANBgkqhkiG9w0BAQUFAAOCAQEApZaLXS6/6FudPA3l2xom5U7nJUOpQ1E6DO/ic9dFGtLE0WgyAqB3JVPvXEntppX55x/dAV7rvvz9NaEdiAe8DAj7qyoPDvC8ZWQK8U4n9l8N78QwALOURxzQNs+CBatJQzbu2w1RKVwkfE6xEIVnu+wjiAtymfwdLHMagHxDIC/eOPbTnbbtITJk2ukFfoc0WJ6Awg5lW+x7nGokEn/XAjKyRHCpkRUFGQm4ww41zlrqCqQqnVGVABJtjbdtFf7nh33QHl0fkj19nfMox9eGuntPyM0bNA0XqPMA+FWSCqeDT6uLbyaOKWxlhv53U/NCJl76U3tssMEWsm9amEDDQg=="; | |||
| parser.parse(userCert, issuerCert); | |||
| assertEquals("SHA1WITHRSA",parser.getSigAlgName()); | |||
| } | |||
| @Test | |||
| public void parseSM3WITHSM2Test() { | |||
| CertParser parser = new CertParser(); | |||
| String issuerCert = | |||
| "-----BEGIN CERTIFICATE-----\n" + | |||
| "MIICTzCCAfOgAwIBAgIKJFSZ4SRVDndYUTAMBggqgRzPVQGDdQUAMF0xCzAJBgNV\n" + | |||
| "BAYTAkNOMTAwLgYDVQQKDCdDaGluYSBGaW5hbmNpYWwgQ2VydGlmaWNhdGlvbiBB\n" + | |||
| "dXRob3JpdHkxHDAaBgNVBAMME0NGQ0EgVEVTVCBDUyBTTTIgQ0EwHhcNMTIwODI5\n" + | |||
| "MDU0ODQ3WhcNMzIwODI0MDU0ODQ3WjBdMQswCQYDVQQGEwJDTjEwMC4GA1UECgwn\n" + | |||
| "Q2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQD\n" + | |||
| "DBNDRkNBIFRFU1QgU00yIE9DQTExMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE\n" + | |||
| "L1mx4wriQUojGsIkNL14kslv9nwiqsiVpELOZauzghrbccNlPYKNYKZOCvXwIIqU\n" + | |||
| "9QY02d4weqKqo/JMcNsKEaOBmDCBlTAfBgNVHSMEGDAWgBS12JBvXPDYM9JjvX6y\n" + | |||
| "w43GTxJ6YTAMBgNVHRMEBTADAQH/MDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6Ly8y\n" + | |||
| "MTAuNzQuNDIuMy90ZXN0cmNhL1NNMi9jcmwxLmNybDALBgNVHQ8EBAMCAQYwHQYD\n" + | |||
| "VR0OBBYEFL6mfk09fI+gVebBLwkuLCBDs0J/MAwGCCqBHM9VAYN1BQADSAAwRQIh\n" + | |||
| "AKuk7s3eYCZDck5NWU0eNQmLhBN/1zmKs517qFrDrkJWAiAP4cVfLtdza/OkwU9P\n" + | |||
| "PrIDl+E4aL3FypntFXHG3T+Keg==\n" + | |||
| "-----END CERTIFICATE-----"; | |||
| String userCert = "MIICwDCCAmWgAwIBAgIFICdWkWgwDAYIKoEcz1UBg3UFADBdMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQDDBNDRkNBIFRFU1QgU00yIE9DQTExMB4XDTE5MDUxNjA4MTA1MVoXDTIxMDUxNjA4MTA1MVoweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoMD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECwwITG9jYWwgUkExFTATBgNVBAsMDEluZGl2aWR1YWwtMTElMCMGA1UEAwwcMDUxQHpoYW5nbGluIUBaMTg2MTIyMjkyOTVAMzBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABPvNXpdZ4/4g+wx5qKS94CPkMqpEDhlnXYYW7ZzsbNI4d28sVBz5Ji6dTT1Zx627Kvw4tdUaUt7BVMvZsu3BFlyjgfQwgfEwHwYDVR0jBBgwFoAUvqZ+TT18j6BV5sEvCS4sIEOzQn8wSAYDVR0gBEEwPzA9BghggRyG7yoBAjAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE1Lmh0bTA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vMjEwLjc0LjQyLjMvT0NBMTEvU00yL2NybDIxMDkuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUxR5C/VjASus5zrAAFS4ulMpRjKgwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMAwGCCqBHM9VAYN1BQADRwAwRAIgVBzVi/fgkknr+2BH2wXeGMXC+Pa6p7rbldUsYMOYoyUCIAmQ4KEk2U1xJZSBpOPy5jN9kmRb+0YH6x04O/2tqCgq"; | |||
| parser.parse(userCert, issuerCert); | |||
| assertEquals("SM3WITHSM2",parser.getSigAlgName()); | |||
| } | |||
| @Test | |||
| public void authenticateIssuerByCATest() { | |||
| CertParser parser = new CertParser(); | |||
| String CACert = | |||
| "-----BEGIN CERTIFICATE-----\n" + | |||
| "MIICFDCCAbegAwIBAgIKPYozwkCO86Nd9TAMBggqgRzPVQGDdQUAMF0xCzAJBgNV\n" + | |||
| "BAYTAkNOMTAwLgYDVQQKDCdDaGluYSBGaW5hbmNpYWwgQ2VydGlmaWNhdGlvbiBB\n" + | |||
| "dXRob3JpdHkxHDAaBgNVBAMME0NGQ0EgVEVTVCBDUyBTTTIgQ0EwHhcNMTIwODI5\n" + | |||
| "MDMyOTQ2WhcNMzIwODI5MDMyOTQ2WjBdMQswCQYDVQQGEwJDTjEwMC4GA1UECgwn\n" + | |||
| "Q2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQD\n" + | |||
| "DBNDRkNBIFRFU1QgQ1MgU00yIENBMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE\n" + | |||
| "tTjB3O4JueYFDDOtxH678HBZbEmrsgd3BDIdGf0BekyA26n9S0/pKPnjBh/zLouS\n" + | |||
| "8+GB5EEnjbn4An24yo1Gv6NdMFswHwYDVR0jBBgwFoAUtdiQb1zw2DPSY71+ssON\n" + | |||
| "xk8SemEwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFLXYkG9c\n" + | |||
| "8Ngz0mO9frLDjcZPEnphMAwGCCqBHM9VAYN1BQADSQAwRgIhAKwuuqoBS1bwDowW\n" + | |||
| "a4IU//UsvudswJYSlltqrd/PQ9q+AiEAyTUAjFdaGI+8yPdr3A93UiA38wtGPf9e\n" + | |||
| "6B6O/6abyWE=\n" + | |||
| "-----END CERTIFICATE-----"; | |||
| String issuerCert = "-----BEGIN CERTIFICATE-----\n" + | |||
| "MIICTzCCAfOgAwIBAgIKJFSZ4SRVDndYUTAMBggqgRzPVQGDdQUAMF0xCzAJBgNV\n" + | |||
| "BAYTAkNOMTAwLgYDVQQKDCdDaGluYSBGaW5hbmNpYWwgQ2VydGlmaWNhdGlvbiBB\n" + | |||
| "dXRob3JpdHkxHDAaBgNVBAMME0NGQ0EgVEVTVCBDUyBTTTIgQ0EwHhcNMTIwODI5\n" + | |||
| "MDU0ODQ3WhcNMzIwODI0MDU0ODQ3WjBdMQswCQYDVQQGEwJDTjEwMC4GA1UECgwn\n" + | |||
| "Q2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQD\n" + | |||
| "DBNDRkNBIFRFU1QgU00yIE9DQTExMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE\n" + | |||
| "L1mx4wriQUojGsIkNL14kslv9nwiqsiVpELOZauzghrbccNlPYKNYKZOCvXwIIqU\n" + | |||
| "9QY02d4weqKqo/JMcNsKEaOBmDCBlTAfBgNVHSMEGDAWgBS12JBvXPDYM9JjvX6y\n" + | |||
| "w43GTxJ6YTAMBgNVHRMEBTADAQH/MDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6Ly8y\n" + | |||
| "MTAuNzQuNDIuMy90ZXN0cmNhL1NNMi9jcmwxLmNybDALBgNVHQ8EBAMCAQYwHQYD\n" + | |||
| "VR0OBBYEFL6mfk09fI+gVebBLwkuLCBDs0J/MAwGCCqBHM9VAYN1BQADSAAwRQIh\n" + | |||
| "AKuk7s3eYCZDck5NWU0eNQmLhBN/1zmKs517qFrDrkJWAiAP4cVfLtdza/OkwU9P\n" + | |||
| "PrIDl+E4aL3FypntFXHG3T+Keg==\n" + | |||
| "-----END CERTIFICATE-----"; | |||
| parser.parse(issuerCert, CACert); | |||
| assertEquals("SM3WITHSM2",parser.getSigAlgName()); | |||
| } | |||
| } | |||
| @@ -16,6 +16,7 @@ | |||
| <module>crypto-sm</module> | |||
| <!-- <module>crypto-jni-clib</module> --> | |||
| <module>crypto-adv</module> | |||
| <module>crypto-pki</module> | |||
| </modules> | |||
| </project> | |||
| @@ -1,67 +0,0 @@ | |||
| #账本的种子;一段16进制字符,最长可以包含64个字符;可以用字符“-”分隔,以便更容易读取; | |||
| #不同的账本,种子不能相同 | |||
| ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323ffe | |||
| #账本的描述名称;此属性不参与共识,仅仅在当前参与方的本地节点用于描述用途; | |||
| #ledger.name= | |||
| #参与方的个数,后续以cons_parti.id分别标识每一个参与方的配置; | |||
| cons_parti.count=4 | |||
| #第0个参与方的名称(不同参与方名称不能相同) | |||
| cons_parti.0.name= | |||
| #第0个参与方的公钥文件路径 | |||
| cons_parti.0.pubkey-path= | |||
| #第0个参与方的公钥内容(由keygen工具生成),此参数优先于 pubkey-path 参数 | |||
| cons_parti.0.pubkey= | |||
| #第0个参与方的账本初始服务的主机 | |||
| cons_parti.0.initializer.host=127.0.0.1 | |||
| #第0个参与方的账本初始服务的端口 | |||
| cons_parti.0.initializer.port=17000 | |||
| #第0个参与方的账本初始服务是否开启安全连接 | |||
| cons_parti.0.initializer.secure=false | |||
| #第1个参与方的名称 | |||
| cons_parti.1.name= | |||
| #第1个参与方的公钥文件路径 | |||
| cons_parti.1.pubkey-path= | |||
| #第1个参与方的公钥内容(由keygen工具生成),此参数优先于 pubkey-path 参数 | |||
| cons_parti.1.pubkey= | |||
| #第1个参与方的账本初始服务的主机 | |||
| cons_parti.1.initializer.host=127.0.0.1 | |||
| #第1个参与方的账本初始服务的端口 | |||
| cons_parti.1.initializer.port=17010 | |||
| #第1个参与方的账本初始服务是否开启安全连接 | |||
| cons_parti.1.initializer.secure=false | |||
| #第2个参与方的名称 | |||
| cons_parti.2.name= | |||
| #第2个参与方的公钥文件路径 | |||
| cons_parti.2.pubkey-path= | |||
| #第2个参与方的公钥内容(由keygen工具生成),此参数优先于 pubkey-path 参数 | |||
| cons_parti.2.pubkey= | |||
| #第2个参与方的账本初始服务的主机 | |||
| cons_parti.2.initializer.host=127.0.0.1 | |||
| #第2个参与方的账本初始服务的端口 | |||
| cons_parti.2.initializer.port=17020 | |||
| #第2个参与方的账本初始服务是否开启安全连接 | |||
| cons_parti.2.initializer.secure=false | |||
| #第3个参与方的名称 | |||
| cons_parti.3.name= | |||
| #第3个参与方的公钥文件路径 | |||
| cons_parti.3.pubkey-path= | |||
| #第3个参与方的公钥内容(由keygen工具生成),此参数优先于 pubkey-path 参数 | |||
| cons_parti.3.pubkey= | |||
| #第3个参与方的账本初始服务的主机 | |||
| cons_parti.3.initializer.host=127.0.0.1 | |||
| #第3个参与方的账本初始服务的端口 | |||
| cons_parti.3.initializer.port=17030 | |||
| #第3个参与方的账本初始服务是否开启安全连接 | |||
| cons_parti.3.initializer.secure=false | |||
| @@ -0,0 +1,97 @@ | |||
| #账本的种子;一段16进制字符,最长可以包含64个字符;可以用字符“-”分隔,以便更容易读取; | |||
| ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323ffe | |||
| #账本的描述名称;此属性不参与共识,仅仅在当前参与方的本地节点用于描述用途; | |||
| ledger.name= | |||
| #共识服务提供者;必须; | |||
| consensus.service-provider=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider | |||
| #共识服务的参数配置;必须; | |||
| consensus.conf=classpath:bftsmart.config | |||
| #密码服务提供者列表,以英文逗点“,”分隔;必须; | |||
| crypto.service-providers=com.jd.blockchain.crypto.service.classic.ClassicCryptoService, \ | |||
| com.jd.blockchain.crypto.service.sm.SMCryptoService | |||
| #参与方的个数,后续以 cons_parti.id 分别标识每一个参与方的配置; | |||
| cons_parti.count=4 | |||
| #第0个参与方的名称; | |||
| cons_parti.0.name=jd.com | |||
| #第0个参与方的公钥文件路径; | |||
| cons_parti.0.pubkey-path=keys/jd-com.pub | |||
| #第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | |||
| cons_parti.0.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9 | |||
| #第0个参与方的共识服务的主机地址; | |||
| cons_parti.0.consensus.host=127.0.0.1 | |||
| #第0个参与方的共识服务的端口; | |||
| cons_parti.0.consensus.port=8900 | |||
| #第0个参与方的共识服务是否开启安全连接; | |||
| cons_parti.0.consensus.secure=true | |||
| #第0个参与方的账本初始服务的主机; | |||
| cons_parti.0.initializer.host=127.0.0.1 | |||
| #第0个参与方的账本初始服务的端口; | |||
| cons_parti.0.initializer.port=8800 | |||
| #第0个参与方的账本初始服务是否开启安全连接; | |||
| cons_parti.0.initializer.secure=true | |||
| #第1个参与方的名称; | |||
| cons_parti.1.name=at.com | |||
| #第1个参与方的公钥文件路径; | |||
| cons_parti.1.pubkey-path=keys/at-com.pub | |||
| #第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | |||
| cons_parti.1.pubkey=3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX | |||
| #第1个参与方的共识服务的主机地址; | |||
| cons_parti.1.consensus.host=127.0.0.1 | |||
| #第1个参与方的共识服务的端口; | |||
| cons_parti.1.consensus.port=8910 | |||
| #第1个参与方的共识服务是否开启安全连接; | |||
| cons_parti.1.consensus.secure=false | |||
| #第1个参与方的账本初始服务的主机; | |||
| cons_parti.1.initializer.host=127.0.0.1 | |||
| #第1个参与方的账本初始服务的端口; | |||
| cons_parti.1.initializer.port=8810 | |||
| #第1个参与方的账本初始服务是否开启安全连接; | |||
| cons_parti.1.initializer.secure=false | |||
| #第2个参与方的名称; | |||
| cons_parti.2.name=bt.com | |||
| #第2个参与方的公钥文件路径; | |||
| cons_parti.2.pubkey-path=classpath:keys/parti2.pub | |||
| #第2个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | |||
| cons_parti.2.pubkey= | |||
| #第2个参与方的共识服务的主机地址; | |||
| cons_parti.2.consensus.host=127.0.0.1 | |||
| #第2个参与方的共识服务的端口; | |||
| cons_parti.2.consensus.port=8920 | |||
| #第2个参与方的共识服务是否开启安全连接; | |||
| cons_parti.2.consensus.secure=false | |||
| #第2个参与方的账本初始服务的主机; | |||
| cons_parti.2.initializer.host=127.0.0.1 | |||
| #第2个参与方的账本初始服务的端口; | |||
| cons_parti.2.initializer.port=8820 | |||
| #第2个参与方的账本初始服务是否开启安全连接; | |||
| cons_parti.2.initializer.secure=true | |||
| #第3个参与方的名称; | |||
| cons_parti.3.name=xt.com | |||
| #第3个参与方的公钥文件路径; | |||
| cons_parti.3.pubkey-path=keys/xt-com.pub | |||
| #第3个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | |||
| cons_parti.3.pubkey=3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk | |||
| #第3个参与方的共识服务的主机地址; | |||
| cons_parti.3.consensus.host=127.0.0.1 | |||
| #第3个参与方的共识服务的端口; | |||
| cons_parti.3.consensus.port=8930 | |||
| #第3个参与方的共识服务是否开启安全连接; | |||
| cons_parti.3.consensus.secure=false | |||
| #第3个参与方的账本初始服务的主机; | |||
| cons_parti.3.initializer.host=127.0.0.1 | |||
| #第3个参与方的账本初始服务的端口; | |||
| cons_parti.3.initializer.port=8830 | |||
| #第3个参与方的账本初始服务是否开启安全连接; | |||
| cons_parti.3.initializer.secure=false | |||
| @@ -22,11 +22,3 @@ ledger.db.uri= | |||
| #账本数据库的连接口令 | |||
| ledger.db.pwd= | |||
| #共识配置文件路径 | |||
| #推荐使用绝对路径,相对路径以当前文件(local.conf)所在目录为基准 | |||
| consensus.conf=bftsmart.config | |||
| #共识Providers配置 | |||
| #BftSmart共识Provider:com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider | |||
| #简单消息共识Provider:com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider | |||
| consensus.service-provider=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider | |||
| @@ -81,7 +81,7 @@ public class GatewayQueryServiceHandler implements GatewayQueryService { | |||
| ledgerInitSettings.setSeed(initSeed(ledgerMetadata.getSeed())); | |||
| // 设置共识协议 | |||
| ledgerInitSettings.setConsensusProtocol(consensusProtocol(ledgerMetadata.getSetting().getConsensusProvider())); | |||
| ledgerInitSettings.setConsensusProtocol(ledgerMetadata.getSetting().getConsensusProvider()); | |||
| return ledgerInitSettings; | |||
| } | |||
| @@ -110,24 +110,6 @@ public class GatewayQueryServiceHandler implements GatewayQueryService { | |||
| return seed.toString(); | |||
| } | |||
| /** | |||
| * 生成共识协议 | |||
| * | |||
| * @param consensusProvider | |||
| * 共识协议提提供者 | |||
| * @return | |||
| */ | |||
| private int consensusProtocol(String consensusProvider) { | |||
| if (consensusProvider.equals(BftsmartConsensusProvider.NAME)) { | |||
| return LedgerInitSettings.CONSENSUS_PROTOCOL.BFTSMART.code(); | |||
| } else if (consensusProvider.equals(MsgQueueConsensusProvider.NAME)) { | |||
| return LedgerInitSettings.CONSENSUS_PROTOCOL.MSGQUEUE.code(); | |||
| } | |||
| return LedgerInitSettings.CONSENSUS_PROTOCOL.UNKNOWN.code(); | |||
| } | |||
| /** | |||
| * 初始化共识配置 | |||
| * | |||
| @@ -239,6 +239,13 @@ public class BlockBrowserController implements BlockchainExtendQueryService { | |||
| return peerService.getQueryService().getDataEntries(ledgerHash, address, keys); | |||
| } | |||
| @RequestMapping(method = {RequestMethod.GET, RequestMethod.POST}, path = "ledgers/{ledgerHash}/accounts/{address}/entries-version") | |||
| public KVDataEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, | |||
| @PathVariable("address") String address, | |||
| @RequestBody KVInfoVO kvInfoVO) { | |||
| return peerService.getQueryService().getDataEntries(ledgerHash, address, kvInfoVO); | |||
| } | |||
| @RequestMapping(method = {RequestMethod.GET, RequestMethod.POST}, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") | |||
| @Override | |||
| public KVDataEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, | |||
| @@ -1,22 +1,37 @@ | |||
| package com.jd.blockchain.ledger.core; | |||
| import java.util.HashMap; | |||
| import com.jd.blockchain.crypto.CryptoAlgorithm; | |||
| import com.jd.blockchain.crypto.CryptoProvider; | |||
| import com.jd.blockchain.ledger.CryptoSetting; | |||
| public class CryptoConfig implements CryptoSetting { | |||
| private CryptoProvider[] cryptoProviders; | |||
| private short hashAlgorithm; | |||
| private boolean autoVerifyHash; | |||
| HashMap<String, CryptoProvider> providers; | |||
| HashMap<String, CryptoAlgorithm> nameAlgorithms; | |||
| HashMap<Short, CryptoAlgorithm> codeAlgorithms; | |||
| public CryptoConfig() { | |||
| } | |||
| public CryptoConfig(CryptoSetting setting) { | |||
| this.hashAlgorithm = setting.getHashAlgorithm(); | |||
| setSupportedProviders(setting.getSupportedProviders()); | |||
| setHashAlgorithm(setting.getHashAlgorithm()); | |||
| this.autoVerifyHash = setting.getAutoVerifyHash(); | |||
| } | |||
| @Override | |||
| public CryptoProvider[] getSupportedProviders() { | |||
| return cryptoProviders == null ? null : cryptoProviders.clone(); | |||
| } | |||
| @Override | |||
| public short getHashAlgorithm() { | |||
| return hashAlgorithm; | |||
| @@ -27,11 +42,47 @@ public class CryptoConfig implements CryptoSetting { | |||
| return autoVerifyHash; | |||
| } | |||
| public void setSupportedProviders(CryptoProvider[] supportedProviders) { | |||
| HashMap<String, CryptoProvider> providers = new HashMap<String, CryptoProvider>(); | |||
| HashMap<String, CryptoAlgorithm> nameAlgorithms = new HashMap<String, CryptoAlgorithm>(); | |||
| HashMap<Short, CryptoAlgorithm> codeAlgorithms = new HashMap<Short, CryptoAlgorithm>(); | |||
| if (supportedProviders != null) { | |||
| // 检查是否存在重复的提供者以及算法; | |||
| for (CryptoProvider cryptoProvider : supportedProviders) { | |||
| if (providers.containsKey(cryptoProvider.getName())) { | |||
| throw new LedgerException("Duplicate crypto providers [" + cryptoProvider.getName() + "]!"); | |||
| } | |||
| CryptoAlgorithm[] algorithms = cryptoProvider.getAlgorithms(); | |||
| for (CryptoAlgorithm alg : algorithms) { | |||
| if (nameAlgorithms.containsKey(alg.name())) { | |||
| throw new LedgerException("Duplicate crypto algorithms [" + alg.toString() + "] from provider " | |||
| + cryptoProvider.getName() + "!"); | |||
| } | |||
| if (codeAlgorithms.containsKey(alg.code())) { | |||
| throw new LedgerException("Duplicate crypto algorithms [" + alg.toString() + "] from provider" | |||
| + cryptoProvider.getName() + "!"); | |||
| } | |||
| nameAlgorithms.put(alg.name(), alg); | |||
| codeAlgorithms.put(alg.code(), alg); | |||
| } | |||
| providers.put(cryptoProvider.getName(), cryptoProvider); | |||
| } | |||
| } | |||
| this.providers = providers; | |||
| this.nameAlgorithms = nameAlgorithms; | |||
| this.codeAlgorithms = codeAlgorithms; | |||
| this.cryptoProviders = supportedProviders; | |||
| } | |||
| public void setHashAlgorithm(CryptoAlgorithm hashAlgorithm) { | |||
| this.hashAlgorithm = hashAlgorithm.code(); | |||
| setHashAlgorithm(hashAlgorithm.code()); | |||
| } | |||
| public void setHashAlgorithm(short hashAlgorithm) { | |||
| if (codeAlgorithms == null || !codeAlgorithms.containsKey(hashAlgorithm)) { | |||
| throw new LedgerException("The specified algorithm[" + hashAlgorithm + "] has no provider!"); | |||
| } | |||
| this.hashAlgorithm = hashAlgorithm; | |||
| } | |||
| @@ -157,6 +157,9 @@ public class DataAccount implements AccountHeader, MerkleProvable { | |||
| * @return return total count; | |||
| */ | |||
| public long getDataEntriesTotalCount() { | |||
| if(baseAccount == null){ | |||
| return 0; | |||
| } | |||
| return baseAccount.dataset.getDataCount(); | |||
| } | |||
| @@ -3,10 +3,15 @@ package com.jd.blockchain.ledger.core.impl; | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.CryptoAlgorithm; | |||
| import com.jd.blockchain.crypto.CryptoProvider; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.CryptoSetting; | |||
| import com.jd.blockchain.ledger.LedgerInitSetting; | |||
| import com.jd.blockchain.ledger.core.LedgerConsts; | |||
| import com.jd.blockchain.ledger.core.LedgerEditor; | |||
| import com.jd.blockchain.ledger.core.LedgerException; | |||
| import com.jd.blockchain.ledger.core.LedgerManage; | |||
| import com.jd.blockchain.ledger.core.LedgerRepository; | |||
| import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
| @@ -57,26 +62,83 @@ public class LedgerManager implements LedgerManage { | |||
| @Override | |||
| public LedgerRepository register(HashDigest ledgerHash, KVStorageService storageService) { | |||
| // 加载账本数据库; | |||
| VersioningKVStorage ledgerVersioningStorage = storageService.getVersioningKVStorage(); | |||
| ExPolicyKVStorage ledgerExPolicyStorage = storageService.getExPolicyKVStorage(); | |||
| LedgerRepository ledgerRepo = new LedgerRepositoryImpl(ledgerHash, LEDGER_PREFIX, ledgerExPolicyStorage, | |||
| ledgerVersioningStorage); | |||
| LedgerRepositoryContext ledgerCtx = new LedgerRepositoryContext(); | |||
| ledgerCtx.ledgerRepo = ledgerRepo; | |||
| ledgerCtx.storageService = storageService; | |||
| // 校验 crypto service provider ; | |||
| CryptoSetting cryptoSetting = ledgerRepo.getAdminAccount().getSetting().getCryptoSetting(); | |||
| checkCryptoSetting(cryptoSetting, ledgerHash); | |||
| // 创建账本上下文; | |||
| LedgerRepositoryContext ledgerCtx = new LedgerRepositoryContext(ledgerRepo, storageService); | |||
| ledgers.put(ledgerHash, ledgerCtx); | |||
| return ledgerRepo; | |||
| } | |||
| /** | |||
| * 检查账本的密码参数设置与本地节点的运行时环境是否匹配; | |||
| * | |||
| * @param cryptoSetting | |||
| * @param ledgerHash | |||
| */ | |||
| private void checkCryptoSetting(CryptoSetting cryptoSetting, HashDigest ledgerHash) { | |||
| CryptoProvider[] cryptoProviders = cryptoSetting.getSupportedProviders(); | |||
| if (cryptoProviders == null || cryptoProviders.length == 0) { | |||
| throw new LedgerException("No supported crypto service providers has been setted in the ledger[" | |||
| + ledgerHash.toBase58() + "]!"); | |||
| } | |||
| for (CryptoProvider cp : cryptoProviders) { | |||
| CryptoProvider regCp = Crypto.getProvider(cp.getName()); | |||
| checkCryptoProviderConsistency(regCp, cp); | |||
| } | |||
| } | |||
| /** | |||
| * 检查密码服务提供者的信息是否匹配; | |||
| * | |||
| * @param registeredProvider | |||
| * @param settingProvider | |||
| */ | |||
| private void checkCryptoProviderConsistency(CryptoProvider registeredProvider, CryptoProvider settingProvider) { | |||
| if (registeredProvider == null) { | |||
| throw new LedgerException("Crypto service provider[" + settingProvider.getName() | |||
| + "] has not registered in the runtime environment of current peer!"); | |||
| } | |||
| CryptoAlgorithm[] runtimeAlgothms = registeredProvider.getAlgorithms(); | |||
| CryptoAlgorithm[] settingAlgothms = settingProvider.getAlgorithms(); | |||
| if (runtimeAlgothms.length != settingAlgothms.length) { | |||
| throw new LedgerException("Crypto service provider[" + settingProvider.getName() | |||
| + "] has not registered in runtime of current peer!"); | |||
| } | |||
| HashMap<Short, CryptoAlgorithm> runtimeAlgothmMap = new HashMap<Short, CryptoAlgorithm>(); | |||
| for (CryptoAlgorithm alg : runtimeAlgothms) { | |||
| runtimeAlgothmMap.put(alg.code(), alg); | |||
| } | |||
| for (CryptoAlgorithm alg : settingAlgothms) { | |||
| CryptoAlgorithm regAlg = runtimeAlgothmMap.get(alg.code()); | |||
| if (regAlg == null) { | |||
| throw new LedgerException( | |||
| String.format("Crypto algorithm[%s] is not defined by provider[%s] in runtime of current peer!", | |||
| alg.toString(), registeredProvider.getName())); | |||
| } | |||
| if (!regAlg.name().equals(alg.name())) { | |||
| throw new LedgerException(String.format( | |||
| "Crypto algorithm[%s] do not match the same code algorithm[%s] defined by provider[%s] in runtime of current peer!", | |||
| CryptoAlgorithm.getString(alg), CryptoAlgorithm.getString(regAlg), | |||
| registeredProvider.getName())); | |||
| } | |||
| } | |||
| } | |||
| @Override | |||
| public void unregister(HashDigest ledgerHash) { | |||
| LedgerRepositoryContext ledgerCtx = ledgers.get(ledgerHash); | |||
| LedgerRepositoryContext ledgerCtx = ledgers.remove(ledgerHash); | |||
| if (ledgerCtx != null) { | |||
| ledgerCtx.ledgerRepo.close(); | |||
| ledgers.remove(ledgerHash); | |||
| ledgerCtx.ledgerRepo = null; | |||
| ledgerCtx.storageService = null; | |||
| } | |||
| } | |||
| @@ -88,18 +150,6 @@ public class LedgerManager implements LedgerManage { | |||
| */ | |||
| @Override | |||
| public LedgerEditor newLedger(LedgerInitSetting initSetting, KVStorageService storageService) { | |||
| // GenesisLedgerStorageProxy genesisStorageProxy = new | |||
| // GenesisLedgerStorageProxy(); | |||
| // BufferedKVStorage bufferedStorage = new | |||
| // BufferedKVStorage(genesisStorageProxy, genesisStorageProxy, false); | |||
| // LedgerEditor genesisBlockEditor = | |||
| // LedgerTransactionalEditor.createEditor(initSetting, | |||
| // bufferedStorage, bufferedStorage); | |||
| // return new LedgerInitializer(genesisBlockEditor, bufferedStorage, | |||
| // genesisStorageProxy, storageService, this); | |||
| LedgerEditor genesisBlockEditor = LedgerTransactionalEditor.createEditor(initSetting, LEDGER_PREFIX, | |||
| storageService.getExPolicyKVStorage(), storageService.getVersioningKVStorage()); | |||
| return genesisBlockEditor; | |||
| @@ -110,10 +160,16 @@ public class LedgerManager implements LedgerManage { | |||
| return LEDGER_PREFIX + base58LedgerHash + LedgerConsts.KEY_SEPERATOR; | |||
| } | |||
| private static class LedgerRepositoryContext { | |||
| private LedgerRepository ledgerRepo; | |||
| public final LedgerRepository ledgerRepo; | |||
| private KVStorageService storageService; | |||
| public final KVStorageService storageService; | |||
| public LedgerRepositoryContext(LedgerRepository ledgerRepo, KVStorageService storageService) { | |||
| this.ledgerRepo = ledgerRepo; | |||
| this.storageService = storageService; | |||
| } | |||
| } | |||
| } | |||
| @@ -2,6 +2,7 @@ package com.jd.blockchain.ledger.core.impl; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.binaryproto.PrimitiveType; | |||
| import com.jd.blockchain.contract.ContractException; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.*; | |||
| import com.jd.blockchain.ledger.core.ContractAccountSet; | |||
| @@ -15,6 +16,10 @@ import com.jd.blockchain.ledger.core.UserAccountSet; | |||
| import com.jd.blockchain.transaction.BlockchainQueryService; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.QueryUtil; | |||
| import com.jd.blockchain.utils.StringUtils; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| public class LedgerQueryService implements BlockchainQueryService { | |||
| @@ -263,6 +268,9 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
| long ver; | |||
| for (int i = 0; i < entries.length; i++) { | |||
| ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); | |||
| dataAccount.getBytes(Bytes.fromString(keys[i]),1); | |||
| if (ver < 0) { | |||
| entries[i] = new KVDataObject(keys[i], -1, PrimitiveType.NIL, null); | |||
| }else { | |||
| @@ -275,6 +283,60 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
| return entries; | |||
| } | |||
| public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { | |||
| //parse kvInfoVO; | |||
| List<String> keyList = new ArrayList<>(); | |||
| List<Long> versionList = new ArrayList<>(); | |||
| if(kvInfoVO != null){ | |||
| for(KVDataVO kvDataVO : kvInfoVO.getData()){ | |||
| for(Long version : kvDataVO.getVersion()){ | |||
| keyList.add(kvDataVO.getKey()); | |||
| versionList.add(version); | |||
| } | |||
| } | |||
| } | |||
| String[] keys = keyList.toArray(new String[keyList.size()]); | |||
| Long[] versions = versionList.toArray(new Long[versionList.size()]); | |||
| if (keys == null || keys.length == 0) { | |||
| return null; | |||
| } | |||
| if (versions == null || versions.length == 0) { | |||
| return null; | |||
| } | |||
| if(keys.length != versions.length){ | |||
| throw new ContractException("keys.length!=versions.length!"); | |||
| } | |||
| LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||
| DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | |||
| KVDataEntry[] entries = new KVDataEntry[keys.length]; | |||
| long ver = -1; | |||
| for (int i = 0; i < entries.length; i++) { | |||
| // ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); | |||
| // dataAccount.getBytes(Bytes.fromString(keys[i]),1); | |||
| ver = versions[i]; | |||
| if (ver < 0) { | |||
| entries[i] = new KVDataObject(keys[i], -1, PrimitiveType.NIL, null); | |||
| }else { | |||
| if(dataAccount.getDataEntriesTotalCount()==0 || | |||
| dataAccount.getBytes(Bytes.fromString(keys[i]), ver) == null){ | |||
| //is the address is not exist; the result is null; | |||
| entries[i] = new KVDataObject(keys[i], -1, PrimitiveType.NIL, null); | |||
| } else { | |||
| byte[] value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver); | |||
| BytesValue decodeData = BinaryProtocol.decode(value); | |||
| entries[i] = new KVDataObject(keys[i], ver, PrimitiveType.valueOf(decodeData.getType().CODE), decodeData.getValue().toBytes()); | |||
| } | |||
| } | |||
| } | |||
| return entries; | |||
| } | |||
| @Override | |||
| public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { | |||
| @@ -156,6 +156,11 @@ public class ContractLedgerContext implements LedgerContext { | |||
| return innerQueryService.getDataEntries(ledgerHash, address, keys); | |||
| } | |||
| @Override | |||
| public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { | |||
| return innerQueryService.getDataEntries(ledgerHash, address, kvInfoVO); | |||
| } | |||
| @Override | |||
| public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { | |||
| return innerQueryService.getDataEntries(ledgerHash, address, fromIndex, count); | |||
| @@ -6,8 +6,12 @@ import static org.junit.Assert.assertTrue; | |||
| import org.junit.Test; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.CryptoProvider; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; | |||
| import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
| import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
| import com.jd.blockchain.ledger.BlockchainKeypair; | |||
| import com.jd.blockchain.ledger.core.AccountSet; | |||
| @@ -17,6 +21,11 @@ import com.jd.blockchain.ledger.core.impl.OpeningAccessPolicy; | |||
| import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | |||
| public class AccountSetTest { | |||
| private static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(), | |||
| SMCryptoService.class.getName() }; | |||
| @Test | |||
| public void test() { | |||
| @@ -24,7 +33,12 @@ public class AccountSetTest { | |||
| MemoryKVStorage storage = new MemoryKVStorage(); | |||
| CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; | |||
| for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { | |||
| supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); | |||
| } | |||
| CryptoConfig cryptoConf = new CryptoConfig(); | |||
| cryptoConf.setSupportedProviders(supportedProviders); | |||
| cryptoConf.setAutoVerifyHash(true); | |||
| cryptoConf.setHashAlgorithm(ClassicAlgorithm.SHA256); | |||
| @@ -5,7 +5,11 @@ import static org.junit.Assert.assertFalse; | |||
| import org.junit.Test; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.CryptoProvider; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; | |||
| import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
| import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
| import com.jd.blockchain.ledger.BlockchainKeypair; | |||
| import com.jd.blockchain.ledger.core.BaseAccount; | |||
| @@ -22,12 +26,21 @@ import com.jd.blockchain.utils.io.BytesUtils; | |||
| */ | |||
| public class BaseAccountTest { | |||
| public static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(), | |||
| SMCryptoService.class.getName() }; | |||
| @Test | |||
| public void basicTest() { | |||
| String keyPrefix = ""; | |||
| MemoryKVStorage testStorage = new MemoryKVStorage(); | |||
| CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; | |||
| for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { | |||
| supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); | |||
| } | |||
| CryptoConfig cryptoConf = new CryptoConfig(); | |||
| cryptoConf.setSupportedProviders(supportedProviders); | |||
| cryptoConf.setAutoVerifyHash(true); | |||
| cryptoConf.setHashAlgorithm(ClassicAlgorithm.SHA256); | |||
| @@ -13,8 +13,12 @@ import com.jd.blockchain.ledger.LedgerMetadata; | |||
| import org.junit.Test; | |||
| import com.jd.blockchain.crypto.AddressEncoding; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.CryptoProvider; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; | |||
| import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
| import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
| import com.jd.blockchain.ledger.BlockchainKeypair; | |||
| import com.jd.blockchain.ledger.ParticipantNode; | |||
| @@ -30,6 +34,9 @@ import com.jd.blockchain.utils.net.NetworkAddress; | |||
| public class LedgerAdminAccountTest { | |||
| private static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(), | |||
| SMCryptoService.class.getName() }; | |||
| private Random rand = new Random(); | |||
| @Test | |||
| @@ -55,7 +62,13 @@ public class LedgerAdminAccountTest { | |||
| initSetting.setConsensusSettings(new Bytes(csSysSettingBytes)); | |||
| initSetting.setConsensusProvider("consensus-provider"); | |||
| CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; | |||
| for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { | |||
| supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); | |||
| } | |||
| CryptoConfig cryptoSetting = new CryptoConfig(); | |||
| cryptoSetting.setSupportedProviders(supportedProviders); | |||
| cryptoSetting.setAutoVerifyHash(true); | |||
| cryptoSetting.setHashAlgorithm(ClassicAlgorithm.SHA256); | |||
| initSetting.setCryptoSetting(cryptoSetting); | |||
| @@ -11,8 +11,11 @@ import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.crypto.AddressEncoding; | |||
| import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.CryptoProvider; | |||
| import com.jd.blockchain.crypto.SignatureFunction; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; | |||
| import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
| import com.jd.blockchain.ledger.BlockchainKeypair; | |||
| import com.jd.blockchain.ledger.LedgerBlock; | |||
| import com.jd.blockchain.ledger.LedgerInitSetting; | |||
| @@ -34,6 +37,10 @@ import com.jd.blockchain.utils.io.BytesUtils; | |||
| import com.jd.blockchain.utils.net.NetworkAddress; | |||
| public class LedgerEditerTest { | |||
| private static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(), | |||
| SMCryptoService.class.getName() }; | |||
| static { | |||
| DataContractRegistry.register(com.jd.blockchain.ledger.TransactionContent.class); | |||
| @@ -109,8 +116,14 @@ public class LedgerEditerTest { | |||
| private LedgerInitSetting createLedgerInitSetting() { | |||
| SignatureFunction signFunc = Crypto.getSignatureFunction("ED25519"); | |||
| CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; | |||
| for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { | |||
| supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); | |||
| } | |||
| CryptoConfig defCryptoSetting = new CryptoConfig(); | |||
| defCryptoSetting.setSupportedProviders(supportedProviders); | |||
| defCryptoSetting.setAutoVerifyHash(true); | |||
| defCryptoSetting.setHashAlgorithm(ClassicAlgorithm.SHA256); | |||
| @@ -12,7 +12,11 @@ import org.junit.Test; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.crypto.AddressEncoding; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.CryptoProvider; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; | |||
| import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
| import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
| import com.jd.blockchain.ledger.BlockchainKeypair; | |||
| import com.jd.blockchain.ledger.LedgerInitOperation; | |||
| @@ -27,6 +31,9 @@ import com.jd.blockchain.utils.net.NetworkAddress; | |||
| public class LedgerInitOperationTest { | |||
| private static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(), | |||
| SMCryptoService.class.getName() }; | |||
| byte[] seed = null; | |||
| byte[] csSysSettingBytes = null; | |||
| LedgerInitSettingData ledgerInitSettingData = new LedgerInitSettingData(); | |||
| @@ -44,7 +51,12 @@ public class LedgerInitOperationTest { | |||
| csSysSettingBytes = new byte[64]; | |||
| rand.nextBytes(csSysSettingBytes); | |||
| CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; | |||
| for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { | |||
| supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); | |||
| } | |||
| CryptoConfig cryptoConfig = new CryptoConfig(); | |||
| cryptoConfig.setSupportedProviders(supportedProviders); | |||
| cryptoConfig.setAutoVerifyHash(true); | |||
| cryptoConfig.setHashAlgorithm(ClassicAlgorithm.SHA256); | |||
| @@ -12,7 +12,11 @@ import org.junit.Test; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.crypto.AddressEncoding; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.CryptoProvider; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; | |||
| import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
| import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
| import com.jd.blockchain.ledger.BlockchainKeypair; | |||
| import com.jd.blockchain.ledger.LedgerInitSetting; | |||
| @@ -24,12 +28,15 @@ import com.jd.blockchain.transaction.LedgerInitSettingData; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.net.NetworkAddress; | |||
| public class LedgerInitSettingTest { | |||
| public class LedgerInitSettingSerializeTest { | |||
| byte[] seed = null; | |||
| byte[] csSysSettingBytes = null; | |||
| LedgerInitSettingData ledgerInitSettingData = new LedgerInitSettingData(); | |||
| LedgerInitOpTemplate template = new LedgerInitOpTemplate(); | |||
| private static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(), | |||
| SMCryptoService.class.getName() }; | |||
| @Before | |||
| public void initCfg() { | |||
| @@ -41,7 +48,13 @@ public class LedgerInitSettingTest { | |||
| csSysSettingBytes = new byte[64]; | |||
| rand.nextBytes(csSysSettingBytes); | |||
| CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; | |||
| for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { | |||
| supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); | |||
| } | |||
| CryptoConfig cryptoConfig = new CryptoConfig(); | |||
| cryptoConfig.setSupportedProviders(supportedProviders); | |||
| cryptoConfig.setAutoVerifyHash(true); | |||
| cryptoConfig.setHashAlgorithm(ClassicAlgorithm.SHA256); | |||
| @@ -71,7 +84,7 @@ public class LedgerInitSettingTest { | |||
| ConsensusParticipantData[] parties1 = Arrays.copyOf(parties, 4); | |||
| ledgerInitSettingData.setConsensusParticipants(parties1); | |||
| byte[] encode = BinaryProtocol.encode(ledgerInitSettingData, LedgerInitSetting.class); | |||
| LedgerInitSetting decode = BinaryProtocol.decode(encode); | |||
| @@ -13,9 +13,12 @@ import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.crypto.AddressEncoding; | |||
| import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.CryptoProvider; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.crypto.SignatureFunction; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; | |||
| import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
| import com.jd.blockchain.ledger.BlockBody; | |||
| import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
| import com.jd.blockchain.ledger.BlockchainKeypair; | |||
| @@ -54,8 +57,12 @@ public class LedgerManagerTest { | |||
| DataContractRegistry.register(UserRegisterOperation.class); | |||
| DataContractRegistry.register(DataAccountRegisterOperation.class); | |||
| DataContractRegistry.register(BlockBody.class); | |||
| DataContractRegistry.register(CryptoProvider.class); | |||
| } | |||
| public static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(), | |||
| SMCryptoService.class.getName() }; | |||
| private SignatureFunction signatureFunction; | |||
| @Before | |||
| @@ -170,7 +177,16 @@ public class LedgerManagerTest { | |||
| } | |||
| private LedgerInitSetting createLedgerInitSetting() { | |||
| CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; | |||
| for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { | |||
| supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); | |||
| } | |||
| CryptoConfig defCryptoSetting = new CryptoConfig(); | |||
| defCryptoSetting.setSupportedProviders(supportedProviders); | |||
| defCryptoSetting.setAutoVerifyHash(true); | |||
| defCryptoSetting.setHashAlgorithm(ClassicAlgorithm.SHA256); | |||
| @@ -15,9 +15,13 @@ import org.junit.Test; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.crypto.AddressEncoding; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.CryptoProvider; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; | |||
| import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
| import com.jd.blockchain.ledger.CryptoSetting; | |||
| import com.jd.blockchain.ledger.ParticipantNode; | |||
| import com.jd.blockchain.ledger.core.CryptoConfig; | |||
| @@ -30,6 +34,10 @@ import com.jd.blockchain.utils.Bytes; | |||
| * Created by zhangshuang3 on 2018/8/31. | |||
| */ | |||
| public class LedgerMetaDataTest { | |||
| private static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(), | |||
| SMCryptoService.class.getName() }; | |||
| byte[] seed = null; | |||
| String consensusProvider = "test-provider"; | |||
| byte[] consensusSettingBytes = null; | |||
| @@ -56,7 +64,13 @@ public class LedgerMetaDataTest { | |||
| // ConsensusConfig consensusConfig = new ConsensusConfig(); | |||
| // consensusConfig.setValue(settingValue);ClassicCryptoService.ED25519_ALGORITHM | |||
| CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; | |||
| for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { | |||
| supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); | |||
| } | |||
| CryptoConfig cryptoConfig = new CryptoConfig(); | |||
| cryptoConfig.setSupportedProviders(supportedProviders); | |||
| cryptoConfig.setAutoVerifyHash(true); | |||
| cryptoConfig.setHashAlgorithm(ClassicAlgorithm.SHA256); | |||
| @@ -93,7 +107,13 @@ public class LedgerMetaDataTest { | |||
| // ConsensusConfig consensusConfig = new ConsensusConfig(); | |||
| // consensusConfig.setValue(settingValue); | |||
| CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; | |||
| for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { | |||
| supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); | |||
| } | |||
| CryptoConfig cryptoConfig = new CryptoConfig(); | |||
| cryptoConfig.setSupportedProviders(supportedProviders); | |||
| cryptoConfig.setAutoVerifyHash(true); | |||
| cryptoConfig.setHashAlgorithm(ClassicAlgorithm.SHA256); | |||
| @@ -133,7 +153,14 @@ public class LedgerMetaDataTest { | |||
| @Test | |||
| public void testSerialize_CryptoSetting() { | |||
| // LedgerCodes.METADATA_LEDGER_SETTING_CRYPTO | |||
| CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; | |||
| for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { | |||
| supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); | |||
| } | |||
| CryptoConfig cryptoConfig = new CryptoConfig(); | |||
| cryptoConfig.setSupportedProviders(supportedProviders); | |||
| cryptoConfig.setAutoVerifyHash(true); | |||
| cryptoConfig.setHashAlgorithm(ClassicAlgorithm.SHA256); | |||
| byte[] encodeBytes = BinaryProtocol.encode(cryptoConfig, CryptoSetting.class); | |||
| @@ -4,10 +4,13 @@ import java.util.Random; | |||
| import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.CryptoProvider; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import com.jd.blockchain.crypto.SignatureFunction; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; | |||
| import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
| import com.jd.blockchain.ledger.BlockchainIdentityData; | |||
| import com.jd.blockchain.ledger.CryptoSetting; | |||
| import com.jd.blockchain.ledger.PreparedTransaction; | |||
| @@ -22,6 +25,9 @@ public class LedgerTestUtils { | |||
| // private static ThreadLocalRandom rand = ThreadLocalRandom.current(); | |||
| private static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(), | |||
| SMCryptoService.class.getName() }; | |||
| private static Random rand = new Random(); | |||
| public static TransactionRequest createTxRequest(HashDigest ledgerHash) { | |||
| @@ -76,7 +82,14 @@ public class LedgerTestUtils { | |||
| } | |||
| public static CryptoSetting createDefaultCryptoSetting() { | |||
| CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; | |||
| for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { | |||
| supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); | |||
| } | |||
| CryptoConfig cryptoSetting = new CryptoConfig(); | |||
| cryptoSetting.setSupportedProviders(supportedProviders); | |||
| cryptoSetting.setAutoVerifyHash(true); | |||
| cryptoSetting.setHashAlgorithm(ClassicAlgorithm.SHA256); | |||
| return cryptoSetting; | |||
| @@ -14,8 +14,12 @@ import java.util.Set; | |||
| import org.junit.Test; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.CryptoProvider; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; | |||
| import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; | |||
| import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
| import com.jd.blockchain.ledger.core.CryptoConfig; | |||
| import com.jd.blockchain.ledger.core.MerkleDataSet; | |||
| import com.jd.blockchain.ledger.core.MerkleProof; | |||
| @@ -26,13 +30,23 @@ import com.jd.blockchain.utils.io.BytesUtils; | |||
| public class MerkleDataSetTest { | |||
| private static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(), | |||
| SMCryptoService.class.getName() }; | |||
| /** | |||
| * 测试存储的增长; | |||
| */ | |||
| @Test | |||
| public void testStorageIncreasement() { | |||
| CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; | |||
| for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { | |||
| supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); | |||
| } | |||
| String keyPrefix = ""; | |||
| CryptoConfig cryptoConfig = new CryptoConfig(); | |||
| cryptoConfig.setSupportedProviders(supportedProviders); | |||
| cryptoConfig.setHashAlgorithm(ClassicAlgorithm.SHA256); | |||
| cryptoConfig.setAutoVerifyHash(true); | |||
| @@ -116,7 +130,13 @@ public class MerkleDataSetTest { | |||
| String keyPrefix = ""; | |||
| Random rand = new Random(); | |||
| CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; | |||
| for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { | |||
| supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); | |||
| } | |||
| CryptoConfig cryptoConfig = new CryptoConfig(); | |||
| cryptoConfig.setSupportedProviders(supportedProviders); | |||
| cryptoConfig.setHashAlgorithm(ClassicAlgorithm.SHA256); | |||
| cryptoConfig.setAutoVerifyHash(true); | |||
| @@ -281,7 +301,13 @@ public class MerkleDataSetTest { | |||
| String keyPrefix = ""; | |||
| Random rand = new Random(); | |||
| CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; | |||
| for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { | |||
| supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); | |||
| } | |||
| CryptoConfig cryptoConfig = new CryptoConfig(); | |||
| cryptoConfig.setSupportedProviders(supportedProviders); | |||
| cryptoConfig.setHashAlgorithm(ClassicAlgorithm.SHA256); | |||
| cryptoConfig.setAutoVerifyHash(true); | |||
| @@ -1,26 +1,48 @@ | |||
| package com.jd.blockchain.ledger; | |||
| import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.binaryproto.DataField; | |||
| import com.jd.blockchain.binaryproto.PrimitiveType; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| /** | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| @DataContract(code= DataCodes.TX_OP_CONTRACT_EVENT_SEND) | |||
| public interface ContractEventSendOperation extends Operation { | |||
| @DataField(order=2, primitiveType=PrimitiveType.BYTES) | |||
| Bytes getContractAddress(); | |||
| @DataField(order=3, primitiveType=PrimitiveType.TEXT) | |||
| String getEvent(); | |||
| @DataField(order=4, primitiveType=PrimitiveType.BYTES) | |||
| byte[] getArgs(); | |||
| } | |||
| package com.jd.blockchain.ledger; | |||
| import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.binaryproto.DataField; | |||
| import com.jd.blockchain.binaryproto.PrimitiveType; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| /** | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| @DataContract(code = DataCodes.TX_OP_CONTRACT_EVENT_SEND) | |||
| public interface ContractEventSendOperation extends Operation { | |||
| /** | |||
| * 响应事件的合约地址; | |||
| * | |||
| * @return | |||
| */ | |||
| @DataField(order = 2, primitiveType = PrimitiveType.BYTES) | |||
| Bytes getContractAddress(); | |||
| /** | |||
| * 事件名; | |||
| * | |||
| * @return | |||
| */ | |||
| @DataField(order = 3, primitiveType = PrimitiveType.TEXT) | |||
| String getEvent(); | |||
| /** | |||
| * 事件参数; | |||
| * | |||
| * @return | |||
| */ | |||
| @DataField(order = 4, primitiveType = PrimitiveType.BYTES) | |||
| byte[] getArgs(); | |||
| /** | |||
| * 时间戳; | |||
| * | |||
| * @return | |||
| */ | |||
| @DataField(order = 5, primitiveType = PrimitiveType.INT64) | |||
| long getTs(); | |||
| } | |||
| @@ -1,12 +0,0 @@ | |||
| package com.jd.blockchain.ledger; | |||
| import com.jd.blockchain.crypto.CryptoAlgorithm; | |||
| public interface CryptoProviderInfo { | |||
| String getName(); | |||
| CryptoAlgorithm[] getAlgorithms(); | |||
| } | |||
| @@ -4,6 +4,7 @@ import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.binaryproto.DataField; | |||
| import com.jd.blockchain.binaryproto.PrimitiveType; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| import com.jd.blockchain.crypto.CryptoProvider; | |||
| /** | |||
| * 默克尔树算法相关的配置; | |||
| @@ -14,6 +15,16 @@ import com.jd.blockchain.consts.DataCodes; | |||
| @DataContract(code = DataCodes.METADATA_CRYPTO_SETTING) | |||
| public interface CryptoSetting { | |||
| /** | |||
| * 系统支持的密码服务提供者; | |||
| * | |||
| * @return | |||
| */ | |||
| @DataField(order = 0, refContract = true, list = true) | |||
| public CryptoProvider[] getSupportedProviders(); | |||
| /** | |||
| * 系统中使用的 Hash 算法; <br> | |||
| * | |||
| @@ -27,7 +38,7 @@ public interface CryptoSetting { | |||
| public short getHashAlgorithm(); | |||
| /** | |||
| * 当有完整性证明的数据被从持久化介质中加载时,是否对其进行完整性校验(重新计算 hash 比对是否一致); <br> | |||
| * 当有加载附带哈希摘要的数据时,是否重新计算哈希摘要进行完整性校验; <br> | |||
| * | |||
| * 如果为 true ,则自动进行校验,如果校验失败,会引发异常; <br> | |||
| * | |||
| @@ -37,5 +48,6 @@ public interface CryptoSetting { | |||
| */ | |||
| @DataField(order = 2, primitiveType = PrimitiveType.BOOLEAN) | |||
| public boolean getAutoVerifyHash(); | |||
| } | |||
| @@ -0,0 +1,26 @@ | |||
| package com.jd.blockchain.ledger; | |||
| /** | |||
| * @author zhaogw | |||
| * date 2019/5/14 14:17 | |||
| */ | |||
| public class KVDataVO { | |||
| private String key; | |||
| private long[] version; | |||
| public String getKey() { | |||
| return key; | |||
| } | |||
| public void setKey(String key) { | |||
| this.key = key; | |||
| } | |||
| public long[] getVersion() { | |||
| return version; | |||
| } | |||
| public void setVersion(long[] version) { | |||
| this.version = version; | |||
| } | |||
| } | |||
| @@ -0,0 +1,18 @@ | |||
| package com.jd.blockchain.ledger; | |||
| /** | |||
| * for BlockBrowserController.java, param is json ,then match it; | |||
| * @author zhaogw | |||
| * date 2019/5/14 14:19 | |||
| */ | |||
| public class KVInfoVO { | |||
| private KVDataVO[] data; | |||
| public KVDataVO[] getData() { | |||
| return data; | |||
| } | |||
| public void setData(KVDataVO[] data) { | |||
| this.data = data; | |||
| } | |||
| } | |||
| @@ -22,6 +22,7 @@ public interface ParticipantNode {// extends ConsensusNode, ParticipantInfo { | |||
| * | |||
| * @return | |||
| */ | |||
| @DataField(order = 0, primitiveType = PrimitiveType.INT32) | |||
| int getId(); | |||
| /** | |||
| @@ -1,21 +1,21 @@ | |||
| package com.jd.blockchain.ledger; | |||
| import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.binaryproto.DataField; | |||
| import com.jd.blockchain.binaryproto.PrimitiveType; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| /** | |||
| * 交易内容; | |||
| * | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| @DataContract(code= DataCodes.TX_CONTENT) | |||
| public interface TransactionContent extends TransactionContentBody, HashObject { | |||
| @Override | |||
| @DataField(order=1, primitiveType = PrimitiveType.BYTES) | |||
| HashDigest getHash(); | |||
| } | |||
| package com.jd.blockchain.ledger; | |||
| import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.binaryproto.DataField; | |||
| import com.jd.blockchain.binaryproto.PrimitiveType; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| /** | |||
| * 交易内容; | |||
| * | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| @DataContract(code= DataCodes.TX_CONTENT) | |||
| public interface TransactionContent extends TransactionContentBody, HashObject { | |||
| @Override | |||
| @DataField(order=1, primitiveType = PrimitiveType.BYTES) | |||
| HashDigest getHash(); | |||
| } | |||
| @@ -1,36 +1,36 @@ | |||
| package com.jd.blockchain.ledger; | |||
| import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.binaryproto.DataField; | |||
| import com.jd.blockchain.binaryproto.PrimitiveType; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| /** | |||
| * 交易内容; | |||
| * | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| @DataContract(code = DataCodes.TX_CONTENT_BODY) | |||
| public interface TransactionContentBody { | |||
| /** | |||
| * 执行交易的账本地址; | |||
| * | |||
| * 注:除了账本的创世交易之外,任何交易的账本地址都不允许为 null; | |||
| * | |||
| * @return | |||
| */ | |||
| @DataField(order = 1, primitiveType = PrimitiveType.BYTES) | |||
| HashDigest getLedgerHash(); | |||
| /** | |||
| * 操作列表; | |||
| * | |||
| * @return | |||
| */ | |||
| @DataField(order = 2, list = true, refContract = true, genericContract = true) | |||
| Operation[] getOperations(); | |||
| } | |||
| package com.jd.blockchain.ledger; | |||
| import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.binaryproto.DataField; | |||
| import com.jd.blockchain.binaryproto.PrimitiveType; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| /** | |||
| * 交易内容; | |||
| * | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| @DataContract(code = DataCodes.TX_CONTENT_BODY) | |||
| public interface TransactionContentBody { | |||
| /** | |||
| * 执行交易的账本地址; | |||
| * | |||
| * 注:除了账本的创世交易之外,任何交易的账本地址都不允许为 null; | |||
| * | |||
| * @return | |||
| */ | |||
| @DataField(order = 1, primitiveType = PrimitiveType.BYTES) | |||
| HashDigest getLedgerHash(); | |||
| /** | |||
| * 操作列表; | |||
| * | |||
| * @return | |||
| */ | |||
| @DataField(order = 2, list = true, refContract = true, genericContract = true) | |||
| Operation[] getOperations(); | |||
| } | |||
| @@ -29,6 +29,11 @@ public enum TransactionState { | |||
| */ | |||
| LEDGER_ERROR((byte) 2), | |||
| /** | |||
| * 数据序列更新错误; | |||
| */ | |||
| DATA_SEQUENCE_UPDATE_ERROR((byte) 3), | |||
| /** | |||
| * 系统错误; | |||
| */ | |||
| @@ -261,6 +261,8 @@ public interface BlockchainQueryService { | |||
| */ | |||
| KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys); | |||
| KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO); | |||
| /** | |||
| * 返回指定数据账户中KV数据的总数; <br> | |||
| * | |||
| @@ -1,40 +1,50 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| public class ContractEventSendOpTemplate implements ContractEventSendOperation { | |||
| static { | |||
| DataContractRegistry.register(ContractEventSendOperation.class); | |||
| } | |||
| private Bytes contractAddress; | |||
| private byte[] args; | |||
| private String event; | |||
| public ContractEventSendOpTemplate() { | |||
| } | |||
| public ContractEventSendOpTemplate(Bytes contractAddress, String event, byte[] args) { | |||
| this.contractAddress = contractAddress; | |||
| this.event = event; | |||
| this.args = args; | |||
| } | |||
| @Override | |||
| public Bytes getContractAddress() { | |||
| return contractAddress; | |||
| } | |||
| @Override | |||
| public String getEvent() { | |||
| return event; | |||
| } | |||
| @Override | |||
| public byte[] getArgs() { | |||
| return args; | |||
| } | |||
| } | |||
| package com.jd.blockchain.transaction; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| public class ContractEventSendOpTemplate implements ContractEventSendOperation { | |||
| static { | |||
| DataContractRegistry.register(ContractEventSendOperation.class); | |||
| } | |||
| private Bytes contractAddress; | |||
| private byte[] args; | |||
| private String event; | |||
| private long ts; | |||
| public ContractEventSendOpTemplate() { | |||
| } | |||
| public ContractEventSendOpTemplate(Bytes contractAddress, String event, byte[] args) { | |||
| this.contractAddress = contractAddress; | |||
| this.event = event; | |||
| this.args = args; | |||
| } | |||
| @Override | |||
| public Bytes getContractAddress() { | |||
| return contractAddress; | |||
| } | |||
| @Override | |||
| public String getEvent() { | |||
| return event; | |||
| } | |||
| @Override | |||
| public byte[] getArgs() { | |||
| return args; | |||
| } | |||
| @Override | |||
| public long getTs() { | |||
| return ts; | |||
| } | |||
| public void setTs(long ts) { | |||
| this.ts = ts; | |||
| } | |||
| } | |||
| @@ -4,18 +4,19 @@ import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| @Deprecated | |||
| class ContractEventSendOperationBuilderImpl implements ContractEventSendOperationBuilder{ | |||
| class ContractEventSendOperationBuilderImpl implements ContractEventSendOperationBuilder { | |||
| @Override | |||
| public ContractEventSendOperation send(String address, String event, byte[] args) { | |||
| ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(Bytes.fromBase58(address), event, args); | |||
| op.setTs(System.currentTimeMillis()); | |||
| return op; | |||
| } | |||
| @Override | |||
| public ContractEventSendOperation send(Bytes address, String event, byte[] args) { | |||
| ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args); | |||
| op.setTs(System.currentTimeMillis()); | |||
| return op; | |||
| } | |||
| @@ -49,7 +49,7 @@ public class DataAccountKVSetOpTemplate implements DataAccountKVSetOperation { | |||
| public void set(String key, BytesValue value, long expVersion) { | |||
| if (kvset.containsKey(key)) { | |||
| throw new IllegalArgumentException("Cann't set the same key repeatly!"); | |||
| throw new IllegalArgumentException("Cann't set the same key repeatedly!"); | |||
| } | |||
| KVData kvdata = new KVData(key, value, expVersion); | |||
| kvset.put(key, kvdata); | |||
| @@ -57,7 +57,7 @@ public class DataAccountKVSetOpTemplate implements DataAccountKVSetOperation { | |||
| public void set(KVData kvData) { | |||
| if (kvset.containsKey(kvData.getKey())) { | |||
| throw new IllegalArgumentException("Cann't set the same key repeatly!"); | |||
| throw new IllegalArgumentException("Cann't set the same key repeatedly!"); | |||
| } | |||
| kvset.put(kvData.getKey(), kvData); | |||
| } | |||
| @@ -1,96 +1,96 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.TransactionBuilder; | |||
| import com.jd.blockchain.ledger.TransactionContent; | |||
| import com.jd.blockchain.ledger.TransactionContentBody; | |||
| import com.jd.blockchain.ledger.TransactionRequestBuilder; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| public class TxBuilder implements TransactionBuilder { | |||
| static { | |||
| DataContractRegistry.register(TransactionContentBody.class); | |||
| } | |||
| private BlockchainOperationFactory opFactory = new BlockchainOperationFactory(); | |||
| private static final String DEFAULT_HASH_ALGORITHM = "SHA256"; | |||
| private HashDigest ledgerHash; | |||
| public TxBuilder(HashDigest ledgerHash) { | |||
| this.ledgerHash = ledgerHash; | |||
| } | |||
| @Override | |||
| public HashDigest getLedgerHash() { | |||
| return ledgerHash; | |||
| } | |||
| @Override | |||
| public TransactionRequestBuilder prepareRequest() { | |||
| TransactionContent txContent = prepareContent(); | |||
| return new TxRequestBuilder(txContent); | |||
| } | |||
| @Override | |||
| public TransactionContent prepareContent() { | |||
| TxContentBlob txContent = new TxContentBlob(ledgerHash); | |||
| txContent.addOperations(opFactory.getOperations()); | |||
| byte[] contentBodyBytes = BinaryProtocol.encode(txContent, TransactionContentBody.class); | |||
| HashDigest contentHash = Crypto.getHashFunction(DEFAULT_HASH_ALGORITHM).hash(contentBodyBytes); | |||
| txContent.setHash(contentHash); | |||
| return txContent; | |||
| } | |||
| @Override | |||
| public LedgerInitOperationBuilder ledgers() { | |||
| return opFactory.ledgers(); | |||
| } | |||
| @Override | |||
| public UserRegisterOperationBuilder users() { | |||
| return opFactory.users(); | |||
| } | |||
| @Override | |||
| public DataAccountRegisterOperationBuilder dataAccounts() { | |||
| return opFactory.dataAccounts(); | |||
| } | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder dataAccount(String accountAddress) { | |||
| return opFactory.dataAccount(accountAddress); | |||
| } | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder dataAccount(Bytes accountAddress) { | |||
| return opFactory.dataAccount(accountAddress); | |||
| } | |||
| @Override | |||
| public ContractCodeDeployOperationBuilder contracts() { | |||
| return opFactory.contracts(); | |||
| } | |||
| public ContractEventSendOperationBuilder contractEvents() { | |||
| return opFactory.contractEvents(); | |||
| } | |||
| @Override | |||
| public <T> T contract(Bytes address, Class<T> contractIntf) { | |||
| return opFactory.contract(address, contractIntf); | |||
| } | |||
| @Override | |||
| public <T> T contract(String address, Class<T> contractIntf) { | |||
| return opFactory.contract(address, contractIntf); | |||
| } | |||
| } | |||
| package com.jd.blockchain.transaction; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.TransactionBuilder; | |||
| import com.jd.blockchain.ledger.TransactionContent; | |||
| import com.jd.blockchain.ledger.TransactionContentBody; | |||
| import com.jd.blockchain.ledger.TransactionRequestBuilder; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| public class TxBuilder implements TransactionBuilder { | |||
| static { | |||
| DataContractRegistry.register(TransactionContentBody.class); | |||
| } | |||
| private BlockchainOperationFactory opFactory = new BlockchainOperationFactory(); | |||
| private static final String DEFAULT_HASH_ALGORITHM = "SHA256"; | |||
| private HashDigest ledgerHash; | |||
| public TxBuilder(HashDigest ledgerHash) { | |||
| this.ledgerHash = ledgerHash; | |||
| } | |||
| @Override | |||
| public HashDigest getLedgerHash() { | |||
| return ledgerHash; | |||
| } | |||
| @Override | |||
| public TransactionRequestBuilder prepareRequest() { | |||
| TransactionContent txContent = prepareContent(); | |||
| return new TxRequestBuilder(txContent); | |||
| } | |||
| @Override | |||
| public TransactionContent prepareContent() { | |||
| TxContentBlob txContent = new TxContentBlob(ledgerHash); | |||
| txContent.addOperations(opFactory.getOperations()); | |||
| byte[] contentBodyBytes = BinaryProtocol.encode(txContent, TransactionContentBody.class); | |||
| HashDigest contentHash = Crypto.getHashFunction(DEFAULT_HASH_ALGORITHM).hash(contentBodyBytes); | |||
| txContent.setHash(contentHash); | |||
| return txContent; | |||
| } | |||
| @Override | |||
| public LedgerInitOperationBuilder ledgers() { | |||
| return opFactory.ledgers(); | |||
| } | |||
| @Override | |||
| public UserRegisterOperationBuilder users() { | |||
| return opFactory.users(); | |||
| } | |||
| @Override | |||
| public DataAccountRegisterOperationBuilder dataAccounts() { | |||
| return opFactory.dataAccounts(); | |||
| } | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder dataAccount(String accountAddress) { | |||
| return opFactory.dataAccount(accountAddress); | |||
| } | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder dataAccount(Bytes accountAddress) { | |||
| return opFactory.dataAccount(accountAddress); | |||
| } | |||
| @Override | |||
| public ContractCodeDeployOperationBuilder contracts() { | |||
| return opFactory.contracts(); | |||
| } | |||
| public ContractEventSendOperationBuilder contractEvents() { | |||
| return opFactory.contractEvents(); | |||
| } | |||
| @Override | |||
| public <T> T contract(Bytes address, Class<T> contractIntf) { | |||
| return opFactory.contract(address, contractIntf); | |||
| } | |||
| @Override | |||
| public <T> T contract(String address, Class<T> contractIntf) { | |||
| return opFactory.contract(address, contractIntf); | |||
| } | |||
| } | |||
| @@ -1,91 +1,91 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import java.util.ArrayList; | |||
| import java.util.Collection; | |||
| import java.util.List; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.Operation; | |||
| import com.jd.blockchain.ledger.TransactionContent; | |||
| import com.jd.blockchain.utils.io.NumberMask; | |||
| /** | |||
| * 交易内容的数据块; | |||
| * <p> | |||
| * | |||
| * 包含原始交易请求的数据块; | |||
| * | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| public class TxContentBlob implements TransactionContent { | |||
| /** | |||
| * 操作数量的最大值; | |||
| */ | |||
| public static final int MAX_OP_COUNT = NumberMask.SHORT.MAX_BOUNDARY_SIZE; | |||
| private List<Operation> operationList = new ArrayList<Operation>(); | |||
| private HashDigest hash; | |||
| private HashDigest ledgerHash; | |||
| public TxContentBlob(HashDigest ledgerHash) { | |||
| this.ledgerHash = ledgerHash; | |||
| } | |||
| /** | |||
| * 交易内容的哈希值; | |||
| */ | |||
| @Override | |||
| public HashDigest getHash() { | |||
| return this.hash; | |||
| } | |||
| /** | |||
| * 更新交易内容的哈希值; | |||
| * <p> | |||
| * 注:当前对象只充当值对象,不校验指定哈希值的完整性,调用者应该在外部实施完整性校验; | |||
| * | |||
| * @param hash | |||
| */ | |||
| public void setHash(HashDigest hash) { | |||
| this.hash = hash; | |||
| } | |||
| /** | |||
| * 交易请求链的hash | |||
| * | |||
| * @return | |||
| */ | |||
| @Override | |||
| public HashDigest getLedgerHash() { | |||
| return ledgerHash; | |||
| } | |||
| public void setLedgerHash(HashDigest ledgerHash) { | |||
| this.ledgerHash = ledgerHash; | |||
| } | |||
| @Override | |||
| public Operation[] getOperations() { | |||
| return operationList.toArray(new Operation[operationList.size()]); | |||
| } | |||
| public void setOperations(Object[] operations) { | |||
| // in array's case ,cast will failed! | |||
| for (Object operation : operations) { | |||
| Operation op = (Operation) operation; | |||
| addOperation(op); | |||
| } | |||
| } | |||
| public void addOperation(Operation operation) { | |||
| operationList.add(operation); | |||
| } | |||
| public void addOperations(Collection<Operation> operations) { | |||
| operationList.addAll(operations); | |||
| } | |||
| } | |||
| package com.jd.blockchain.transaction; | |||
| import java.util.ArrayList; | |||
| import java.util.Collection; | |||
| import java.util.List; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.Operation; | |||
| import com.jd.blockchain.ledger.TransactionContent; | |||
| import com.jd.blockchain.utils.io.NumberMask; | |||
| /** | |||
| * 交易内容的数据块; | |||
| * <p> | |||
| * | |||
| * 包含原始交易请求的数据块; | |||
| * | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| public class TxContentBlob implements TransactionContent { | |||
| /** | |||
| * 操作数量的最大值; | |||
| */ | |||
| public static final int MAX_OP_COUNT = NumberMask.SHORT.MAX_BOUNDARY_SIZE; | |||
| private List<Operation> operationList = new ArrayList<Operation>(); | |||
| private HashDigest hash; | |||
| private HashDigest ledgerHash; | |||
| public TxContentBlob(HashDigest ledgerHash) { | |||
| this.ledgerHash = ledgerHash; | |||
| } | |||
| /** | |||
| * 交易内容的哈希值; | |||
| */ | |||
| @Override | |||
| public HashDigest getHash() { | |||
| return this.hash; | |||
| } | |||
| /** | |||
| * 更新交易内容的哈希值; | |||
| * <p> | |||
| * 注:当前对象只充当值对象,不校验指定哈希值的完整性,调用者应该在外部实施完整性校验; | |||
| * | |||
| * @param hash | |||
| */ | |||
| public void setHash(HashDigest hash) { | |||
| this.hash = hash; | |||
| } | |||
| /** | |||
| * 交易请求链的hash | |||
| * | |||
| * @return | |||
| */ | |||
| @Override | |||
| public HashDigest getLedgerHash() { | |||
| return ledgerHash; | |||
| } | |||
| public void setLedgerHash(HashDigest ledgerHash) { | |||
| this.ledgerHash = ledgerHash; | |||
| } | |||
| @Override | |||
| public Operation[] getOperations() { | |||
| return operationList.toArray(new Operation[operationList.size()]); | |||
| } | |||
| public void setOperations(Object[] operations) { | |||
| // in array's case ,cast will failed! | |||
| for (Object operation : operations) { | |||
| Operation op = (Operation) operation; | |||
| addOperation(op); | |||
| } | |||
| } | |||
| public void addOperation(Operation operation) { | |||
| operationList.add(operation); | |||
| } | |||
| public void addOperations(Collection<Operation> operations) { | |||
| operationList.addAll(operations); | |||
| } | |||
| } | |||
| @@ -0,0 +1,132 @@ | |||
| //package com.jd.blockchain.peer.statetransfer; | |||
| // | |||
| //import com.jd.blockchain.binaryproto.BinaryEncodingUtils; | |||
| //import com.jd.blockchain.crypto.hash.HashDigest; | |||
| //import com.jd.blockchain.ledger.LedgerBlock; | |||
| //import com.jd.blockchain.ledger.LedgerTransaction; | |||
| //import com.jd.blockchain.ledger.core.LedgerManage; | |||
| //import com.jd.blockchain.ledger.core.LedgerRepository; | |||
| //import com.jd.blockchain.ledger.core.TransactionSet; | |||
| //import com.jd.blockchain.statetransfer.DataSequenceElement; | |||
| //import com.jd.blockchain.statetransfer.DataSequenceInfo; | |||
| //import com.jd.blockchain.statetransfer.callback.DataSequenceReader; | |||
| //import com.jd.blockchain.storage.service.DbConnection; | |||
| //import com.jd.blockchain.storage.service.DbConnectionFactory; | |||
| //import com.jd.blockchain.tools.initializer.LedgerBindingConfig; | |||
| //import com.jd.blockchain.utils.codec.Base58Utils; | |||
| //import com.jd.blockchain.utils.codec.HexUtils; | |||
| //import org.springframework.beans.factory.annotation.Autowired; | |||
| // | |||
| ///** | |||
| // *数据序列差异的提供者需要使用的回调接口实现类 | |||
| // * @author zhangshuang | |||
| // * @create 2019/4/11 | |||
| // * @since 1.0.0 | |||
| // */ | |||
| //public class DataSequenceReaderImpl implements DataSequenceReader { | |||
| // | |||
| // private LedgerManage ledgerManager; | |||
| // | |||
| // private DbConnectionFactory connFactory; | |||
| // | |||
| // private LedgerBindingConfig config; | |||
| // | |||
| // public DataSequenceReaderImpl(LedgerBindingConfig config, LedgerManage ledgerManager, DbConnectionFactory connFactory) { | |||
| // this.config = config; | |||
| // this.ledgerManager = ledgerManager; | |||
| // this.connFactory = connFactory; | |||
| // } | |||
| // | |||
| // | |||
| // /** | |||
| // * @param id 账本哈希的Base58编码 | |||
| // * @return DataSequenceInfo 数据序列信息 | |||
| // */ | |||
| // @Override | |||
| // public DataSequenceInfo getDSInfo(String id) { | |||
| // | |||
| // byte[] hashBytes = Base58Utils.decode(id); | |||
| // | |||
| // HashDigest ledgerHash = new HashDigest(hashBytes); | |||
| // | |||
| // LedgerBindingConfig.BindingConfig bindingConfig = config.getLedger(ledgerHash); | |||
| // DbConnection dbConnNew = connFactory.connect(bindingConfig.getDbConnection().getUri(), | |||
| // bindingConfig.getDbConnection().getPassword()); | |||
| // LedgerRepository ledgerRepository = ledgerManager.register(ledgerHash, dbConnNew.getStorageService()); | |||
| // | |||
| // return new DataSequenceInfo(id, ledgerRepository.getLatestBlockHeight()); | |||
| // } | |||
| // | |||
| // /** | |||
| // * | |||
| // * @param id 账本哈希的Base58编码 | |||
| // * @param from 数据序列复制的起始高度 | |||
| // * @param to 数据序列复制的结束高度 | |||
| // * @return DataSequenceElement【】数据序列差异数据元素的数组 | |||
| // */ | |||
| // @Override | |||
| // public DataSequenceElement[] getDSDiffContent(String id, long from, long to) { | |||
| // | |||
| // DataSequenceElement[] dataSequenceElements = new DataSequenceElement[(int)(to - from + 1)]; | |||
| // for (long i = from; i < to + 1; i++) { | |||
| // dataSequenceElements[(int)(i - from)] = getDSDiffContent(id, i); | |||
| // } | |||
| // | |||
| // return dataSequenceElements; | |||
| // } | |||
| // | |||
| // /** | |||
| // * 账本交易序列化 | |||
| // * @param transaction 账本交易 | |||
| // * @return byte[] 对账本交易进行序列化的结果 | |||
| // */ | |||
| // private byte[] serialize(LedgerTransaction transaction) { | |||
| // return BinaryEncodingUtils.encode(transaction, LedgerTransaction.class); | |||
| // } | |||
| // | |||
| // /** | |||
| // * 获得账本某一高度区块上的所有交易 | |||
| // * @param id 账本哈希的Base58编码 | |||
| // * @param height 账本的某个区块高度 | |||
| // * @return DataSequenceElement 数据序列差异数据元素 | |||
| // */ | |||
| // @Override | |||
| // public DataSequenceElement getDSDiffContent(String id, long height) { | |||
| // | |||
| // int lastHeightTxTotalNums = 0; | |||
| // | |||
| // byte[][] transacionDatas = null; | |||
| // | |||
| // byte[] hashBytes = Base58Utils.decode(id); | |||
| // | |||
| // HashDigest ledgerHash = new HashDigest(hashBytes); | |||
| // | |||
| // LedgerBindingConfig.BindingConfig bindingConfig = config.getLedger(ledgerHash); | |||
| // DbConnection dbConnNew = connFactory.connect(bindingConfig.getDbConnection().getUri(), | |||
| // bindingConfig.getDbConnection().getPassword()); | |||
| // LedgerRepository ledgerRepository = ledgerManager.register(ledgerHash, dbConnNew.getStorageService()); | |||
| // | |||
| // LedgerBlock ledgerBlock = ledgerRepository.getBlock(height); | |||
| // TransactionSet transactionSet = ledgerRepository.getTransactionSet(ledgerBlock); | |||
| // | |||
| // if (height > 0) { | |||
| // lastHeightTxTotalNums = (int) ledgerRepository.getTransactionSet(ledgerRepository.getBlock(height - 1)).getTotalCount(); | |||
| // } | |||
| // | |||
| // int currentHeightTxTotalNums = (int)ledgerRepository.getTransactionSet(ledgerRepository.getBlock(height)).getTotalCount(); | |||
| // | |||
| // // get all transactions from current height block | |||
| // int currentHeightTxNums = currentHeightTxTotalNums - lastHeightTxTotalNums; | |||
| // | |||
| // LedgerTransaction[] transactions = transactionSet.getTxs(lastHeightTxTotalNums , currentHeightTxNums); | |||
| // | |||
| // for (int i = 0; i < transactions.length; i++) { | |||
| // byte[] transactionData = serialize(transactions[i]); | |||
| // transacionDatas[i] = transactionData; | |||
| // } | |||
| // | |||
| // return new DataSequenceElement(id, height, transacionDatas); | |||
| // } | |||
| // | |||
| // | |||
| //} | |||
| @@ -0,0 +1,170 @@ | |||
| //package com.jd.blockchain.peer.statetransfer; | |||
| // | |||
| //import com.jd.blockchain.consensus.service.MessageHandle; | |||
| //import com.jd.blockchain.ledger.TransactionState; | |||
| //import com.jd.blockchain.statetransfer.DataSequenceElement; | |||
| //import com.jd.blockchain.statetransfer.DataSequenceInfo; | |||
| //import com.jd.blockchain.statetransfer.callback.DataSequenceWriter; | |||
| //import com.jd.blockchain.statetransfer.comparator.DataSequenceComparator; | |||
| // | |||
| //import java.util.ArrayList; | |||
| //import java.util.Collections; | |||
| // | |||
| ///** | |||
| // *数据序列差异的请求者需要使用的回调接口实现类 | |||
| // * @author zhangshuang | |||
| // * @create 2019/4/11 | |||
| // * @since 1.0.0 | |||
| // */ | |||
| //public class DataSequenceWriterImpl implements DataSequenceWriter { | |||
| // | |||
| // private long currHeight; | |||
| // private ArrayList<DataSequenceElement> deceidedElements = new ArrayList<DataSequenceElement>(); | |||
| // | |||
| // private MessageHandle batchMessageHandle; | |||
| // | |||
| // | |||
| // public DataSequenceWriterImpl(MessageHandle batchMessageHandle) { | |||
| // this.batchMessageHandle = batchMessageHandle; | |||
| // } | |||
| // | |||
| // /** | |||
| // * 检查数据序列差异元素中的高度是否合理; | |||
| // * @param currHeight 当前结点的账本高度 | |||
| // * @param dsUpdateElements 需要更新到本地结点的数据序列元素List | |||
| // * @return | |||
| // */ | |||
| // private int checkElementsHeight(long currHeight, ArrayList<DataSequenceElement> dsUpdateElements) { | |||
| // boolean lossMiddleElements = false; | |||
| // | |||
| // // lose first element | |||
| // if (currHeight + 1 < dsUpdateElements.get(0).getHeight()){ | |||
| // System.out.println("Diff response loss first element error!"); | |||
| // return DataSequenceErrorType.DATA_SEQUENCE_LOSS_FIRST_ELEMENT.CODE; | |||
| // } | |||
| // else { | |||
| // for (int i = 0; i < dsUpdateElements.size(); i++) { | |||
| // if (dsUpdateElements.get(i).getHeight() == currHeight + 1 + i) { | |||
| // deceidedElements.add(dsUpdateElements.get(i)); | |||
| // } | |||
| // // lose middle elements | |||
| // else { | |||
| // lossMiddleElements = true; | |||
| // break; | |||
| // } | |||
| // } | |||
| // | |||
| // if (lossMiddleElements) { | |||
| // System.out.println("Diff response loss middle elements error!"); | |||
| // return DataSequenceErrorType.DATA_SEQUENCE_LOSS_MIDDLE_ELEMENT.CODE; | |||
| // } | |||
| // | |||
| // System.out.println("Diff response elements height normal!"); | |||
| // return DataSequenceErrorType.DATA_SEQUENCE_ELEMENT_HEIGHT_NORMAL.CODE; | |||
| // } | |||
| // | |||
| // } | |||
| // | |||
| // /** | |||
| // * 对本地结点执行账本更新 | |||
| // * @param realmName 账本哈希的Base58编码 | |||
| // * @return void | |||
| // */ | |||
| // private void exeUpdate(String realmName) { | |||
| // | |||
| // for (int i = 0; i < deceidedElements.size(); i++) { | |||
| // byte[][] element = deceidedElements.get(i).getData(); | |||
| // | |||
| // String batchId = batchMessageHandle.beginBatch(realmName); | |||
| // try { | |||
| // int msgId = 0; | |||
| // for (byte[] txContent : element) { | |||
| // batchMessageHandle.processOrdered(msgId++, txContent, realmName, batchId); | |||
| // } | |||
| // // 结块 | |||
| // batchMessageHandle.completeBatch(realmName, batchId); | |||
| // batchMessageHandle.commitBatch(realmName, batchId); | |||
| // } catch (Exception e) { | |||
| // // todo 需要处理应答码 404 | |||
| // batchMessageHandle.rollbackBatch(realmName, batchId, TransactionState.DATA_SEQUENCE_UPDATE_ERROR.CODE); | |||
| // } | |||
| // } | |||
| // | |||
| // } | |||
| // | |||
| // /** | |||
| // * @param dsInfo 当前结点的数据序列信息 | |||
| // * @param diffContents 数据序列差异的数据元素数组 | |||
| // * @return int 更新结果码 | |||
| // */ | |||
| // @Override | |||
| // public int updateDSInfo(DataSequenceInfo dsInfo, DataSequenceElement[] diffContents) { | |||
| // int result = 0; | |||
| // | |||
| // try { | |||
| // ArrayList<DataSequenceElement> dsUpdateElements = new ArrayList<DataSequenceElement>(); | |||
| // //remove unexpected elements | |||
| // for (int i = 0 ; i < diffContents.length; i++) { | |||
| // if (diffContents[i].getId().equals(dsInfo.getId())) { | |||
| // dsUpdateElements.add(diffContents[i]); | |||
| // } | |||
| // } | |||
| // | |||
| // // sort elements by height | |||
| // Collections.sort(dsUpdateElements, new DataSequenceComparator()); | |||
| // | |||
| // currHeight = dsInfo.getHeight(); | |||
| // | |||
| // // check element's height | |||
| // result = checkElementsHeight(currHeight, dsUpdateElements); | |||
| // | |||
| // // cann't exe update | |||
| // if (result == DataSequenceErrorType.DATA_SEQUENCE_LOSS_FIRST_ELEMENT.CODE) { | |||
| // return result; | |||
| // } | |||
| // // exe elements update | |||
| // else { | |||
| // exeUpdate(dsInfo.getId()); | |||
| // return result; | |||
| // } | |||
| // } catch (Exception e) { | |||
| // System.out.println(e.getMessage()); | |||
| // e.printStackTrace(); | |||
| // } | |||
| // | |||
| // return result; | |||
| // } | |||
| // | |||
| // @Override | |||
| // public int updateDSInfo(DataSequenceInfo dsInfo, DataSequenceElement diffContents) { | |||
| // return 0; | |||
| // } | |||
| // | |||
| // | |||
| // /** | |||
| // * 数据序列更新错误码 | |||
| // * @param | |||
| // * @return | |||
| // */ | |||
| // public enum DataSequenceErrorType { | |||
| // DATA_SEQUENCE_LOSS_FIRST_ELEMENT((byte) 0x1), | |||
| // DATA_SEQUENCE_LOSS_MIDDLE_ELEMENT((byte) 0x2), | |||
| // DATA_SEQUENCE_ELEMENT_HEIGHT_NORMAL((byte) 0x3), | |||
| // ; | |||
| // public final int CODE; | |||
| // | |||
| // private DataSequenceErrorType(byte code) { | |||
| // this.CODE = code; | |||
| // } | |||
| // | |||
| // public static DataSequenceErrorType valueOf(byte code) { | |||
| // for (DataSequenceErrorType errorType : DataSequenceErrorType.values()) { | |||
| // if (errorType.CODE == code) { | |||
| // return errorType; | |||
| // } | |||
| // } | |||
| // throw new IllegalArgumentException("Unsupported code[" + code + "] of errorType!"); | |||
| // } | |||
| // } | |||
| // | |||
| //} | |||
| @@ -1,21 +1,30 @@ | |||
| package com.jd.blockchain.peer.web; | |||
| import com.jd.blockchain.contract.ContractException; | |||
| import com.jd.blockchain.ledger.*; | |||
| import com.jd.blockchain.ledger.core.*; | |||
| import com.jd.blockchain.utils.StringUtils; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.RequestMethod; | |||
| import org.springframework.web.bind.annotation.RequestParam; | |||
| import org.springframework.web.bind.annotation.RestController; | |||
| import org.springframework.web.bind.annotation.*; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.binaryproto.PrimitiveType; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.core.ContractAccountSet; | |||
| import com.jd.blockchain.ledger.core.DataAccount; | |||
| import com.jd.blockchain.ledger.core.DataAccountSet; | |||
| import com.jd.blockchain.ledger.core.LedgerAdministration; | |||
| import com.jd.blockchain.ledger.core.LedgerRepository; | |||
| import com.jd.blockchain.ledger.core.LedgerService; | |||
| import com.jd.blockchain.ledger.core.ParticipantCertData; | |||
| import com.jd.blockchain.ledger.core.TransactionSet; | |||
| import com.jd.blockchain.ledger.core.UserAccountSet; | |||
| import com.jd.blockchain.transaction.BlockchainQueryService; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.QueryUtil; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| @RestController | |||
| @RequestMapping(path = "/") | |||
| public class LedgerQueryController implements BlockchainQueryService { | |||
| @@ -342,6 +351,63 @@ public class LedgerQueryController implements BlockchainQueryService { | |||
| return entries; | |||
| } | |||
| @RequestMapping(method = {RequestMethod.GET, RequestMethod.POST}, path = "ledgers/{ledgerHash}/accounts/{address}/entries-version") | |||
| @Override | |||
| public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
| @PathVariable(name = "address") String address, | |||
| @RequestBody KVInfoVO kvInfoVO) { | |||
| //parse kvInfoVO; | |||
| List<String> keyList = new ArrayList<>(); | |||
| List<Long> versionList = new ArrayList<>(); | |||
| if(kvInfoVO != null){ | |||
| for(KVDataVO kvDataVO : kvInfoVO.getData()){ | |||
| for(Long version : kvDataVO.getVersion()){ | |||
| keyList.add(kvDataVO.getKey()); | |||
| versionList.add(version); | |||
| } | |||
| } | |||
| } | |||
| String[] keys = keyList.toArray(new String[keyList.size()]); | |||
| Long[] versions = versionList.toArray(new Long[versionList.size()]); | |||
| if (keys == null || keys.length == 0) { | |||
| return null; | |||
| } | |||
| if (versions == null || versions.length == 0) { | |||
| return null; | |||
| } | |||
| if(keys.length != versions.length){ | |||
| throw new ContractException("keys.length!=versions.length!"); | |||
| } | |||
| LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||
| DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | |||
| KVDataEntry[] entries = new KVDataEntry[keys.length]; | |||
| long ver = -1; | |||
| for (int i = 0; i < entries.length; i++) { | |||
| // ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); | |||
| ver = versions[i]; | |||
| if (ver < 0) { | |||
| entries[i] = new KVDataObject(keys[i], -1, PrimitiveType.NIL, null); | |||
| }else { | |||
| if(dataAccount.getDataEntriesTotalCount()==0 || | |||
| dataAccount.getBytes(Bytes.fromString(keys[i]), ver) == null){ | |||
| //is the address is not exist; the result is null; | |||
| entries[i] = new KVDataObject(keys[i], -1, PrimitiveType.NIL, null); | |||
| } else { | |||
| byte[] value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver); | |||
| BytesValue decodeData = BinaryProtocol.decode(value); | |||
| entries[i] = new KVDataObject(keys[i], ver, PrimitiveType.valueOf(decodeData.getType().CODE), decodeData.getValue().toBytes()); | |||
| } | |||
| } | |||
| } | |||
| return entries; | |||
| } | |||
| @RequestMapping(method = {RequestMethod.GET, RequestMethod.POST}, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") | |||
| @Override | |||
| public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
| @@ -5,10 +5,6 @@ import java.util.List; | |||
| import java.util.Map; | |||
| import java.util.concurrent.ConcurrentHashMap; | |||
| import javax.annotation.PostConstruct; | |||
| import javax.annotation.PreDestroy; | |||
| import com.jd.blockchain.ledger.*; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| @@ -35,6 +31,21 @@ import com.jd.blockchain.consensus.service.NodeServer; | |||
| import com.jd.blockchain.consensus.service.ServerSettings; | |||
| import com.jd.blockchain.consensus.service.StateMachineReplicate; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.ContractCodeDeployOperation; | |||
| import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
| import com.jd.blockchain.ledger.CryptoSetting; | |||
| import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
| import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
| import com.jd.blockchain.ledger.EndpointRequest; | |||
| import com.jd.blockchain.ledger.LedgerBlock; | |||
| import com.jd.blockchain.ledger.LedgerInitOperation; | |||
| import com.jd.blockchain.ledger.NodeRequest; | |||
| import com.jd.blockchain.ledger.Operation; | |||
| import com.jd.blockchain.ledger.TransactionContent; | |||
| import com.jd.blockchain.ledger.TransactionContentBody; | |||
| import com.jd.blockchain.ledger.TransactionRequest; | |||
| import com.jd.blockchain.ledger.TransactionResponse; | |||
| import com.jd.blockchain.ledger.UserRegisterOperation; | |||
| import com.jd.blockchain.ledger.core.LedgerAdminAccount; | |||
| import com.jd.blockchain.ledger.core.LedgerManage; | |||
| import com.jd.blockchain.ledger.core.LedgerRepository; | |||
| @@ -68,35 +79,17 @@ public class ManagementController implements LedgerBindingConfigAware, PeerManag | |||
| public static final int MIN_GATEWAY_ID = 10000; | |||
| // @Autowired | |||
| // private PeerSettings peerSetting; | |||
| // @Autowired | |||
| // private ConsensusTransactionService consensusService; | |||
| // private ConsensusPeer consensusReplica; | |||
| @Autowired | |||
| private LedgerManage ledgerManager; | |||
| @Autowired | |||
| private DbConnectionFactory connFactory; | |||
| // private Map<HashDigest, DbConnection> ledgerConns = new | |||
| // ConcurrentHashMap<>(); | |||
| private Map<HashDigest, MsgQueueMessageDispatcher> ledgerTxConverters = new ConcurrentHashMap<>(); | |||
| private Map<HashDigest, NodeServer> ledgerPeers = new ConcurrentHashMap<>(); | |||
| private Map<HashDigest, CryptoSetting> ledgerCryptoSettings = new ConcurrentHashMap<>(); | |||
| // private Map<ConsensusNode, ConsensusRealm> nodeRealms = new | |||
| // ConcurrentHashMap<>(); | |||
| // private Map<HashDigest, ConsensusRealm> ledgerRealms = new | |||
| // ConcurrentHashMap<>(); | |||
| // private Map<HashDigest, ConsensusRealm> ledgerRealmsNoConflict = new | |||
| // ConcurrentHashMap<>(); | |||
| private LedgerBindingConfig config; | |||
| @@ -106,9 +99,6 @@ public class ManagementController implements LedgerBindingConfigAware, PeerManag | |||
| @Autowired | |||
| private StateMachineReplicate consensusStateManager; | |||
| // private static int step = 0; | |||
| // private static int temp = 0; | |||
| static { | |||
| DataContractRegistry.register(LedgerInitOperation.class); | |||
| DataContractRegistry.register(LedgerBlock.class); | |||
| @@ -134,24 +124,6 @@ public class ManagementController implements LedgerBindingConfigAware, PeerManag | |||
| } | |||
| @PostConstruct | |||
| private void init() { | |||
| } | |||
| @PreDestroy | |||
| private void destroy() { | |||
| // DbConnection[] conns = ledgerConns.values().toArray(new DbConnection[ledgerConns.size()]); | |||
| // ledgerConns.clear(); | |||
| // for (DbConnection conn : conns) { | |||
| // try { | |||
| // conn.close(); | |||
| // } catch (Exception e) { | |||
| // // Ignore; | |||
| // } | |||
| // } | |||
| } | |||
| /** | |||
| * 接入认证; | |||
| * | |||
| @@ -234,42 +206,8 @@ public class ManagementController implements LedgerBindingConfigAware, PeerManag | |||
| HashDigest[] ledgerHashs = config.getLedgerHashs(); | |||
| for (HashDigest ledgerHash : ledgerHashs) { | |||
| setConfig(config,ledgerHash); | |||
| // LedgerBindingConfig.BindingConfig bindingConfig = config.getLedger(ledgerHash); | |||
| // DbConnection dbConnNew = connFactory.connect(bindingConfig.getDbConnection().getUri(), | |||
| // bindingConfig.getDbConnection().getPassword()); | |||
| // LedgerRepository ledgerRepository = ledgerManager.register(ledgerHash, dbConnNew.getStorageService()); | |||
| // | |||
| // // load provider; | |||
| // LedgerAdminAccount ledgerAdminAccount = ledgerRepository.getAdminAccount(); | |||
| // String consensusProvider = ledgerAdminAccount.getSetting().getConsensusProvider(); | |||
| // ConsensusProvider provider = ConsensusProviders.getProvider(consensusProvider); | |||
| // // find current node; | |||
| // Bytes csSettingBytes = ledgerAdminAccount.getSetting().getConsensusSetting(); | |||
| // ConsensusSettings csSettings = provider.getSettingsFactory().getConsensusSettingsEncoder() | |||
| // .decode(csSettingBytes.toBytes()); | |||
| // NodeSettings currentNode = null; | |||
| // for (NodeSettings nodeSettings : csSettings.getNodes()) { | |||
| // if (nodeSettings.getAddress().equals(bindingConfig.getParticipant().getAddress())) { | |||
| // currentNode = nodeSettings; | |||
| // } | |||
| // } | |||
| // if (currentNode == null) { | |||
| // throw new IllegalArgumentException( | |||
| // "Current node is not found from the consensus settings of ledger[" + ledgerHash.toBase58() | |||
| // + "]!"); | |||
| // } | |||
| // ServerSettings serverSettings = provider.getServerFactory().buildServerSettings(ledgerHash.toBase58(), csSettings, currentNode.getAddress()); | |||
| // | |||
| // NodeServer server = provider.getServerFactory().setupServer(serverSettings, consensusMessageHandler, | |||
| // consensusStateManager); | |||
| // ledgerPeers.put(ledgerHash, server); | |||
| // ledgerCryptoSettings.put(ledgerHash, ledgerAdminAccount.getSetting().getCryptoSetting()); | |||
| } | |||
| // remove duplicate consensus realm,and establish consensus peer and consensus | |||
| // realm corresponding relationship | |||
| // initBindingConfig(config); | |||
| this.config = config; | |||
| } catch (Exception e) { | |||
| @@ -314,46 +252,6 @@ public class ManagementController implements LedgerBindingConfigAware, PeerManag | |||
| return server; | |||
| } | |||
| // private void initBindingConfig(LedgerBindingConfig config) { | |||
| // boolean intersection = false; | |||
| // // to remove intersection consensus realm | |||
| // for (HashDigest hashDigest : ledgerRealms.keySet()) { | |||
| // ConsensusRealm consensusRealm1i = ledgerRealms.get(hashDigest); | |||
| // for (ConsensusRealm consensusRealm1j : ledgerRealms.values()) { | |||
| // // avoid compare with myself | |||
| // if (consensusRealm1i.equals(consensusRealm1j)) { | |||
| // continue; | |||
| // } | |||
| // if (consensusRealm1i.hasIntersection(consensusRealm1j)) { | |||
| // intersection = true; | |||
| // break; | |||
| // } | |||
| // } | |||
| // // prompt consensus realm conflict info | |||
| // if (intersection == true) { | |||
| // ConsoleUtils.info("\r\nconsensus realm intersection with other consensus | |||
| // realm\r\n"); | |||
| // continue; | |||
| // } | |||
| // if (intersection == false) { | |||
| // // add consensus realm without conflict to ledgerRealmsNoConflict | |||
| // ledgerRealmsNoConflict.put(hashDigest, consensusRealm1i); | |||
| // | |||
| // // String consensusSystemFile = | |||
| // config.getLedger(hashDigest).getCsConfigFile(); | |||
| // int currentId = config.getLedger(hashDigest).getParticipant().getId(); | |||
| // // init consensusSystemConfig; | |||
| // ConsensusProperties csProps = | |||
| // ConsensusProperties.resolve(consensusRealm1i.getSetting()); | |||
| // ConsensusPeer consensusPeer = new ConsensusPeer(consensusRealm1i, currentId, | |||
| // consensusService, | |||
| // csProps.getProperties()); | |||
| // ledgerPeers.put(hashDigest, consensusPeer); | |||
| // } | |||
| // } // END OF FOR:get ledgerRealmsNoConflict and ledgerPeers | |||
| // | |||
| // } | |||
| @Override | |||
| public ConsensusRealm[] getRealms() { | |||
| throw new IllegalStateException("Not implemented!"); | |||
| @@ -364,45 +262,6 @@ public class ManagementController implements LedgerBindingConfigAware, PeerManag | |||
| for (NodeServer peer : ledgerPeers.values()) { | |||
| runRealm(peer); | |||
| } | |||
| // try { | |||
| // | |||
| // // for (ConsensusPeer peer : ledgerPeers.values()) { | |||
| // for (Map.Entry<HashDigest, ConsensusPeer> entry : ledgerPeers.entrySet()) { | |||
| // HashDigest ledgerHash = entry.getKey(); | |||
| // ConsensusPeer peer = entry.getValue(); | |||
| // // TODO: 多线程启动; | |||
| // ConsensusNode[] nodes = peer.getConsensusRealm().getNodes(); | |||
| // StringBuilder consensusInfo = new StringBuilder(); | |||
| // for (ConsensusNode node : nodes) { | |||
| // consensusInfo.append( | |||
| // String.format("[%s]-%s; ", node.getAddress(), | |||
| // node.getConsensusAddress().toString())); | |||
| // } | |||
| // LOGGER.debug(String.format("-------- start consensus peer[Id=%s] --Nodes=%s | |||
| // -------------", | |||
| // peer.getCurrentId(), consensusInfo.toString())); | |||
| // peer.start(); | |||
| // // 设置消息队列 | |||
| // MsgQueueMessageDispatcher messageDispatcher = ledgerTxConverters.get(ledgerHash); | |||
| // | |||
| // if (messageDispatcher == null) { | |||
| // LedgerBindingConfig.BindingConfig bindingConfig = | |||
| // this.config.getLedger(ledgerHash); | |||
| // MQConnectionConfig mqConnection = bindingConfig.getMqConnection(); | |||
| // if (mqConnection != null && mqConnection.getServer() != null) { | |||
| // MessageQueueConfig mqConfig = new | |||
| // MessageQueueConfig(mqConnection.getServer(), | |||
| // mqConnection.getTopic()); | |||
| // messageDispatcher = MessageDispatcherFactory.newInstance(mqConfig, peer); | |||
| // Executors.newSingleThreadExecutor().execute(messageDispatcher); // 启动监听 | |||
| // } | |||
| // } | |||
| // } | |||
| // } catch (Exception e) { | |||
| // LOGGER.error("Error occurred on starting all consensus realms! --" + | |||
| // e.getMessage(), e); | |||
| // throw new IllegalStateException(e.getMessage(), e); | |||
| // } | |||
| } | |||
| @Override | |||
| @@ -15,11 +15,11 @@ import com.jd.blockchain.peer.ConsensusManage; | |||
| import com.jd.blockchain.peer.LedgerBindingConfigAware; | |||
| import com.jd.blockchain.peer.PeerServerBooter; | |||
| import com.jd.blockchain.tools.initializer.LedgerBindingConfig; | |||
| import com.jd.blockchain.utils.ArgumentSet; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.BeansException; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.boot.CommandLineRunner; | |||
| import org.springframework.context.ApplicationContext; | |||
| import org.springframework.context.ApplicationContextAware; | |||
| import org.springframework.core.io.ClassPathResource; | |||
| @@ -38,9 +38,11 @@ import java.util.*; | |||
| * @since 1.0.0 | |||
| */ | |||
| @Component | |||
| //@EnableScheduling | |||
| @EnableScheduling | |||
| public class PeerTimeTasks implements ApplicationContextAware { | |||
| private static Logger LOGGER = LoggerFactory.getLogger(PeerTimeTasks.class); | |||
| private ApplicationContext applicationContext; | |||
| @Autowired | |||
| @@ -51,7 +53,9 @@ public class PeerTimeTasks implements ApplicationContextAware { | |||
| //每1分钟执行一次 | |||
| @Scheduled(cron = "0 */5 * * * * ") | |||
| public void updateLedger(){ | |||
| System.out.println ("Update Ledger Tasks Start " + new Date()); | |||
| LOGGER.debug("Time Task Update Ledger Tasks Start {}", new Date()); | |||
| try { | |||
| LedgerBindingConfig ledgerBindingConfig = loadLedgerBindingConfig(); | |||
| @@ -78,7 +82,8 @@ public class PeerTimeTasks implements ApplicationContextAware { | |||
| Map<String, LedgerBindingConfigAware> bindingConfigAwares = applicationContext.getBeansOfType(LedgerBindingConfigAware.class); | |||
| List<NodeServer> nodeServers = new ArrayList<>(); | |||
| for (HashDigest ledgerHash : newAddHashs) { | |||
| System.out.printf("newLedger[%s] \r\n", ledgerHash.toBase58()); | |||
| LOGGER.info("New Ledger [{}] Need To Be Init !!!", ledgerHash.toBase58()); | |||
| for (LedgerBindingConfigAware aware : bindingConfigAwares.values()) { | |||
| nodeServers.add(aware.setConfig(ledgerBindingConfig, ledgerHash)); | |||
| } | |||
| @@ -89,10 +94,10 @@ public class PeerTimeTasks implements ApplicationContextAware { | |||
| consensusManage.runRealm(nodeServer); | |||
| } | |||
| } else { | |||
| System.out.println("All Ledgers is newest!!!"); | |||
| LOGGER.debug("All Ledgers is newest!!!"); | |||
| } | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| LOGGER.error(e.getMessage()); | |||
| } | |||
| } | |||
| @@ -104,7 +109,8 @@ public class PeerTimeTasks implements ApplicationContextAware { | |||
| private LedgerBindingConfig loadLedgerBindingConfig() throws Exception { | |||
| LedgerBindingConfig ledgerBindingConfig; | |||
| ledgerBindConfigFile = PeerServerBooter.ledgerBindConfigFile; | |||
| System.out.printf("load ledgerBindConfigFile = %s \r\n", ledgerBindConfigFile); | |||
| LOGGER.debug("Load LedgerBindConfigFile path = {}", | |||
| ledgerBindConfigFile == null ? "Default" : ledgerBindConfigFile); | |||
| if (ledgerBindConfigFile == null) { | |||
| ClassPathResource configResource = new ClassPathResource("ledger-binding.conf"); | |||
| InputStream in = configResource.getInputStream(); | |||
| @@ -34,7 +34,7 @@ public class LedgerInitSettings { | |||
| /** | |||
| * 共识协议 | |||
| */ | |||
| private int consensusProtocol; | |||
| private String consensusProtocol; | |||
| /** | |||
| * 共识配置 | |||
| @@ -70,11 +70,11 @@ public class LedgerInitSettings { | |||
| this.cryptoSetting = cryptoSetting; | |||
| } | |||
| public int getConsensusProtocol() { | |||
| public String getConsensusProtocol() { | |||
| return consensusProtocol; | |||
| } | |||
| public void setConsensusProtocol(int consensusProtocol) { | |||
| public void setConsensusProtocol(String consensusProtocol) { | |||
| this.consensusProtocol = consensusProtocol; | |||
| } | |||
| @@ -93,21 +93,4 @@ public class LedgerInitSettings { | |||
| public void setParticipantNodes(ParticipantNode[] participantNodes) { | |||
| this.participantNodes = participantNodes; | |||
| } | |||
| public enum CONSENSUS_PROTOCOL { | |||
| UNKNOWN(0), | |||
| BFTSMART(1), | |||
| MSGQUEUE(2), | |||
| ; | |||
| private int code; | |||
| CONSENSUS_PROTOCOL(int code) { | |||
| this.code = code; | |||
| } | |||
| public int code() { | |||
| return code; | |||
| } | |||
| } | |||
| } | |||
| @@ -147,6 +147,11 @@ public abstract class BlockchainServiceProxy implements BlockchainService { | |||
| return getQueryService(ledgerHash).getDataEntries(ledgerHash, address, keys); | |||
| } | |||
| @Override | |||
| public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { | |||
| return getQueryService(ledgerHash).getDataEntries(ledgerHash, address, kvInfoVO); | |||
| } | |||
| @Override | |||
| public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { | |||
| return getQueryService(ledgerHash).getDataEntries(ledgerHash, address, fromIndex, count); | |||
| @@ -496,7 +496,11 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService | |||
| @PathParam(name="address") String address, | |||
| @RequestParam(name="keys", array = true) String... keys); | |||
| @HttpAction(method = HttpMethod.POST, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") | |||
| @HttpAction(method=HttpMethod.POST, path="ledgers/{ledgerHash}/accounts/{address}/entries-version") | |||
| @Override | |||
| KVDataEntry[] getDataEntries(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, | |||
| @PathParam(name="address") String address, | |||
| @RequestBody KVInfoVO kvInfoVO); | |||
| /** | |||
| * 返回数据账户中指定序号的最新值; | |||
| @@ -513,6 +517,7 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService | |||
| * 如果参数值为 -1,则返回全部的记录;<br> | |||
| * @return | |||
| */ | |||
| @HttpAction(method = HttpMethod.POST, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") | |||
| @Override | |||
| KVDataEntry[] getDataEntries(@PathParam(name = "ledgerHash") HashDigest ledgerHash, | |||
| @PathParam(name = "address") String address, | |||
| @@ -0,0 +1,34 @@ | |||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | |||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |||
| <modelVersion>4.0.0</modelVersion> | |||
| <parent> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>jdchain-root</artifactId> | |||
| <version>0.9.0-SNAPSHOT</version> | |||
| </parent> | |||
| <artifactId>state-transfer</artifactId> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>stp-communication</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>utils-common</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>utils-serialize</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| </dependencies> | |||
| </project> | |||
| @@ -0,0 +1,75 @@ | |||
| package com.jd.blockchain.statetransfer; | |||
| import java.net.InetSocketAddress; | |||
| import java.util.LinkedList; | |||
| /** | |||
| * 测试过程建立的一个数据序列 | |||
| * @author zhangshuang | |||
| * @create 2019/4/18 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class DataSequence { | |||
| private InetSocketAddress address; | |||
| private String id; | |||
| // 每个数据序列维护了一系列的数据序列元素 | |||
| private LinkedList<DataSequenceElement> dataSequenceElements = new LinkedList<>(); | |||
| public DataSequence(InetSocketAddress address, String id) { | |||
| this.address = address; | |||
| this.id = id; | |||
| } | |||
| public String getId() { | |||
| return id; | |||
| } | |||
| public InetSocketAddress getAddress() { | |||
| return address; | |||
| } | |||
| public void addElements(DataSequenceElement[] elements) { | |||
| for (DataSequenceElement element : elements) { | |||
| addElement(element); | |||
| } | |||
| } | |||
| public void addElement(DataSequenceElement element) { | |||
| try { | |||
| if (dataSequenceElements.size() == 0) { | |||
| if (element.getHeight() != 0) { | |||
| throw new IllegalArgumentException("Data sequence add element height error!"); | |||
| } | |||
| dataSequenceElements.addLast(element); | |||
| } | |||
| else { | |||
| if (dataSequenceElements.getLast().getHeight() != element.getHeight() - 1) { | |||
| throw new IllegalArgumentException("Data sequence add element height error!"); | |||
| } | |||
| dataSequenceElements.addLast(element); | |||
| } | |||
| } catch (Exception e) { | |||
| System.out.println(e.getMessage()); | |||
| e.printStackTrace(); | |||
| } | |||
| } | |||
| public LinkedList<DataSequenceElement> getDataSequenceElements() { | |||
| return dataSequenceElements; | |||
| } | |||
| public DataSequenceInfo getDSInfo() { | |||
| if (dataSequenceElements.size() == 0) { | |||
| return new DataSequenceInfo(id, -1); | |||
| } | |||
| else { | |||
| return new DataSequenceInfo(id, dataSequenceElements.getLast().getHeight()); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,53 @@ | |||
| package com.jd.blockchain.statetransfer; | |||
| import java.io.Serializable; | |||
| /** | |||
| * 数据序列需要复制内容的元素或单位 | |||
| * @author zhangshuang | |||
| * @create 2019/4/11 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class DataSequenceElement implements Serializable { | |||
| private static final long serialVersionUID = -719578198150380571L; | |||
| //数据序列的唯一标识符; | |||
| private String id; | |||
| //数据序列的某个高度; | |||
| private long height; | |||
| //对应某个高度的数据序列内容 | |||
| private byte[][] data; | |||
| public DataSequenceElement(String id, long height, byte[][] data) { | |||
| this.id = id; | |||
| this.height = height; | |||
| this.data = data; | |||
| } | |||
| public long getHeight() { | |||
| return height; | |||
| } | |||
| public void setHeight(long height) { | |||
| this.height = height; | |||
| } | |||
| public String getId() { | |||
| return id; | |||
| } | |||
| public void setId(String id) { | |||
| id = id; | |||
| } | |||
| public byte[][] getData() { | |||
| return data; | |||
| } | |||
| public void setData(byte[][] data) { | |||
| this.data = data; | |||
| } | |||
| } | |||
| @@ -0,0 +1,37 @@ | |||
| package com.jd.blockchain.statetransfer; | |||
| /** | |||
| * 共识结点上的某个数据序列的当前状态信息,每个共识结点可以对应任意个数据序列; | |||
| * @author zhangshuang | |||
| * @create 2019/4/11 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class DataSequenceInfo { | |||
| //数据序列的唯一标识 | |||
| private String id; | |||
| //数据序列的当前高度 | |||
| private long height; | |||
| public DataSequenceInfo(String id, long height) { | |||
| this.id = id; | |||
| this.height = height; | |||
| } | |||
| public String getId() { | |||
| return id; | |||
| } | |||
| public void setId(String id) { | |||
| this.id = id; | |||
| } | |||
| public long getHeight() { | |||
| return height; | |||
| } | |||
| public void setHeight(long height) { | |||
| this.height = height; | |||
| } | |||
| } | |||
| @@ -0,0 +1,39 @@ | |||
| package com.jd.blockchain.statetransfer.callback; | |||
| import com.jd.blockchain.statetransfer.DataSequenceElement; | |||
| import com.jd.blockchain.statetransfer.DataSequenceInfo; | |||
| /** | |||
| * 数据序列差异提供者需要使用的回调接口 | |||
| * @author zhangshuang | |||
| * @create 2019/4/11 | |||
| * @since 1.0.0 | |||
| */ | |||
| public interface DataSequenceReader { | |||
| /** | |||
| * 差异提供者根据数据序列标识符获取数据序列当前状态; | |||
| * @param id 数据序列标识符 | |||
| * @return 数据序列当前状态信息 | |||
| */ | |||
| DataSequenceInfo getDSInfo(String id); | |||
| /** | |||
| * 差异提供者根据数据序列标识符以及起始,结束高度提供数据序列该范围的差异内容; | |||
| * @param id 数据序列标识符 | |||
| * @param from 差异的起始高度 | |||
| * @param to 差异的结束高度 | |||
| * @return 差异元素组成的数组 | |||
| */ | |||
| DataSequenceElement[] getDSDiffContent(String id, long from, long to); | |||
| /** | |||
| * 差异提供者根据数据序列标识符以及高度提供数据序列的差异内容; | |||
| * @param id 数据序列标识符 | |||
| * @param height 要获得哪个高度的差异元素 | |||
| * @return 差异元素 | |||
| */ | |||
| DataSequenceElement getDSDiffContent(String id, long height); | |||
| } | |||
| @@ -0,0 +1,59 @@ | |||
| package com.jd.blockchain.statetransfer.callback; | |||
| import com.jd.blockchain.statetransfer.DataSequence; | |||
| import com.jd.blockchain.statetransfer.DataSequenceElement; | |||
| import com.jd.blockchain.statetransfer.DataSequenceInfo; | |||
| import java.util.LinkedList; | |||
| /** | |||
| * 数据序列差异的提供者需要使用的回调接口实现类 | |||
| * @author zhangshuang | |||
| * @create 2019/4/22 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class DataSequenceReaderImpl implements DataSequenceReader { | |||
| DataSequence currDataSequence; | |||
| public DataSequenceReaderImpl(DataSequence currDataSequence) { | |||
| this.currDataSequence = currDataSequence; | |||
| } | |||
| @Override | |||
| public DataSequenceInfo getDSInfo(String id) { | |||
| return currDataSequence.getDSInfo(); | |||
| } | |||
| @Override | |||
| public DataSequenceElement[] getDSDiffContent(String id, long from, long to) { | |||
| DataSequenceElement[] elements = new DataSequenceElement[(int)(to - from + 1)]; | |||
| int i = 0; | |||
| LinkedList<DataSequenceElement> dataSequenceElements = currDataSequence.getDataSequenceElements(); | |||
| for (DataSequenceElement element : dataSequenceElements) { | |||
| if (element.getHeight() < from || element.getHeight() > to) { | |||
| continue; | |||
| } | |||
| else { | |||
| elements[i++] = element; | |||
| } | |||
| } | |||
| return elements; | |||
| } | |||
| @Override | |||
| public DataSequenceElement getDSDiffContent(String id, long height) { | |||
| for(DataSequenceElement dataSequenceElement : currDataSequence.getDataSequenceElements()) { | |||
| if (dataSequenceElement.getHeight() == height) { | |||
| return dataSequenceElement; | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| } | |||
| @@ -0,0 +1,30 @@ | |||
| package com.jd.blockchain.statetransfer.callback; | |||
| import com.jd.blockchain.statetransfer.DataSequenceElement; | |||
| import com.jd.blockchain.statetransfer.DataSequenceInfo; | |||
| /** | |||
| * 数据序列差异请求者获得差异内容后需要回调该接口 | |||
| * @author zhangshuang | |||
| * @create 2019/4/11 | |||
| * @since 1.0.0 | |||
| */ | |||
| public interface DataSequenceWriter { | |||
| /** | |||
| * 差异请求者更新本地数据序列的状态,一次可以更新多个差异元素 | |||
| * @param dsInfo 数据序列当前状态信息 | |||
| * @param diffContents 需要更新的差异元素数组 | |||
| * @return 更新结果编码 | |||
| */ | |||
| int updateDSInfo(DataSequenceInfo dsInfo, DataSequenceElement[] diffContents); | |||
| /** | |||
| * 差异请求者更新本地数据序列的状态,一次只更新一个差异元素 | |||
| * @param dsInfo 数据序列当前状态信息 | |||
| * @param diffContent 需要更新的差异元素 | |||
| * @return 更新结果编码 | |||
| */ | |||
| // int updateDSInfo(DataSequenceInfo dsInfo, DataSequenceElement diffContent); | |||
| } | |||
| @@ -0,0 +1,142 @@ | |||
| package com.jd.blockchain.statetransfer.callback; | |||
| import com.jd.blockchain.statetransfer.DataSequence; | |||
| import com.jd.blockchain.statetransfer.DataSequenceElement; | |||
| import com.jd.blockchain.statetransfer.DataSequenceInfo; | |||
| import java.util.ArrayList; | |||
| /** | |||
| * 数据序列差异的请求者需要使用的回调接口实现类 | |||
| * @author zhangshuang | |||
| * @create 2019/4/22 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class DataSequenceWriterImpl implements DataSequenceWriter { | |||
| private long currHeight; | |||
| private DataSequence currDataSequence; | |||
| private ArrayList<DataSequenceElement> deceidedElements = new ArrayList<DataSequenceElement>(); | |||
| public DataSequenceWriterImpl(DataSequence currDataSequence) { | |||
| this.currDataSequence = currDataSequence; | |||
| } | |||
| /** | |||
| * 检查数据序列差异元素中的高度是否合理; | |||
| * @param currHeight 当前结点的账本高度 | |||
| * @param dsUpdateElements 需要更新到本地结点的数据序列元素List | |||
| * @return | |||
| */ | |||
| private int checkElementsHeight(long currHeight, ArrayList<DataSequenceElement> dsUpdateElements) { | |||
| boolean lossMiddleElements = false; | |||
| // lose first element | |||
| if (currHeight + 1 < dsUpdateElements.get(0).getHeight()){ | |||
| System.out.println("Diff response loss first element error!"); | |||
| return DataSequenceErrorType.DATA_SEQUENCE_LOSS_FIRST_ELEMENT.CODE; | |||
| } | |||
| else { | |||
| for (int i = 0; i < dsUpdateElements.size(); i++) { | |||
| if (dsUpdateElements.get(i).getHeight() == currHeight + 1 + i) { | |||
| deceidedElements.add(dsUpdateElements.get(i)); | |||
| } | |||
| // lose middle elements | |||
| else { | |||
| lossMiddleElements = true; | |||
| break; | |||
| } | |||
| } | |||
| if (lossMiddleElements) { | |||
| System.out.println("Diff response loss middle elements error!"); | |||
| return DataSequenceErrorType.DATA_SEQUENCE_LOSS_MIDDLE_ELEMENT.CODE; | |||
| } | |||
| System.out.println("Diff response elements height normal!"); | |||
| return DataSequenceErrorType.DATA_SEQUENCE_ELEMENT_HEIGHT_NORMAL.CODE; | |||
| } | |||
| } | |||
| @Override | |||
| public int updateDSInfo(DataSequenceInfo dsInfo, DataSequenceElement[] diffContents) { | |||
| int result = 0; | |||
| try { | |||
| ArrayList<DataSequenceElement> dsUpdateElements = new ArrayList<DataSequenceElement>(); | |||
| if (diffContents == null) { | |||
| throw new IllegalArgumentException("Update diffContents is null!"); | |||
| } | |||
| //remove unexpected elements | |||
| for (int i = 0 ; i < diffContents.length; i++) { | |||
| if (diffContents[i].getId().equals(dsInfo.getId())) { | |||
| dsUpdateElements.add(diffContents[i]); | |||
| } | |||
| } | |||
| currHeight = dsInfo.getHeight(); | |||
| // check element's height | |||
| result = checkElementsHeight(currHeight, dsUpdateElements); | |||
| // cann't exe update | |||
| if (result == DataSequenceErrorType.DATA_SEQUENCE_LOSS_FIRST_ELEMENT.CODE) { | |||
| return result; | |||
| } | |||
| // exe elements update | |||
| else { | |||
| System.out.println("Old data sequence state: "); | |||
| System.out.println(" Current height = " + currDataSequence.getDataSequenceElements().getLast().getHeight()); | |||
| currDataSequence.addElements(deceidedElements.toArray(new DataSequenceElement[deceidedElements.size()])); | |||
| System.out.println("Update diffContents is completed!"); | |||
| System.out.println("New data sequence state: "); | |||
| System.out.println(" Current height = " + currDataSequence.getDataSequenceElements().getLast().getHeight()); | |||
| return result; | |||
| } | |||
| } catch (Exception e) { | |||
| System.out.println(e.getMessage()); | |||
| e.printStackTrace(); | |||
| } | |||
| return DataSequenceErrorType.DATA_SEQUENCE_ELEMENT_HEIGHT_NORMAL.CODE; | |||
| } | |||
| // @Override | |||
| // public int updateDSInfo(DataSequenceInfo dsInfo, DataSequenceElement diffContent) { | |||
| // currDataSequence.addElement(diffContent); | |||
| // return DataSequenceErrorType.DATA_SEQUENCE_ELEMENT_HEIGHT_NORMAL.CODE; | |||
| // } | |||
| public enum DataSequenceErrorType { | |||
| DATA_SEQUENCE_LOSS_FIRST_ELEMENT((byte) 0x1), | |||
| DATA_SEQUENCE_LOSS_MIDDLE_ELEMENT((byte) 0x2), | |||
| DATA_SEQUENCE_ELEMENT_HEIGHT_NORMAL((byte) 0x3), | |||
| ; | |||
| public final int CODE; | |||
| private DataSequenceErrorType(byte code) { | |||
| this.CODE = code; | |||
| } | |||
| public static DataSequenceErrorType valueOf(byte code) { | |||
| for (DataSequenceErrorType errorType : DataSequenceErrorType.values()) { | |||
| if (errorType.CODE == code) { | |||
| return errorType; | |||
| } | |||
| } | |||
| throw new IllegalArgumentException("Unsupported code[" + code + "] of errorType!"); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,32 @@ | |||
| package com.jd.blockchain.statetransfer.comparator; | |||
| import com.jd.blockchain.statetransfer.DataSequenceElement; | |||
| import java.util.Comparator; | |||
| /** | |||
| * 数据序列差异元素的高度比较器 | |||
| * @author zhangshuang | |||
| * @create 2019/4/18 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class DataSequenceComparator implements Comparator<DataSequenceElement> { | |||
| // sort by data sequence height | |||
| /** | |||
| * 对差异元素根据高度大小排序 | |||
| * @param o1 差异元素1 | |||
| * @param o2 差异元素2 | |||
| * @return >0 or <0 | |||
| */ | |||
| @Override | |||
| public int compare(DataSequenceElement o1, DataSequenceElement o2) { | |||
| long height1; | |||
| long height2; | |||
| height1 = o1.getHeight(); | |||
| height2 = o2.getHeight(); | |||
| return (int) (height1 - height2); | |||
| } | |||
| } | |||
| @@ -0,0 +1,21 @@ | |||
| package com.jd.blockchain.statetransfer.exception; | |||
| /** | |||
| * 数据序列异常处理 | |||
| * @author zhangshuang | |||
| * @create 2019/4/18 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class DataSequenceException extends RuntimeException { | |||
| private static final long serialVersionUID = -4090881296855827889L; | |||
| public DataSequenceException(String message) { | |||
| super(message); | |||
| } | |||
| public DataSequenceException(String message, Throwable cause) { | |||
| super(message, cause); | |||
| } | |||
| } | |||
| @@ -0,0 +1,80 @@ | |||
| package com.jd.blockchain.statetransfer.message; | |||
| import com.jd.blockchain.statetransfer.callback.DataSequenceReader; | |||
| import com.jd.blockchain.statetransfer.callback.DataSequenceWriter; | |||
| import com.jd.blockchain.statetransfer.process.DSTransferProcess; | |||
| import com.jd.blockchain.statetransfer.result.DSDiffRequestResult; | |||
| import com.jd.blockchain.stp.communication.MessageExecutor; | |||
| import com.jd.blockchain.stp.communication.RemoteSession; | |||
| /** | |||
| * 数据序列差异提供者使用,解析收到的差异请求消息并产生响应 | |||
| * @author zhangshuang | |||
| * @create 2019/4/11 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class DSDefaultMessageExecutor implements MessageExecutor { | |||
| DataSequenceReader dsReader; | |||
| DataSequenceWriter dsWriter; | |||
| public DSDefaultMessageExecutor(DataSequenceReader dsReader, DataSequenceWriter dsWriter) { | |||
| this.dsReader = dsReader; | |||
| this.dsWriter = dsWriter; | |||
| } | |||
| /** | |||
| * 对状态机复制的差异请求进行响应 | |||
| * @param key 请求消息的Key | |||
| * @param data 需要解码的字节数组 | |||
| * @param session 指定响应需要使用的目标结点会话 | |||
| * @return 配置为自动响应时,返回值为响应的字节数组,配置为手动响应时,不需要关注返回值 | |||
| */ | |||
| @Override | |||
| public byte[] receive(String key, byte[] data, RemoteSession session) { | |||
| try { | |||
| Object object = DSMsgResolverFactory.getDecoder(dsWriter, dsReader).decode(data); | |||
| // 解析CMD_DSINFO_REQUEST 请求的情况 | |||
| if (object instanceof String) { | |||
| String id = (String)object; | |||
| byte[] respLoadMsg = DSMsgResolverFactory.getEncoder(dsWriter, dsReader).encode(DSTransferProcess.DataSequenceMsgType.CMD_DSINFO_RESPONSE, id, 0, 0); | |||
| session.reply(key, new DataSequenceLoadMessage(respLoadMsg)); | |||
| } | |||
| // 解析CMD_GETDSDIFF_REQUEST 请求的情况 | |||
| else if (object instanceof DSDiffRequestResult) { | |||
| DSDiffRequestResult requestResult = (DSDiffRequestResult)object; | |||
| String id = requestResult.getId(); | |||
| long fromHeight = requestResult.getFromHeight(); | |||
| long toHeight = requestResult.getToHeight(); | |||
| //每个高度的数据序列差异元素进行一次响应的情况 | |||
| for (long i = fromHeight; i < toHeight + 1; i++) { | |||
| byte[] respLoadMsg = DSMsgResolverFactory.getEncoder(dsWriter, dsReader).encode(DSTransferProcess.DataSequenceMsgType.CMD_GETDSDIFF_RESPONSE, id, i, i); | |||
| session.reply(key, new DataSequenceLoadMessage(respLoadMsg)); | |||
| } | |||
| //所有差异进行一次响应的情况 | |||
| } | |||
| else { | |||
| throw new IllegalArgumentException("Receive data exception, unknown message type!"); | |||
| } | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| } | |||
| return null; | |||
| } | |||
| /** | |||
| * 响应类型设置 | |||
| * 分手动响应,自动响应两种类型 | |||
| */ | |||
| @Override | |||
| public REPLY replyType() { | |||
| return REPLY.MANUAL; | |||
| } | |||
| } | |||
| @@ -0,0 +1,34 @@ | |||
| package com.jd.blockchain.statetransfer.message; | |||
| import com.jd.blockchain.statetransfer.callback.DataSequenceReader; | |||
| import com.jd.blockchain.statetransfer.callback.DataSequenceWriter; | |||
| /** | |||
| * 数据序列消息解析器工厂 | |||
| * @author zhangshuang | |||
| * @create 2019/4/18 | |||
| * @since 1.0.0 | |||
| * | |||
| */ | |||
| public class DSMsgResolverFactory { | |||
| /** | |||
| * 获得数据序列消息编码器实例 | |||
| * @param dsWriter 差异请求者执行数据序列更新的执行器 | |||
| * @param dsReader 差异响应者执行数据序列读取的执行器 | |||
| * @return 消息编码器实例 | |||
| */ | |||
| public static DataSequenceMsgEncoder getEncoder(DataSequenceWriter dsWriter, DataSequenceReader dsReader) { | |||
| return new DataSequenceMsgEncoder(dsWriter, dsReader); | |||
| } | |||
| /** | |||
| * 获得数据序列消息解码器实例 | |||
| * @param dsWriter 差异请求者执行数据序列更新的执行器 | |||
| * @param dsReader 差异响应者执行数据序列读取的执行器 | |||
| * @return 消息解码器实例 | |||
| */ | |||
| public static DataSequenceMsgDecoder getDecoder(DataSequenceWriter dsWriter, DataSequenceReader dsReader) { | |||
| return new DataSequenceMsgDecoder(dsWriter, dsReader); | |||
| } | |||
| } | |||
| @@ -0,0 +1,28 @@ | |||
| package com.jd.blockchain.statetransfer.message; | |||
| import com.jd.blockchain.stp.communication.message.LoadMessage; | |||
| /** | |||
| * 数据序列复制的负载消息 | |||
| * @author zhangshuang | |||
| * @create 2019/4/18 | |||
| * @since 1.0.0 | |||
| * | |||
| */ | |||
| public class DataSequenceLoadMessage implements LoadMessage { | |||
| byte[] bytes; | |||
| public DataSequenceLoadMessage(byte[] bytes) { | |||
| this.bytes = bytes; | |||
| } | |||
| public void setBytes(byte[] bytes) { | |||
| this.bytes = bytes; | |||
| } | |||
| @Override | |||
| public byte[] toBytes() { | |||
| return bytes; | |||
| } | |||
| } | |||
| @@ -0,0 +1,107 @@ | |||
| package com.jd.blockchain.statetransfer.message; | |||
| import com.jd.blockchain.statetransfer.DataSequenceElement; | |||
| import com.jd.blockchain.statetransfer.DataSequenceInfo; | |||
| import com.jd.blockchain.statetransfer.callback.DataSequenceReader; | |||
| import com.jd.blockchain.statetransfer.callback.DataSequenceWriter; | |||
| import com.jd.blockchain.statetransfer.process.DSTransferProcess; | |||
| import com.jd.blockchain.statetransfer.result.DSDiffRequestResult; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils; | |||
| /** | |||
| * 数据序列消息解码器 | |||
| * @author zhangshuang | |||
| * @create 2019/4/18 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class DataSequenceMsgDecoder { | |||
| private int heightSize = 8; | |||
| private int msgTypeSize = 1; | |||
| private long respHeight; | |||
| private long fromHeight; | |||
| private long toHeight; | |||
| private int idSize; | |||
| private byte[] idBytes; | |||
| private String id; | |||
| private int diffElemSize; | |||
| private byte[] diffElem; | |||
| DataSequenceElement dsElement; | |||
| private DataSequenceWriter dsWriter; | |||
| private DataSequenceReader dsReader; | |||
| public DataSequenceMsgDecoder(DataSequenceWriter dsWriter, DataSequenceReader dsReader) { | |||
| this.dsWriter = dsWriter; | |||
| this.dsReader = dsReader; | |||
| } | |||
| /** | |||
| * 对编过码的字节数组解码,还原成对象实例 | |||
| * @param loadMessage 字节序列 | |||
| * @return 解码后的对象 | |||
| */ | |||
| public Object decode(byte[] loadMessage) { | |||
| try { | |||
| if (loadMessage.length <= 5) { | |||
| System.out.println("LoadMessage size is less than 5!"); | |||
| throw new IllegalArgumentException(); | |||
| } | |||
| int dataLength = BytesUtils.toInt(loadMessage, 0, 4); | |||
| byte msgCode = loadMessage[4]; | |||
| // send by diff provider, diff requester decode | |||
| if (msgCode == DSTransferProcess.DataSequenceMsgType.CMD_DSINFO_RESPONSE.CODE) { | |||
| respHeight = BytesUtils.toLong(loadMessage, 4 + msgTypeSize); | |||
| idSize = BytesUtils.toInt(loadMessage, 4 + msgTypeSize + heightSize, 4); | |||
| idBytes = new byte[idSize]; | |||
| System.arraycopy(loadMessage, 4 + msgTypeSize + heightSize + 4, idBytes, 0, idSize); | |||
| id = new String(idBytes); | |||
| return new DataSequenceInfo(id, respHeight); | |||
| } | |||
| // send by diff provider, diff requester decode | |||
| else if (msgCode == DSTransferProcess.DataSequenceMsgType.CMD_GETDSDIFF_RESPONSE.CODE) { | |||
| diffElemSize = BytesUtils.toInt(loadMessage, 4 + msgTypeSize, 4); | |||
| diffElem = new byte[diffElemSize]; | |||
| System.arraycopy(loadMessage, 4 + msgTypeSize + 4, diffElem, 0, diffElemSize); | |||
| dsElement = BinarySerializeUtils.deserialize(diffElem); | |||
| return dsElement; | |||
| } | |||
| // send by diff requester, diff provider decode | |||
| else if (msgCode == DSTransferProcess.DataSequenceMsgType.CMD_DSINFO_REQUEST.CODE) { | |||
| idSize = BytesUtils.toInt(loadMessage, 4 + msgTypeSize, 4); | |||
| idBytes = new byte[idSize]; | |||
| System.arraycopy(loadMessage, 4 + msgTypeSize + 4, idBytes, 0, idSize); | |||
| id = new String(idBytes); | |||
| return id; | |||
| } | |||
| // send by diff requester, diff provider decode | |||
| else if (msgCode == DSTransferProcess.DataSequenceMsgType.CMD_GETDSDIFF_REQUEST.CODE) { | |||
| fromHeight = BytesUtils.toLong(loadMessage, 4 + msgTypeSize); | |||
| toHeight = BytesUtils.toLong(loadMessage, 4 + msgTypeSize + heightSize); | |||
| idSize = BytesUtils.toInt(loadMessage, 4 + msgTypeSize + heightSize + heightSize, 4); | |||
| idBytes = new byte[idSize]; | |||
| System.arraycopy(loadMessage, 4 + msgTypeSize + heightSize + heightSize + 4, idBytes, 0, idSize); | |||
| id = new String(idBytes); | |||
| return new DSDiffRequestResult(id, fromHeight, toHeight); | |||
| } | |||
| else { | |||
| System.out.println("Unknown message type!"); | |||
| throw new IllegalArgumentException(); | |||
| } | |||
| } catch (Exception e) { | |||
| System.out.println("Error to decode message: " + e.getMessage() + "!"); | |||
| e.printStackTrace(); | |||
| } | |||
| return null; | |||
| } | |||
| } | |||
| @@ -0,0 +1,133 @@ | |||
| package com.jd.blockchain.statetransfer.message; | |||
| import com.jd.blockchain.statetransfer.DataSequenceElement; | |||
| import com.jd.blockchain.statetransfer.callback.DataSequenceReader; | |||
| import com.jd.blockchain.statetransfer.callback.DataSequenceWriter; | |||
| import com.jd.blockchain.statetransfer.process.DSTransferProcess; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils; | |||
| /** | |||
| * 数据序列消息编码器 | |||
| * @author zhangshuang | |||
| * @create 2019/4/18 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class DataSequenceMsgEncoder { | |||
| private int heightSize = 8; | |||
| private int msgTypeSize = 1; | |||
| private DataSequenceWriter dsWriter; | |||
| private DataSequenceReader dsReader; | |||
| public DataSequenceMsgEncoder(DataSequenceWriter dsWriter, DataSequenceReader dsReader) { | |||
| this.dsWriter = dsWriter; | |||
| this.dsReader = dsReader; | |||
| } | |||
| /** | |||
| * 目前暂时考虑fromHeight与toHeight相同的情况,即每次只对一个高度的差异内容进行编码并响应 | |||
| * 把消息编码成字节数组,再交给通信层传输 | |||
| * @param msgType 数据序列状态复制消息类型 | |||
| * @param id 数据序列唯一标识符 | |||
| * @param fromHeight 差异元素起始高度 | |||
| * @param toHeight 差异元素结束高度 | |||
| */ | |||
| public byte[] encode(DSTransferProcess.DataSequenceMsgType msgType, String id, long fromHeight, long toHeight) { | |||
| try { | |||
| int dataLength; | |||
| int idSize = id.getBytes().length; | |||
| byte[] loadMessage = null; | |||
| // different encoding methods for different message types | |||
| // send by diff requester, diff requester encode | |||
| if (msgType == DSTransferProcess.DataSequenceMsgType.CMD_DSINFO_REQUEST) { | |||
| // CMD_DSINFO_REQUEST Message parts : 4 bytes total message size, 1 byte message type coe, | |||
| // 4 bytes id length, id content size bytes | |||
| dataLength = 4 + msgTypeSize + 4 + idSize; | |||
| loadMessage = new byte[dataLength]; | |||
| System.arraycopy(BytesUtils.toBytes(dataLength), 0, loadMessage, 0, 4); | |||
| loadMessage[4] = msgType.CODE; | |||
| System.arraycopy(BytesUtils.toBytes(idSize), 0, loadMessage, 4 + msgTypeSize, 4); | |||
| System.arraycopy(id.getBytes(), 0, loadMessage, 4 + msgTypeSize + 4, idSize); | |||
| } | |||
| // send by diff requester, diff requester encode | |||
| else if (msgType == DSTransferProcess.DataSequenceMsgType.CMD_GETDSDIFF_REQUEST) { | |||
| // CMD_GETDSDIFF_REQUEST Message parts : 4 bytes total message size, 1 byte message type coe, 8 bytes from height, | |||
| // 8 bytes to height, 4 bytes id length, id content size bytes | |||
| dataLength = 4 + msgTypeSize + heightSize + heightSize + 4 + idSize; | |||
| loadMessage = new byte[dataLength]; | |||
| System.arraycopy(BytesUtils.toBytes(dataLength), 0, loadMessage, 0, 4); | |||
| loadMessage[4] = msgType.CODE; | |||
| System.arraycopy(BytesUtils.toBytes(fromHeight), 0, loadMessage, 4 + msgTypeSize, heightSize); | |||
| System.arraycopy(BytesUtils.toBytes(toHeight), 0, loadMessage, 4 + msgTypeSize + heightSize, heightSize); | |||
| System.arraycopy(BytesUtils.toBytes(idSize), 0, loadMessage, 4 + msgTypeSize + heightSize + heightSize, 4); | |||
| System.arraycopy(id.getBytes(), 0, loadMessage, 4 + msgTypeSize + heightSize + heightSize + 4, idSize); | |||
| } | |||
| // send by diff provider, diff provider encode | |||
| else if (msgType == DSTransferProcess.DataSequenceMsgType.CMD_DSINFO_RESPONSE) { | |||
| // CMD_DSINFO_RESPONSE Message parts : 4 bytes total message size, 1 byte message type coe, 8 bytes data sequence local height, | |||
| // 4 bytes id length, id content size bytes | |||
| dataLength = 4 + msgTypeSize + heightSize + 4 + idSize; | |||
| loadMessage = new byte[dataLength]; | |||
| System.arraycopy(BytesUtils.toBytes(dataLength), 0, loadMessage, 0, 4); | |||
| loadMessage[4] = msgType.CODE; | |||
| System.arraycopy(BytesUtils.toBytes(dsReader.getDSInfo(id).getHeight()), 0, loadMessage, 4 + msgTypeSize, heightSize); | |||
| System.arraycopy(BytesUtils.toBytes(idSize), 0, loadMessage, 4 + msgTypeSize + heightSize, 4); | |||
| System.arraycopy(id.getBytes(), 0, loadMessage, 4 + msgTypeSize + heightSize + 4, idSize); | |||
| } | |||
| // send by diff provider, diff provider encode | |||
| else if (msgType == DSTransferProcess.DataSequenceMsgType.CMD_GETDSDIFF_RESPONSE) { | |||
| if (fromHeight != toHeight) { | |||
| throw new IllegalArgumentException("Height parameter error!"); | |||
| } | |||
| // CMD_DSINFO_RESPONSE Message parts : 4 bytes total message size, 1 byte message type coe, | |||
| // 4 bytes diffElem size, diff content size; | |||
| // 回调reader,获得这个高度上的所有差异的数据序列内容,并组织成DataSequenceElement结构 | |||
| DataSequenceElement element = dsReader.getDSDiffContent(id, fromHeight); | |||
| byte[] diffElem = BinarySerializeUtils.serialize(element); | |||
| dataLength = 4 + msgTypeSize + 4 + diffElem.length; | |||
| loadMessage = new byte[dataLength]; | |||
| System.arraycopy(BytesUtils.toBytes(dataLength), 0, loadMessage, 0, 4); //total size | |||
| loadMessage[4] = msgType.CODE; //msgType size | |||
| System.arraycopy(BytesUtils.toBytes(diffElem.length), 0, loadMessage, 4 + msgTypeSize, 4); // diffElem size | |||
| System.arraycopy(diffElem, 0, loadMessage, 4 + msgTypeSize + 4, diffElem.length); // diffElem bytes | |||
| } | |||
| else { | |||
| System.out.println("Unknown message type!"); | |||
| throw new IllegalArgumentException(); | |||
| } | |||
| return loadMessage; | |||
| } catch (Exception e) { | |||
| System.out.println("Error to encode message type : " + msgType + "!"); | |||
| e.printStackTrace(); | |||
| } | |||
| return null; | |||
| } | |||
| } | |||
| @@ -0,0 +1,186 @@ | |||
| package com.jd.blockchain.statetransfer.process; | |||
| import com.jd.blockchain.statetransfer.DataSequenceElement; | |||
| import com.jd.blockchain.statetransfer.DataSequenceInfo; | |||
| import com.jd.blockchain.statetransfer.callback.DataSequenceReader; | |||
| import com.jd.blockchain.statetransfer.callback.DataSequenceWriter; | |||
| import com.jd.blockchain.statetransfer.comparator.DataSequenceComparator; | |||
| import com.jd.blockchain.statetransfer.message.DSDefaultMessageExecutor; | |||
| import com.jd.blockchain.statetransfer.result.DSInfoResponseResult; | |||
| import com.jd.blockchain.stp.communication.RemoteSession; | |||
| import com.jd.blockchain.stp.communication.callback.CallBackBarrier; | |||
| import com.jd.blockchain.stp.communication.callback.CallBackDataListener; | |||
| import com.jd.blockchain.stp.communication.manager.RemoteSessionManager; | |||
| import com.jd.blockchain.stp.communication.node.LocalNode; | |||
| import com.jd.blockchain.stp.communication.node.RemoteNode; | |||
| import java.net.InetSocketAddress; | |||
| import java.util.*; | |||
| import java.util.concurrent.*; | |||
| /** | |||
| * 数据序列状态复制过程管理器 | |||
| * @author zhangshuang | |||
| * @create 2019/4/11 | |||
| * @since 1.0.0 | |||
| * | |||
| */ | |||
| public class DSProcessManager { | |||
| private static Map<String, DSTransferProcess> dSProcessMap = new ConcurrentHashMap<>(); | |||
| private RemoteSession[] remoteSessions; | |||
| private long dsInfoResponseTimeout = 20000; | |||
| private ExecutorService writeExecutors = Executors.newFixedThreadPool(5); | |||
| private int returnCode = 0; | |||
| /** | |||
| * 启动一个指定数据序列的状态复制过程 | |||
| * @param dsInfo 数据序列当前状态信息 | |||
| * @param listener 本地监听者 | |||
| * @param targets 目标结点 | |||
| * @param dsWriter 差异请求者执行数据序列更新的执行器 | |||
| * @param dsReader 差异响应者执行数据序列读取的执行器 | |||
| * @return returnCode 执行结果码 | |||
| */ | |||
| public int startDSProcess(DataSequenceInfo dsInfo, InetSocketAddress listener, InetSocketAddress[] targets, DataSequenceWriter dsWriter, DataSequenceReader dsReader) { | |||
| // create remote sessions manager, add listener | |||
| LocalNode listenNode = new LocalNode(listener.getHostName(), listener.getPort(), new DSDefaultMessageExecutor(dsReader, dsWriter)); | |||
| RemoteSessionManager remoteSessionManager = new RemoteSessionManager(listenNode); | |||
| // data sequence transfer process life cycle start | |||
| DSTransferProcess dsTransferProcess = new DSTransferProcess(dsInfo, targets); | |||
| dsTransferProcess.setDSReader(dsReader); | |||
| dsTransferProcess.setDSWriter(dsWriter); | |||
| dsTransferProcess.setRemoteSessionManager(remoteSessionManager); | |||
| dSProcessMap.put(dsInfo.getId(), dsTransferProcess); | |||
| try { | |||
| //wait all listener nodes start | |||
| Thread.sleep(2000); | |||
| // start network connections with targets | |||
| dsTransferProcess.start(); | |||
| //get all target sessions | |||
| remoteSessions = dsTransferProcess.getSessions(); | |||
| // async message send process | |||
| CallBackBarrier callBackBarrier = CallBackBarrier.newCallBackBarrier(remoteSessions.length, dsInfoResponseTimeout); | |||
| // response message manage map | |||
| LinkedList<CallBackDataListener> dsInfoResponses = new LinkedList<>(); | |||
| System.out.println("Async send CMD_DSINFO_REQUEST msg to targets will start!"); | |||
| // step1: send get dsInfo request, then hold | |||
| for (RemoteSession remoteSession : remoteSessions) { | |||
| CallBackDataListener dsInfoResponse = dsTransferProcess.send(DSTransferProcess.DataSequenceMsgType.CMD_DSINFO_REQUEST, remoteSession, 0, 0, callBackBarrier); | |||
| dsInfoResponses.addLast(dsInfoResponse); | |||
| } | |||
| System.out.println("Wait CMD_DSINFO_RESPONSE msg from targets!"); | |||
| // step2: collect get dsInfo response | |||
| LinkedList<CallBackDataListener> receiveResponses = new LinkedList<>(); | |||
| if (callBackBarrier.tryCall()) { | |||
| Iterator<CallBackDataListener> iterator = dsInfoResponses.iterator(); | |||
| while (iterator.hasNext()) { | |||
| CallBackDataListener receiveResponse = iterator.next(); | |||
| if (receiveResponse.isDone()) { | |||
| receiveResponses.addLast(receiveResponse); | |||
| } | |||
| } | |||
| } | |||
| System.out.printf("%s:%d Compute diff info!\r\n", listener.getHostName(), listener.getPort()); | |||
| // step3: process received responses | |||
| DSInfoResponseResult diffResult = dsTransferProcess.computeDiffInfo(receiveResponses); | |||
| System.out.printf("%s:%d Diff info result height = %x!\r\n", listener.getHostName(), listener.getPort(), diffResult.getMaxHeight()); | |||
| // height diff | |||
| long diff = dsInfo.getHeight() - diffResult.getMaxHeight(); | |||
| if (diff == 0 || diff > 0) { | |||
| System.out.printf("%s:%d No duplication is required!\r\n", listener.getHostName(), listener.getPort()); | |||
| // no duplication is required, life cycle ends | |||
| // dsTransferProcess.close(); | |||
| dSProcessMap.remove(dsInfo.getId()); | |||
| return returnCode; | |||
| } | |||
| else { | |||
| System.out.printf("%s:%d Duplication is required!\r\n", listener.getHostName(), listener.getPort()); | |||
| // step4: async send get data sequence diff request | |||
| // single step get diff | |||
| // async message send process | |||
| CallBackBarrier callBackBarrierDiff = CallBackBarrier.newCallBackBarrier((int)(diffResult.getMaxHeight() - dsInfo.getHeight()), dsInfoResponseTimeout); | |||
| LinkedList<CallBackDataListener> dsDiffResponses = new LinkedList<>(); | |||
| RemoteSession responseSession = findResponseSession(diffResult.getMaxHeightRemoteNode(), remoteSessions); | |||
| System.out.println("Async send CMD_GETDSDIFF_REQUEST msg to targets will start!"); | |||
| // step5: collect get data sequence diff response | |||
| for (long height = dsInfo.getHeight() + 1; height < diffResult.getMaxHeight() + 1; height++) { | |||
| CallBackDataListener dsDiffResponse = dsTransferProcess.send(DSTransferProcess.DataSequenceMsgType.CMD_GETDSDIFF_REQUEST, responseSession, height, height, callBackBarrierDiff); | |||
| dsDiffResponses.addLast(dsDiffResponse); | |||
| } | |||
| // 上述发送不合理,考虑一次性发送请求 | |||
| System.out.println("Wait CMD_GETDSDIFF_RESPONSE msg from targets!"); | |||
| LinkedList<byte[]> receiveDiffResponses = new LinkedList<>(); | |||
| if (callBackBarrierDiff.tryCall()) { | |||
| for (int i = 0; i < dsDiffResponses.size(); i++) { | |||
| CallBackDataListener asyncFutureDiff = dsDiffResponses.get(i); | |||
| if (asyncFutureDiff.isDone()) { | |||
| receiveDiffResponses.addLast(asyncFutureDiff.getCallBackData()); | |||
| } | |||
| } | |||
| } | |||
| System.out.printf("%s:%d ReceiveDiffResponses size = %d !\r\n", listener.getHostName(), listener.getPort(), receiveDiffResponses.size()); | |||
| // step6: process data sequence diff response, update local data sequence state | |||
| System.out.println("Compute diff elements!"); | |||
| ArrayList<DataSequenceElement> dataSequenceElements = dsTransferProcess.computeDiffElement(receiveDiffResponses.toArray(new byte[receiveDiffResponses.size()][])); | |||
| System.out.println("Update local data sequence!"); | |||
| Collections.sort(dataSequenceElements, new DataSequenceComparator()); | |||
| returnCode = dsWriter.updateDSInfo(dsInfo, dataSequenceElements.toArray(new DataSequenceElement[dataSequenceElements.size()])); | |||
| // data sequence transfer complete, close all sessions, end process life cycle | |||
| System.out.println("Close all sessions"); | |||
| // dsTransferProcess.close(); | |||
| dSProcessMap.remove(dsInfo.getId()); | |||
| } | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| } | |||
| return returnCode; | |||
| } | |||
| /** | |||
| * 根据远端结点找与远端结点建立的会话 | |||
| * @param remoteNode 远端结点 | |||
| * @param remoteSessions 本地维护的远端结点会话表 | |||
| * @return 与远端结点对应的会话 | |||
| */ | |||
| RemoteSession findResponseSession(RemoteNode remoteNode, RemoteSession[] remoteSessions) { | |||
| for (RemoteSession remoteSession : remoteSessions) { | |||
| if (remoteSession.remoteNode().equals(remoteNode)) { | |||
| return remoteSession; | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| /** | |||
| * | |||
| * | |||
| */ | |||
| // void setDSReader(DataSequenceReader reader) { | |||
| // | |||
| // } | |||
| } | |||
| @@ -0,0 +1,216 @@ | |||
| package com.jd.blockchain.statetransfer.process; | |||
| import com.jd.blockchain.statetransfer.DataSequenceElement; | |||
| import com.jd.blockchain.statetransfer.DataSequenceInfo; | |||
| import com.jd.blockchain.statetransfer.callback.DataSequenceReader; | |||
| import com.jd.blockchain.statetransfer.callback.DataSequenceWriter; | |||
| import com.jd.blockchain.statetransfer.message.DSMsgResolverFactory; | |||
| import com.jd.blockchain.statetransfer.message.DataSequenceLoadMessage; | |||
| import com.jd.blockchain.statetransfer.result.DSInfoResponseResult; | |||
| import com.jd.blockchain.stp.communication.RemoteSession; | |||
| import com.jd.blockchain.stp.communication.callback.CallBackBarrier; | |||
| import com.jd.blockchain.stp.communication.callback.CallBackDataListener; | |||
| import com.jd.blockchain.stp.communication.manager.RemoteSessionManager; | |||
| import com.jd.blockchain.stp.communication.node.RemoteNode; | |||
| import com.jd.blockchain.utils.IllegalDataException; | |||
| import java.net.InetSocketAddress; | |||
| import java.util.ArrayList; | |||
| import java.util.LinkedList; | |||
| import java.util.Map; | |||
| /** | |||
| * 数据序列状态复制过程 | |||
| * @author zhangshuang | |||
| * @create 2019/4/11 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class DSTransferProcess { | |||
| private InetSocketAddress[] targets; | |||
| private DataSequenceWriter dsWriter; | |||
| private DataSequenceReader dsReader; | |||
| private DataSequenceInfo dsInfo; | |||
| private RemoteSessionManager remoteSessionManager; | |||
| private RemoteSession[] remoteSessions; | |||
| private String id; | |||
| /** | |||
| * @param dsInfo 数据序列当前状态信息 | |||
| * @param targets 目标结点 | |||
| */ | |||
| public DSTransferProcess(DataSequenceInfo dsInfo, InetSocketAddress[] targets) { | |||
| this.dsInfo = dsInfo; | |||
| this.targets = targets; | |||
| this.id = dsInfo.getId(); | |||
| } | |||
| /** | |||
| * @param dsWriter 差异请求者执行数据序列更新的执行器 | |||
| * @return void | |||
| */ | |||
| public void setDSWriter(DataSequenceWriter dsWriter) { | |||
| this.dsWriter = dsWriter; | |||
| } | |||
| /** | |||
| * @param dsReader 差异响应者执行数据序列读取的执行器 | |||
| * @return void | |||
| */ | |||
| public void setDSReader(DataSequenceReader dsReader) { | |||
| this.dsReader = dsReader; | |||
| } | |||
| /** | |||
| * @param remoteSessionManager 远端会话管理器 | |||
| * @return void | |||
| */ | |||
| public void setRemoteSessionManager(RemoteSessionManager remoteSessionManager) { | |||
| this.remoteSessionManager = remoteSessionManager; | |||
| } | |||
| /** | |||
| * | |||
| * @return 数据序列标识符 | |||
| */ | |||
| public String getId() { | |||
| return id; | |||
| } | |||
| /** | |||
| * @param msgType 数据序列差异请求消息类型 | |||
| * @param remoteSession 目标结点对应的会话 | |||
| * @param fromHeight 差异起始高度 | |||
| * @param toHeight 差异结束高度 | |||
| * @param callBackBarrier 异步回调 | |||
| * @return 异步回调 | |||
| */ | |||
| CallBackDataListener send(DataSequenceMsgType msgType, RemoteSession remoteSession, long fromHeight, long toHeight, CallBackBarrier callBackBarrier) { | |||
| byte[] loadMessage = DSMsgResolverFactory.getEncoder(dsWriter, dsReader).encode(msgType, id, fromHeight, toHeight); | |||
| return remoteSession.asyncRequest(new DataSequenceLoadMessage(loadMessage), callBackBarrier); | |||
| } | |||
| /** | |||
| * 计算数据序列差异元素数组 | |||
| * @param diffArray 差异的字节数组 | |||
| * @return 对差异字节数组的解码结果 | |||
| */ | |||
| public ArrayList<DataSequenceElement> computeDiffElement(byte[][] diffArray) { | |||
| ArrayList<DataSequenceElement> dataSequenceElements = new ArrayList<>(); | |||
| for (int i = 0 ; i < diffArray.length; i++) { | |||
| Object object = DSMsgResolverFactory.getDecoder(dsWriter, dsReader).decode(diffArray[i]); | |||
| if (object instanceof DataSequenceElement) { | |||
| dataSequenceElements.add((DataSequenceElement) object); | |||
| } | |||
| else { | |||
| throw new IllegalDataException("Unknown instance object!"); | |||
| } | |||
| } | |||
| return dataSequenceElements; | |||
| } | |||
| /** | |||
| * 根据差异提供者响应的数据序列状态信息找到拥有最大数据序列高度的远端结点 | |||
| * @param receiveResponses 数据序列差异请求者收到的远端结点状态的响应信息 | |||
| * @return 得到远端数据序列的最大高度以及拥有者结点 | |||
| */ | |||
| public DSInfoResponseResult computeDiffInfo(LinkedList<CallBackDataListener> receiveResponses) { | |||
| long maxHeight = 0; | |||
| RemoteNode maxHeightRemoteNode = null; | |||
| System.out.println("ComputeDiffInfo receiveResponses size = "+ receiveResponses.size()); | |||
| try { | |||
| for (CallBackDataListener receiveResponse : receiveResponses) { | |||
| Object object = DSMsgResolverFactory.getDecoder(dsWriter, dsReader).decode(receiveResponse.getCallBackData()); | |||
| if (object instanceof DataSequenceInfo) { | |||
| DataSequenceInfo dsInfo = (DataSequenceInfo) object; | |||
| long height = dsInfo.getHeight(); | |||
| // sava max height and its remote node | |||
| if (maxHeight < height) { | |||
| maxHeight = height; | |||
| maxHeightRemoteNode = receiveResponse.remoteNode(); | |||
| } | |||
| } | |||
| else { | |||
| throw new IllegalDataException("Unknown instance object!"); | |||
| } | |||
| } | |||
| } catch (Exception e) { | |||
| System.out.println(e.getMessage()); | |||
| e.printStackTrace(); | |||
| } | |||
| return new DSInfoResponseResult(maxHeight, maxHeightRemoteNode); | |||
| } | |||
| /** | |||
| * 获取本复制过程维护的远端会话表 | |||
| * @param | |||
| * @return 远端会话表数组 | |||
| */ | |||
| public RemoteSession[] getSessions() { | |||
| return remoteSessions; | |||
| } | |||
| /** | |||
| * 关闭本复制过程维护的所有远端会话 | |||
| * @return void | |||
| */ | |||
| public void close() { | |||
| for (RemoteSession session : remoteSessions) { | |||
| session.closeAll(); | |||
| } | |||
| } | |||
| /** | |||
| * 建立与远端目标结点的连接,产生本地维护的远端会话表 | |||
| * @return void | |||
| */ | |||
| public void start() { | |||
| RemoteNode[] remoteNodes = new RemoteNode[targets.length]; | |||
| for (int i = 0; i < remoteNodes.length; i++) { | |||
| remoteNodes[i] = new RemoteNode(targets[i].getHostName(), targets[i].getPort()); | |||
| } | |||
| remoteSessions = remoteSessionManager.newSessions(remoteNodes); | |||
| } | |||
| /** | |||
| * 数据序列状态传输使用的消息类型 | |||
| * | |||
| */ | |||
| public enum DataSequenceMsgType { | |||
| CMD_DSINFO_REQUEST((byte) 0x1), | |||
| CMD_DSINFO_RESPONSE((byte) 0x2), | |||
| CMD_GETDSDIFF_REQUEST((byte) 0x3), | |||
| CMD_GETDSDIFF_RESPONSE((byte) 0x4), | |||
| ; | |||
| public final byte CODE; | |||
| private DataSequenceMsgType(byte code) { | |||
| this.CODE = code; | |||
| } | |||
| public static DataSequenceMsgType valueOf(byte code) { | |||
| for (DataSequenceMsgType msgType : DataSequenceMsgType.values()) { | |||
| if (msgType.CODE == code) { | |||
| return msgType; | |||
| } | |||
| } | |||
| throw new IllegalArgumentException("Unsupported code[" + code + "] of msgType!"); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,45 @@ | |||
| package com.jd.blockchain.statetransfer.result; | |||
| /** | |||
| * 数据序列差异提供者解码请求者"CMD_GETDSDIFF_REQUEST"消息时得到的结果 | |||
| * @author zhangshuang | |||
| * @create 2019/4/18 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class DSDiffRequestResult { | |||
| String id; | |||
| long fromHeight; | |||
| long toHeight; | |||
| public DSDiffRequestResult(String id ,long fromHeight, long toHeight) { | |||
| this.id = id; | |||
| this.fromHeight = fromHeight; | |||
| this.toHeight = toHeight; | |||
| } | |||
| public String getId() { | |||
| return id; | |||
| } | |||
| public long getFromHeight() { | |||
| return fromHeight; | |||
| } | |||
| public long getToHeight() { | |||
| return toHeight; | |||
| } | |||
| public void setId(String id) { | |||
| this.id = id; | |||
| } | |||
| public void setFromHeight(long fromHeight) { | |||
| this.fromHeight = fromHeight; | |||
| } | |||
| public void setToHeight(long toHeight) { | |||
| this.toHeight = toHeight; | |||
| } | |||
| } | |||
| @@ -0,0 +1,37 @@ | |||
| package com.jd.blockchain.statetransfer.result; | |||
| import com.jd.blockchain.stp.communication.node.RemoteNode; | |||
| /** | |||
| * 数据序列差异请求者解码提供者"CMD_DSINFO_RESPONSE"消息时得到的结果 | |||
| * @author zhangshuang | |||
| * @create 2019/4/18 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class DSInfoResponseResult { | |||
| long maxHeight; | |||
| RemoteNode maxHeightRemoteNode; | |||
| public DSInfoResponseResult(long maxHeight, RemoteNode maxHeightRemoteNode) { | |||
| this.maxHeight = maxHeight; | |||
| this.maxHeightRemoteNode = maxHeightRemoteNode; | |||
| } | |||
| public long getMaxHeight() { | |||
| return maxHeight; | |||
| } | |||
| public RemoteNode getMaxHeightRemoteNode() { | |||
| return maxHeightRemoteNode; | |||
| } | |||
| public void setMaxHeight(long maxHeight) { | |||
| this.maxHeight = maxHeight; | |||
| } | |||
| public void setMaxHeightRemoteNode(RemoteNode maxHeightRemoteNode) { | |||
| this.maxHeightRemoteNode = maxHeightRemoteNode; | |||
| } | |||
| } | |||
| @@ -0,0 +1,155 @@ | |||
| package test.com.jd.blockchain.statetransfer; | |||
| import com.jd.blockchain.statetransfer.DataSequence; | |||
| import com.jd.blockchain.statetransfer.DataSequenceElement; | |||
| import com.jd.blockchain.statetransfer.DataSequenceInfo; | |||
| import com.jd.blockchain.statetransfer.callback.DataSequenceReaderImpl; | |||
| import com.jd.blockchain.statetransfer.callback.DataSequenceWriterImpl; | |||
| import com.jd.blockchain.statetransfer.process.DSProcessManager; | |||
| import com.jd.blockchain.utils.codec.Base58Utils; | |||
| import org.junit.Before; | |||
| import org.junit.Test; | |||
| import java.net.InetSocketAddress; | |||
| import java.util.LinkedList; | |||
| import java.util.Random; | |||
| import java.util.concurrent.CountDownLatch; | |||
| import java.util.concurrent.ExecutorService; | |||
| import java.util.concurrent.Executors; | |||
| /** | |||
| * @author zhangshuang | |||
| * @create 2019/4/18 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class StateTransferLayerTest { | |||
| private final int[] listenPorts = new int[]{9000, 9010, 9020, 9030}; | |||
| private String localIp = "127.0.0.1"; | |||
| private int DataSequenceNum = 1; | |||
| private int nodesNum = 4; | |||
| private byte[] idBytes = new byte[20]; | |||
| private Random rand = new Random(); | |||
| private String[] dataSequenceIds = new String[DataSequenceNum]; | |||
| private InetSocketAddress[] remoteNodeIps = new InetSocketAddress[nodesNum]; | |||
| private final ExecutorService threadPool = Executors.newFixedThreadPool(8); | |||
| private static LinkedList<DataSequence> dataSequencesPerNode = new LinkedList<>(); | |||
| // 假定每个数据序列元素里有四条记录数据 | |||
| private byte[][] dsElementDatas = new byte[4][]; | |||
| @Before | |||
| public void init() { | |||
| // 产生两个唯一的数据序列Id标识 | |||
| for (int i = 0; i < DataSequenceNum; i++) { | |||
| dataSequenceIds[i] = new String(); | |||
| rand.nextBytes(idBytes); | |||
| dataSequenceIds[i] = Base58Utils.encode(idBytes); | |||
| } | |||
| // 准备好所有的远端结点,包括监听者 | |||
| for (int i = 0; i < nodesNum; i++) { | |||
| remoteNodeIps[i] = new InetSocketAddress(localIp, listenPorts[i]); | |||
| } | |||
| // 为数据序列的每个高度准备好内容,为了方便测试,每个高度的内容设置为一致 | |||
| for (int i = 0; i < dsElementDatas.length; i++) { | |||
| rand.nextBytes(idBytes); | |||
| dsElementDatas[i] = idBytes; | |||
| } | |||
| // 为结点准备数据序列 | |||
| for (String id : dataSequenceIds) { | |||
| for (int i = 0; i < remoteNodeIps.length; i++) { | |||
| DataSequence dataSequence = new DataSequence(remoteNodeIps[i], id); | |||
| // 为数据序列的0,1,2高度添加内容 | |||
| for (int j = 0; j < 3; j++) { | |||
| dataSequence.addElement(new DataSequenceElement(id, j, dsElementDatas)); | |||
| } | |||
| dataSequencesPerNode.addLast(dataSequence); | |||
| } | |||
| // 把其中一个结点的数据序列与其他结点区别开来 | |||
| for (int i = 0; i < dataSequencesPerNode.size(); i++) { | |||
| DataSequence dataSequence = dataSequencesPerNode.get(i); | |||
| if (dataSequence.getAddress().getPort() != listenPorts[0]) { | |||
| // 为数据序列的3,4高度添加内容 | |||
| for (int j = 3; j < 5; j++) { | |||
| dataSequence.addElement(new DataSequenceElement(id, j, dsElementDatas)); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| InetSocketAddress[] getTargetNodesIp(InetSocketAddress listenIp, InetSocketAddress[] remoteNodeIps) { | |||
| // 获得除监听结点之外的其他远端结点 | |||
| InetSocketAddress[] targets = new InetSocketAddress[remoteNodeIps.length - 1]; | |||
| int j = 0; | |||
| for (int i = 0; i < remoteNodeIps.length; i++) { | |||
| if ((remoteNodeIps[i].getHostName().equals(listenIp.getHostName())) && (remoteNodeIps[i].getPort() == listenIp.getPort())) { | |||
| continue; | |||
| } | |||
| targets[j++] = new InetSocketAddress(remoteNodeIps[i].getHostName(), remoteNodeIps[i].getPort()); | |||
| } | |||
| return targets; | |||
| } | |||
| DataSequence findDataSequence(String id, InetSocketAddress listenNodeAddr) { | |||
| for (DataSequence dataSequence : dataSequencesPerNode) { | |||
| if ((dataSequence.getAddress().getPort() == listenNodeAddr.getPort() && (dataSequence.getAddress().getHostName().equals(listenNodeAddr.getHostName())) | |||
| && (dataSequence.getId().equals(id)))) { | |||
| return dataSequence; | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| @Test | |||
| public void test() { | |||
| CountDownLatch countDownLatch = new CountDownLatch(nodesNum); | |||
| for (String id : dataSequenceIds) { | |||
| for (int i = 0; i < nodesNum; i++) { | |||
| InetSocketAddress listenNode = remoteNodeIps[i]; | |||
| threadPool.execute(() -> { | |||
| // 创建数据序列处理管理者实例 | |||
| DSProcessManager dsProcessManager = new DSProcessManager(); | |||
| DataSequence currDataSequence = findDataSequence(id, listenNode); | |||
| DataSequenceInfo dsInfo = currDataSequence.getDSInfo(); | |||
| InetSocketAddress[] targets = getTargetNodesIp(listenNode, remoteNodeIps); | |||
| dsProcessManager.startDSProcess(dsInfo, listenNode, targets, new DataSequenceWriterImpl(currDataSequence), new DataSequenceReaderImpl(currDataSequence)); | |||
| countDownLatch.countDown(); | |||
| }); | |||
| } | |||
| } | |||
| // 等待数据序列更新完成 | |||
| try { | |||
| Thread.sleep(60000); | |||
| countDownLatch.await(); | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,21 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |||
| <parent> | |||
| <artifactId>jdchain-root</artifactId> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <version>0.9.0-SNAPSHOT</version> | |||
| </parent> | |||
| <modelVersion>4.0.0</modelVersion> | |||
| <artifactId>stp</artifactId> | |||
| <packaging>pom</packaging> | |||
| <modules> | |||
| <module>stp-communication</module> | |||
| </modules> | |||
| <properties> | |||
| <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |||
| </properties> | |||
| </project> | |||