diff --git a/.ci/ci_check.sh b/.ci/ci_check.sh index ee6d6dc3a..0ece21adb 100755 --- a/.ci/ci_check.sh +++ b/.ci/ci_check.sh @@ -1,6 +1,6 @@ #!/bin/bash set -e +# check code format bash gradlew verifyGoogleJavaFormat bash gradlew build - diff --git a/build.gradle b/build.gradle index 25c93b52a..334b099a5 100644 --- a/build.gradle +++ b/build.gradle @@ -57,14 +57,14 @@ dependencies { compile 'org.apache.commons:commons-lang3:3.1' compile 'io.netty:netty-all:4.1.50.Final' compile 'com.fasterxml.jackson.core:jackson-databind:2.11.0' - compile group: 'commons-codec', name: 'commons-codec', version: '1.14' - - + compile 'org.slf4j:slf4j-api:1.7.30' + compile files('lib/pkey-sign.jar') testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-core:2.23.0' + } archivesBaseName = 'java-sdk' group = 'org.fisco-bcos' -version = '1.0.0-SNAPSHOT' \ No newline at end of file +version = '1.0.0-SNAPSHOT' diff --git a/lib/pkey-sign.jar b/lib/pkey-sign.jar new file mode 100644 index 000000000..3637530ba Binary files /dev/null and b/lib/pkey-sign.jar differ diff --git a/src/main/java/org/fisco/bcos/sdk/crypto/hash/Hash.java b/src/main/java/org/fisco/bcos/sdk/crypto/hash/Hash.java new file mode 100644 index 000000000..c8f6b6648 --- /dev/null +++ b/src/main/java/org/fisco/bcos/sdk/crypto/hash/Hash.java @@ -0,0 +1,22 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** interface for hash calculation */ +package org.fisco.bcos.sdk.crypto.hash; + +public interface Hash { + String hash(final String inputData); + + byte[] hash(final byte[] inputBytes); +} diff --git a/src/main/java/org/fisco/bcos/sdk/crypto/hash/Keccak256.java b/src/main/java/org/fisco/bcos/sdk/crypto/hash/Keccak256.java new file mode 100644 index 000000000..65151a9bb --- /dev/null +++ b/src/main/java/org/fisco/bcos/sdk/crypto/hash/Keccak256.java @@ -0,0 +1,43 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.hash; + +import com.webank.wedpr.crypto.CryptoResult; +import com.webank.wedpr.crypto.NativeInterface; +import org.fisco.bcos.sdk.exceptions.HashException; +import org.fisco.bcos.sdk.utils.Hex; + +public class Keccak256 implements Hash { + + @Override + public String hash(final String inputData) { + return calculateHash(inputData.getBytes()); + } + + @Override + public byte[] hash(final byte[] inputBytes) { + return Hex.decode(calculateHash(inputBytes)); + } + + private String calculateHash(final byte[] inputBytes) { + // Note: the exceptions should be handled by the caller + CryptoResult hashResult = NativeInterface.keccak256(Hex.toHexString(inputBytes)); + if (hashResult.wedprErrorMessage != null && !hashResult.wedprErrorMessage.isEmpty()) { + throw new HashException( + "Calculate hash with keccak256 failed! error message:" + + hashResult.wedprErrorMessage); + } + return hashResult.hash; + } +} diff --git a/src/main/java/org/fisco/bcos/sdk/crypto/hash/SM3Hash.java b/src/main/java/org/fisco/bcos/sdk/crypto/hash/SM3Hash.java new file mode 100644 index 000000000..2cdcc9136 --- /dev/null +++ b/src/main/java/org/fisco/bcos/sdk/crypto/hash/SM3Hash.java @@ -0,0 +1,43 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.hash; + +import com.webank.wedpr.crypto.CryptoResult; +import com.webank.wedpr.crypto.NativeInterface; +import org.fisco.bcos.sdk.exceptions.HashException; +import org.fisco.bcos.sdk.utils.Hex; + +public class SM3Hash implements Hash { + @Override + public String hash(final String inputData) { + return calcualteHash(inputData.getBytes()); + } + + @Override + public byte[] hash(final byte[] inputBytes) { + // Considering inefficient string conversion, this interface is not recommended + return Hex.decode(calcualteHash(inputBytes)); + } + + private String calcualteHash(final byte[] inputBytes) { + CryptoResult hashResult = NativeInterface.sm3(Hex.toHexString(inputBytes)); + // call sm3 failed + if (hashResult.wedprErrorMessage != null && !hashResult.wedprErrorMessage.isEmpty()) { + throw new HashException( + "calculate hash with sm3 failed, error message:" + + hashResult.wedprErrorMessage); + } + return hashResult.hash; + } +} diff --git a/src/main/java/org/fisco/bcos/sdk/crypto/keypair/CryptoKeyPair.java b/src/main/java/org/fisco/bcos/sdk/crypto/keypair/CryptoKeyPair.java new file mode 100644 index 000000000..4c15ab2f9 --- /dev/null +++ b/src/main/java/org/fisco/bcos/sdk/crypto/keypair/CryptoKeyPair.java @@ -0,0 +1,105 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.keypair; + +import com.webank.wedpr.crypto.CryptoResult; +import java.math.BigInteger; +import java.util.Objects; + +public abstract class CryptoKeyPair { + private BigInteger privateKey; + protected BigInteger publicKey; + + protected String hexPrivateKey; + protected String hexPublicKey; + + public CryptoKeyPair() {} + + public CryptoKeyPair(final BigInteger privateKey) { + this.privateKey = privateKey; + /** + * todo: get publicKey according to privateKey this.publicKey = + * privateKeyToPublic(privateKey); + */ + calculateHexedKeyPair(); + } + + public CryptoKeyPair(final BigInteger privateKey, final BigInteger publicKey) { + this.privateKey = privateKey; + this.publicKey = publicKey; + calculateHexedKeyPair(); + } + + private void calculateHexedKeyPair() { + this.hexPrivateKey = this.privateKey.toString(16); + this.hexPublicKey = this.publicKey.toString(16); + } + + /** + * get CryptoKeyPair information from CryptoResult + * + * @param nativeResult + */ + CryptoKeyPair(final CryptoResult nativeResult) { + this.hexPrivateKey = nativeResult.privteKey; + this.hexPublicKey = nativeResult.publicKey; + this.privateKey = new BigInteger(this.hexPrivateKey, 16); + this.publicKey = new BigInteger(this.hexPublicKey, 16); + } + + public BigInteger getPrivateKey() { + return privateKey; + } + + public BigInteger getPublicKey() { + return publicKey; + } + + public String getHexPrivateKey() { + return hexPrivateKey; + } + + public String getHexPublicKey() { + return hexPublicKey; + } + + /** + * todo: get the public key from the given private key + * + * @param privateKey + * @return: the public key calculated from the private key public abstract BigInteger + * privateKeyToPublic(BigInteger privateKey); + */ + + /** + * generate keyPair randomly + * + * @return: the generated keyPair + */ + public abstract CryptoKeyPair generateKeyPair(); + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CryptoKeyPair keyPair = (CryptoKeyPair) o; + return Objects.equals(privateKey, keyPair.privateKey) + && Objects.equals(publicKey, keyPair.publicKey); + } + + @Override + public int hashCode() { + return Objects.hash(privateKey, publicKey); + } +} diff --git a/src/main/java/org/fisco/bcos/sdk/crypto/keypair/ECDSAKeyPair.java b/src/main/java/org/fisco/bcos/sdk/crypto/keypair/ECDSAKeyPair.java new file mode 100644 index 000000000..5f58fb9b5 --- /dev/null +++ b/src/main/java/org/fisco/bcos/sdk/crypto/keypair/ECDSAKeyPair.java @@ -0,0 +1,45 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.keypair; + +import com.webank.wedpr.crypto.CryptoResult; +import com.webank.wedpr.crypto.NativeInterface; +import java.math.BigInteger; + +public class ECDSAKeyPair extends CryptoKeyPair { + + public ECDSAKeyPair() {} + + public ECDSAKeyPair(BigInteger privateKey) { + super(privateKey); + } + + public ECDSAKeyPair(final BigInteger privateKey, final BigInteger publicKey) { + super(privateKey, publicKey); + } + + protected ECDSAKeyPair(final CryptoResult ecKeyPairInfo) { + super(ecKeyPairInfo); + } + + /** + * generate keyPair randomly + * + * @return: the generated keyPair + */ + @Override + public CryptoKeyPair generateKeyPair() { + return new ECDSAKeyPair(NativeInterface.secp256k1keyPair()); + } +} diff --git a/src/main/java/org/fisco/bcos/sdk/crypto/keypair/SM2KeyPair.java b/src/main/java/org/fisco/bcos/sdk/crypto/keypair/SM2KeyPair.java new file mode 100644 index 000000000..41b86558d --- /dev/null +++ b/src/main/java/org/fisco/bcos/sdk/crypto/keypair/SM2KeyPair.java @@ -0,0 +1,35 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.keypair; + +import com.webank.wedpr.crypto.CryptoResult; +import com.webank.wedpr.crypto.NativeInterface; + +public class SM2KeyPair extends CryptoKeyPair { + public SM2KeyPair() {} + + protected SM2KeyPair(CryptoResult sm2keyPairInfo) { + super(sm2keyPairInfo); + } + + /** + * generate keyPair randomly + * + * @return: the generated keyPair + */ + @Override + public CryptoKeyPair generateKeyPair() { + return new SM2KeyPair(NativeInterface.sm2keyPair()); + } +} diff --git a/src/main/java/org/fisco/bcos/sdk/crypto/signature/ECDSASignature.java b/src/main/java/org/fisco/bcos/sdk/crypto/signature/ECDSASignature.java new file mode 100644 index 000000000..cf7c35b66 --- /dev/null +++ b/src/main/java/org/fisco/bcos/sdk/crypto/signature/ECDSASignature.java @@ -0,0 +1,48 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.signature; + +import com.webank.pkeysign.service.ECCSignService; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.exceptions.SignatureException; + +public class ECDSASignature implements Signature { + + public static final ECCSignService eccSignService = new ECCSignService(); + + @Override + public SignatureResult sign(final String message, final CryptoKeyPair keyPair) { + String signature = eccSignService.sign(message, keyPair.getHexPrivateKey()); + if (signature == null) { + throw new SignatureException("Sign with secp256k1 failed"); + } + // convert signature string to SignatureResult struct + return new ECDSASignatureResult(signature); + } + + @Override + public SignatureResult sign(final byte[] message, final CryptoKeyPair keyPair) { + return sign(new String(message), keyPair); + } + + @Override + public boolean verify(final String publicKey, final String message, final String signature) { + return eccSignService.verify(message, signature, publicKey); + } + + @Override + public boolean verify(final String publicKey, final byte[] message, final byte[] signature) { + return verify(publicKey, new String(message), new String(signature)); + } +} diff --git a/src/main/java/org/fisco/bcos/sdk/crypto/signature/ECDSASignatureResult.java b/src/main/java/org/fisco/bcos/sdk/crypto/signature/ECDSASignatureResult.java new file mode 100644 index 000000000..a41583954 --- /dev/null +++ b/src/main/java/org/fisco/bcos/sdk/crypto/signature/ECDSASignatureResult.java @@ -0,0 +1,61 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.signature; + +import java.util.ArrayList; +import java.util.List; +import org.fisco.bcos.sdk.exceptions.SignatureException; +import org.fisco.bcos.sdk.rlp.RlpString; +import org.fisco.bcos.sdk.rlp.RlpType; +import org.fisco.bcos.sdk.utils.Hex; + +public class ECDSASignatureResult extends SignatureResult { + protected byte v; + + ECDSASignatureResult(byte v, byte[] r, byte[] s) { + super(r, s); + this.v = v; + } + + ECDSASignatureResult(final String signatureResult) { + super(signatureResult); + if (this.signatureBytes.length != 65) { + throw new SignatureException( + "Invalid signature for invalid length " + this.signatureBytes.length); + } + this.v = this.signatureBytes[64]; + } + + /** + * covert signatureResult into String + * + * @return: the signature string with [r, s, v] + */ + @Override + public String convertToString() { + byte[] SignatureBytes = new byte[65]; + System.arraycopy(this.r, 0, SignatureBytes, 0, 32); + System.arraycopy(this.s, 0, SignatureBytes, 32, 32); + SignatureBytes[64] = this.v; + return Hex.toHexString(SignatureBytes); + } + + @Override + public List encode() { + List encodeResult = new ArrayList<>(); + encodeResult.add(RlpString.create(this.v)); + super.encodeCommonField(encodeResult); + return encodeResult; + } +} diff --git a/src/main/java/org/fisco/bcos/sdk/crypto/signature/SM2Signature.java b/src/main/java/org/fisco/bcos/sdk/crypto/signature/SM2Signature.java new file mode 100644 index 000000000..782796b87 --- /dev/null +++ b/src/main/java/org/fisco/bcos/sdk/crypto/signature/SM2Signature.java @@ -0,0 +1,46 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.signature; + +import com.webank.pkeysign.service.SM2SignService; +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.exceptions.SignatureException; + +public class SM2Signature implements Signature { + public static final SM2SignService sm2SignService = new SM2SignService(); + + @Override + public SignatureResult sign(final String message, final CryptoKeyPair keyPair) { + String signature = sm2SignService.sign(message, keyPair.getHexPrivateKey()); + if (signature == null) { + throw new SignatureException("Sign with sm2 failed"); + } + return new SM2SignatureResult(keyPair.getHexPublicKey(), signature); + } + + @Override + public SignatureResult sign(final byte[] message, final CryptoKeyPair keyPair) { + return sign(new String(message), keyPair); + } + + @Override + public boolean verify(final String publicKey, final String message, final String signature) { + return sm2SignService.verify(message, signature, publicKey); + } + + @Override + public boolean verify(final String publicKey, final byte[] message, final byte[] signature) { + return verify(publicKey, new String(message), new String(signature)); + } +} diff --git a/src/main/java/org/fisco/bcos/sdk/crypto/signature/SM2SignatureResult.java b/src/main/java/org/fisco/bcos/sdk/crypto/signature/SM2SignatureResult.java new file mode 100644 index 000000000..c5664e080 --- /dev/null +++ b/src/main/java/org/fisco/bcos/sdk/crypto/signature/SM2SignatureResult.java @@ -0,0 +1,55 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.signature; + +import java.util.ArrayList; +import java.util.List; +import org.fisco.bcos.sdk.rlp.RlpString; +import org.fisco.bcos.sdk.rlp.RlpType; +import org.fisco.bcos.sdk.utils.Hex; + +public class SM2SignatureResult extends SignatureResult { + protected final byte[] pub; + + SM2SignatureResult(final String hexPublicKey, final String signatureString) { + super(signatureString); + this.pub = Hex.decode(hexPublicKey); + } + + SM2SignatureResult(byte[] pub, byte[] r, byte[] s) { + super(r, s); + this.pub = pub; + } + + /** + * covert signatureResult into String + * + * @return: the signature string with [r, s] + */ + @Override + public String convertToString() { + byte[] SignatureBytes = new byte[64]; + System.arraycopy(this.r, 0, SignatureBytes, 0, 32); + System.arraycopy(this.s, 0, SignatureBytes, 32, 32); + return Hex.toHexString(SignatureBytes); + } + + @Override + public List encode() { + List encodeResult = new ArrayList<>(); + encodeResult.add(RlpString.create(this.pub)); + super.encodeCommonField(encodeResult); + return encodeResult; + } +} diff --git a/src/main/java/org/fisco/bcos/sdk/crypto/signature/Signature.java b/src/main/java/org/fisco/bcos/sdk/crypto/signature/Signature.java new file mode 100644 index 000000000..c51b63932 --- /dev/null +++ b/src/main/java/org/fisco/bcos/sdk/crypto/signature/Signature.java @@ -0,0 +1,28 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** interface for sign/verify functions */ +package org.fisco.bcos.sdk.crypto.signature; + +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; + +public interface Signature { + SignatureResult sign(final byte[] message, final CryptoKeyPair keyPair); + + SignatureResult sign(final String message, final CryptoKeyPair keyPair); + + boolean verify(final String publicKey, final String message, final String signature); + + boolean verify(final String publicKey, final byte[] message, final byte[] signature); +} diff --git a/src/main/java/org/fisco/bcos/sdk/crypto/signature/SignatureResult.java b/src/main/java/org/fisco/bcos/sdk/crypto/signature/SignatureResult.java new file mode 100644 index 000000000..28386f4d3 --- /dev/null +++ b/src/main/java/org/fisco/bcos/sdk/crypto/signature/SignatureResult.java @@ -0,0 +1,78 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.crypto.signature; + +import java.util.List; +import org.fisco.bcos.sdk.exceptions.SignatureException; +import org.fisco.bcos.sdk.rlp.RlpString; +import org.fisco.bcos.sdk.rlp.RlpType; +import org.fisco.bcos.sdk.utils.Hex; + +public abstract class SignatureResult { + protected final byte[] r; + protected final byte[] s; + protected byte[] signatureBytes; + + SignatureResult(final byte[] r, final byte[] s) { + this.r = r; + this.s = s; + } + + /** + * Recover v, r, s from signature string The first 32 bytes are r, and the 32 bytes after r are + * s + * + * @param signatureString: the signatureString + */ + SignatureResult(final String signatureString) { + this.signatureBytes = Hex.decode(signatureString); + // at least 64 bytes + if (this.signatureBytes.length < 64) { + throw new SignatureException("Invalid signature: " + signatureString); + } + // get R + this.r = new byte[32]; + System.arraycopy(this.signatureBytes, 0, this.r, 0, 32); + // get S + this.s = new byte[32]; + System.arraycopy(this.signatureBytes, 32, this.s, 0, 32); + } + + public byte[] getR() { + return r; + } + + public byte[] getS() { + return s; + } + + protected void encodeCommonField(List encodeResult) { + encodeResult.add(RlpString.create(this.getR())); + encodeResult.add(RlpString.create(this.getS())); + } + + /** + * covert signatureResult into String + * + * @return: signatureResult in string form can be used as a verify parameter + */ + public abstract String convertToString(); + + /** + * encode the signatureResult into rlp-list + * + * @return: the encoded rlp-list with r, s, v( or pub) + */ + public abstract List encode(); +} diff --git a/src/main/java/org/fisco/bcos/sdk/exceptions/DecoderException.java b/src/main/java/org/fisco/bcos/sdk/exceptions/DecoderException.java index c1fc81e26..ad800cbd7 100644 --- a/src/main/java/org/fisco/bcos/sdk/exceptions/DecoderException.java +++ b/src/main/java/org/fisco/bcos/sdk/exceptions/DecoderException.java @@ -23,7 +23,8 @@ public DecoderException(String msg, Throwable cause) { this.cause = cause; } - public final Throwable getCause() { + @Override + public final synchronized Throwable getCause() { return cause; } } diff --git a/src/main/java/org/fisco/bcos/sdk/exceptions/EncoderException.java b/src/main/java/org/fisco/bcos/sdk/exceptions/EncoderException.java index d2ade61b8..304ec40e8 100644 --- a/src/main/java/org/fisco/bcos/sdk/exceptions/EncoderException.java +++ b/src/main/java/org/fisco/bcos/sdk/exceptions/EncoderException.java @@ -23,7 +23,8 @@ public EncoderException(String msg, Throwable cause) { this.cause = cause; } - public final Throwable getCause() { + @Override + public final synchronized Throwable getCause() { return cause; } } diff --git a/src/main/java/org/fisco/bcos/sdk/exceptions/HashException.java b/src/main/java/org/fisco/bcos/sdk/exceptions/HashException.java new file mode 100644 index 000000000..3ddcc2763 --- /dev/null +++ b/src/main/java/org/fisco/bcos/sdk/exceptions/HashException.java @@ -0,0 +1,25 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.exceptions; + +/** Exceptioned when calling hash. */ +public class HashException extends RuntimeException { + public HashException(String message) { + super(message); + } + + public HashException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/fisco/bcos/sdk/exceptions/SignatureException.java b/src/main/java/org/fisco/bcos/sdk/exceptions/SignatureException.java new file mode 100644 index 000000000..7a57f0850 --- /dev/null +++ b/src/main/java/org/fisco/bcos/sdk/exceptions/SignatureException.java @@ -0,0 +1,25 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.exceptions; + +/** Exceptioned when calling signature related functions. */ +public class SignatureException extends RuntimeException { + public SignatureException(String message) { + super(message); + } + + public SignatureException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/fisco/bcos/sdk/utils/ByteUtil.java b/src/main/java/org/fisco/bcos/sdk/utils/ByteUtil.java index 37a1e823a..627538519 100644 --- a/src/main/java/org/fisco/bcos/sdk/utils/ByteUtil.java +++ b/src/main/java/org/fisco/bcos/sdk/utils/ByteUtil.java @@ -53,17 +53,6 @@ public static byte[] bigIntegerToBytes(BigInteger b, int numBytes) { return bytes; } - public static byte[] bigIntegerToBytesSigned(BigInteger b, int numBytes) { - if (b == null) return null; - byte[] bytes = new byte[numBytes]; - Arrays.fill(bytes, b.signum() < 0 ? (byte) 0xFF : 0x00); - byte[] biBytes = b.toByteArray(); - int start = (biBytes.length == numBytes + 1) ? 1 : 0; - int length = Math.min(biBytes.length, numBytes); - System.arraycopy(biBytes, start, bytes, numBytes - length, length); - return bytes; - } - public static byte[] bigIntegerToBytes(BigInteger value) { if (value == null) return null; @@ -77,6 +66,17 @@ public static byte[] bigIntegerToBytes(BigInteger value) { return data; } + public static byte[] bigIntegerToBytesSigned(BigInteger b, int numBytes) { + if (b == null) return null; + byte[] bytes = new byte[numBytes]; + Arrays.fill(bytes, b.signum() < 0 ? (byte) 0xFF : 0x00); + byte[] biBytes = b.toByteArray(); + int start = (biBytes.length == numBytes + 1) ? 1 : 0; + int length = Math.min(biBytes.length, numBytes); + System.arraycopy(biBytes, start, bytes, numBytes - length, length); + return bytes; + } + /** * Cast hex encoded value from byte[] to BigInteger null is parsed like byte[0] * diff --git a/src/main/java/org/fisco/bcos/sdk/utils/NativeUtils.java b/src/main/java/org/fisco/bcos/sdk/utils/NativeUtils.java deleted file mode 100644 index 32d10921b..000000000 --- a/src/main/java/org/fisco/bcos/sdk/utils/NativeUtils.java +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright 2014-2020 [fisco-dev] - * - *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - *

http://www.apache.org/licenses/LICENSE-2.0 - * - *

Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.fisco.bcos.sdk.utils; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; - -public final class NativeUtils { - /** - * The minimum length a prefix for a file has to have according to {@link - * File#createTempFile(String, String)}}. - */ - private static final int MIN_PREFIX_LENGTH = 3; - - public static final String NATIVE_FOLDER_PATH_PREFIX = "nativeutils"; - - /** Temporary directory which will contain the .so file. */ - private static File temporaryDir; - - /** Private constructor - this class will never be instanced */ - private NativeUtils() {} - - /** - * The file from JAR is copied into system temporary directory and then loaded. The temporary - * file is deleted after exiting. - * - * @param path - * @throws IOException - * @throws FileNotFoundException - */ - public static synchronized void loadLibraryFromJar(String path) throws IOException { - - if (null == path || !path.startsWith("/")) { - throw new IllegalArgumentException("The path has to be absolute (start with '/')."); - } - - // Obtain filename from path - String[] parts = path.split("/"); - String filename = (parts.length > 1) ? parts[parts.length - 1] : null; - - if (filename == null || filename.length() < MIN_PREFIX_LENGTH) { - throw new IllegalArgumentException( - "The filename has to be at least 3 characters long."); - } - - // create temp file - if (temporaryDir == null) { - temporaryDir = createTempDirectory(NATIVE_FOLDER_PATH_PREFIX); - temporaryDir.deleteOnExit(); - } - File temp = new File(temporaryDir, filename); - - // copy file from jar package to temp directory - try (InputStream is = NativeUtils.class.getResourceAsStream(path)) { - Files.copy(is, temp.toPath(), StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - temp.delete(); - throw e; - } catch (NullPointerException e) { - temp.delete(); - throw new FileNotFoundException("File " + path + " was not found inside JAR."); - } - - // load the library - try { - System.load(temp.getAbsolutePath()); - } finally { - temp.deleteOnExit(); - } - } - - /** - * Prepare temporary file - * - * @param prefix - * @return - * @throws IOException - */ - private static File createTempDirectory(String prefix) throws IOException { - String tempDir = System.getProperty("java.io.tmpdir"); - File generatedDir = new File(tempDir, prefix + System.nanoTime()); - - if (!generatedDir.mkdir()) { - throw new IOException("Failed to create temp directory " + generatedDir.getName()); - } - return generatedDir; - } -} diff --git a/src/test/java/org/fisco/bcos/sdk/test/crypto/HashTest.java b/src/test/java/org/fisco/bcos/sdk/test/crypto/HashTest.java new file mode 100644 index 000000000..a10cfb4c2 --- /dev/null +++ b/src/test/java/org/fisco/bcos/sdk/test/crypto/HashTest.java @@ -0,0 +1,77 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.test.crypto; + +import org.fisco.bcos.sdk.crypto.hash.Hash; +import org.fisco.bcos.sdk.crypto.hash.Keccak256; +import org.fisco.bcos.sdk.crypto.hash.SM3Hash; +import org.fisco.bcos.sdk.utils.Hex; +import org.junit.Assert; +import org.junit.Test; + +public class HashTest { + @Test + public void testKeccak256() { + Hash hasher = new Keccak256(); + testKeccak256(hasher); + } + + @Test + public void testSM3() { + Hash sm3Hasher = new SM3Hash(); + testSM3(sm3Hasher); + } + + private void testKeccak256(Hash hasher) { + + // check keccak256 for "abcde" + checkHash( + hasher, + "abcde", + "6377c7e66081cb65e473c1b95db5195a27d04a7108b468890224bedbe1a8a6eb"); + + // check keccak256 for "hello" + checkHash( + hasher, + "hello", + "1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"); + + // check keccak256 for empty string + checkHash(hasher, "", "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); + } + + private void testSM3(Hash hasher) { + // check sm3 hash for "abcde" + checkHash( + hasher, + "abcde", + "afe4ccac5ab7d52bcae36373676215368baf52d3905e1fecbe369cc120e97628"); + + // check sm3 hash for "hello" + checkHash( + hasher, + "hello", + "becbbfaae6548b8bf0cfcad5a27183cd1be6093b1cceccc303d9c61d0a645268"); + + // check sm3 hash for empty string + checkHash(hasher, "", "1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b"); + } + + private void checkHash(Hash hasher, String message, String expectedHash) { + String calculatedHash = hasher.hash(message); + Assert.assertTrue(calculatedHash.equals(expectedHash)); + byte[] calculatedHashBytes = hasher.hash(message.getBytes()); + Assert.assertTrue(Hex.toHexString(calculatedHashBytes).equals(expectedHash)); + } +} diff --git a/src/test/java/org/fisco/bcos/sdk/test/crypto/SignatureTest.java b/src/test/java/org/fisco/bcos/sdk/test/crypto/SignatureTest.java new file mode 100644 index 000000000..cb67f18ce --- /dev/null +++ b/src/test/java/org/fisco/bcos/sdk/test/crypto/SignatureTest.java @@ -0,0 +1,80 @@ +/** + * Copyright 2014-2020 [fisco-dev] + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fisco.bcos.sdk.test.crypto; + +import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.crypto.keypair.ECDSAKeyPair; +import org.fisco.bcos.sdk.crypto.keypair.SM2KeyPair; +import org.fisco.bcos.sdk.crypto.signature.ECDSASignature; +import org.fisco.bcos.sdk.crypto.signature.SM2Signature; +import org.fisco.bcos.sdk.crypto.signature.Signature; +import org.fisco.bcos.sdk.crypto.signature.SignatureResult; +import org.junit.Assert; +import org.junit.Test; + +public class SignatureTest { + @Test + public void testECDSASignature() { + Signature ecdsaSignature = new ECDSASignature(); + CryptoKeyPair keyPair = (new ECDSAKeyPair()).generateKeyPair(); + testSignature(ecdsaSignature, keyPair); + } + + @Test + public void testSM2Signature() { + Signature sm2Signature = new SM2Signature(); + CryptoKeyPair keyPair = (new SM2KeyPair()).generateKeyPair(); + testSignature(sm2Signature, keyPair); + } + + private void testSignature(Signature signature, CryptoKeyPair keyPair) { + String message = "abcde"; + // check valid case + for (int i = 0; i < 10; i++) { + message = "abcd----" + Integer.toString(i); + // sign + SignatureResult signResult = signature.sign(message, keyPair); + // verify + Assert.assertTrue( + signature.verify( + keyPair.getHexPublicKey(), message, signResult.convertToString())); + signResult = signature.sign(message.getBytes(), keyPair); + Assert.assertTrue( + signature.verify( + keyPair.getHexPublicKey(), message, signResult.convertToString())); + } + + // check invalid case + for (int i = 0; i < 10; i++) { + message = "abcd----" + Integer.toString(i); + String invaidMessage = "abcd---" + Integer.toString(i + 1); + // sign + SignatureResult signResult = signature.sign(message, keyPair); + // verify + Assert.assertEquals( + false, + signature.verify( + keyPair.getHexPublicKey(), + invaidMessage, + signResult.convertToString())); + signResult = signature.sign(message.getBytes(), keyPair); + Assert.assertEquals( + false, + signature.verify( + keyPair.getHexPublicKey(), + invaidMessage, + signResult.convertToString())); + } + } +}