mirror of
https://github.com/corda/corda.git
synced 2025-02-04 10:11:14 +00:00
Support for multi-sig schemes. ECC (K1/R1) and EdDSA are fully supported. (#599)
Support for multi-sig scheme. ECC (K1/R1) and EdDSA are fully supported.
This commit is contained in:
parent
fe7d893de2
commit
d8fa75654f
@ -207,7 +207,7 @@ object JacksonSupport {
|
||||
|
||||
object PublicKeySerializer : JsonSerializer<EdDSAPublicKey>() {
|
||||
override fun serialize(obj: EdDSAPublicKey, generator: JsonGenerator, provider: SerializerProvider) {
|
||||
check(obj.params == ed25519Curve)
|
||||
check(obj.params == Crypto.EDDSA_ED25519_SHA512.algSpec)
|
||||
generator.writeString(obj.toBase58String())
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ class CompositeSignature : Signature(ALGORITHM) {
|
||||
val sig = sigBytes.deserialize<CompositeSignaturesWithKeys>()
|
||||
return if (verifyKey.isFulfilledBy(sig.sigs.map { it.by })) {
|
||||
val clearData = buffer.toByteArray()
|
||||
sig.sigs.all { it.isValidForECDSA(clearData) }
|
||||
sig.sigs.all { it.isValid(clearData) }
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import net.i2p.crypto.eddsa.EdDSAEngine
|
||||
import net.i2p.crypto.eddsa.EdDSAKey
|
||||
import net.i2p.crypto.eddsa.EdDSASecurityProvider
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable
|
||||
import org.bouncycastle.jce.ECNamedCurveTable
|
||||
import org.bouncycastle.jce.interfaces.ECKey
|
||||
@ -26,62 +28,61 @@ import java.security.spec.X509EncodedKeySpec
|
||||
* </ul>
|
||||
*/
|
||||
object Crypto {
|
||||
// This map is required to defend against users that forcibly call Security.addProvider / Security.removeProvider
|
||||
// that could cause unexpected and suspicious behaviour.
|
||||
// i.e. if someone removes a Provider and then he/she adds a new one with the same name.
|
||||
// The val is private to avoid any harmful state changes.
|
||||
private val providerMap = mapOf(
|
||||
EdDSASecurityProvider.PROVIDER_NAME to EdDSASecurityProvider(),
|
||||
BouncyCastleProvider.PROVIDER_NAME to BouncyCastleProvider(),
|
||||
"BCPQC" to BouncyCastlePQCProvider()) // unfortunately, provider's name is not final in BouncyCastlePQCProvider, so we explicitly set it.
|
||||
|
||||
init {
|
||||
Security.addProvider(I2PProvider()) // register I2P Crypto Provider, required for EdDSA.
|
||||
Security.addProvider(BouncyCastleProvider()) // register Bouncy Castle Crypto Provider (for RSA, ECDSA).
|
||||
Security.addProvider(BouncyCastlePQCProvider()) // register Bouncy Castle Post-Quantum Crypto Provider (for SPHINCS-256).
|
||||
}
|
||||
/**
|
||||
* RSA_SHA256 signature scheme using SHA256 as hash algorithm and MGF1 (with SHA256) as mask generation function.
|
||||
* Note: Recommended key size >= 3072 bits.
|
||||
*/
|
||||
private val RSA_SHA256 = SignatureScheme(
|
||||
val RSA_SHA256 = SignatureScheme(
|
||||
1,
|
||||
"RSA_SHA256",
|
||||
BouncyCastleProvider.PROVIDER_NAME,
|
||||
"RSA",
|
||||
Signature.getInstance("SHA256WITHRSAANDMGF1", "BC"),
|
||||
KeyFactory.getInstance("RSA", "BC"),
|
||||
KeyPairGenerator.getInstance("RSA", "BC"),
|
||||
"SHA256WITHRSAANDMGF1",
|
||||
null,
|
||||
3072,
|
||||
"RSA_SHA256 signature scheme using SHA256 as hash algorithm and MGF1 (with SHA256) as mask generation function."
|
||||
)
|
||||
|
||||
/** ECDSA signature scheme using the secp256k1 Koblitz curve. */
|
||||
private val ECDSA_SECP256K1_SHA256 = SignatureScheme(
|
||||
val ECDSA_SECP256K1_SHA256 = SignatureScheme(
|
||||
2,
|
||||
"ECDSA_SECP256K1_SHA256",
|
||||
BouncyCastleProvider.PROVIDER_NAME,
|
||||
"ECDSA",
|
||||
Signature.getInstance("SHA256withECDSA", "BC"),
|
||||
KeyFactory.getInstance("ECDSA", "BC"),
|
||||
KeyPairGenerator.getInstance("ECDSA", "BC"),
|
||||
"SHA256withECDSA",
|
||||
ECNamedCurveTable.getParameterSpec("secp256k1"),
|
||||
256,
|
||||
"ECDSA signature scheme using the secp256k1 Koblitz curve."
|
||||
)
|
||||
|
||||
/** ECDSA signature scheme using the secp256r1 (NIST P-256) curve. */
|
||||
private val ECDSA_SECP256R1_SHA256 = SignatureScheme(
|
||||
val ECDSA_SECP256R1_SHA256 = SignatureScheme(
|
||||
3,
|
||||
"ECDSA_SECP256R1_SHA256",
|
||||
BouncyCastleProvider.PROVIDER_NAME,
|
||||
"ECDSA",
|
||||
Signature.getInstance("SHA256withECDSA", "BC"),
|
||||
KeyFactory.getInstance("ECDSA", "BC"),
|
||||
KeyPairGenerator.getInstance("ECDSA", "BC"),
|
||||
"SHA256withECDSA",
|
||||
ECNamedCurveTable.getParameterSpec("secp256r1"),
|
||||
256,
|
||||
"ECDSA signature scheme using the secp256r1 (NIST P-256) curve."
|
||||
)
|
||||
|
||||
/** EdDSA signature scheme using the ed255519 twisted Edwards curve. */
|
||||
private val EDDSA_ED25519_SHA512 = SignatureScheme(
|
||||
val EDDSA_ED25519_SHA512 = SignatureScheme(
|
||||
4,
|
||||
"EDDSA_ED25519_SHA512",
|
||||
"EdDSA",
|
||||
Signature.getInstance("SHA512withEdDSA", "I2P"),
|
||||
KeyFactory.getInstance("EdDSA", "I2P"),
|
||||
KeyPairGenerator.getInstance("EdDSA", "I2P"),
|
||||
EdDSASecurityProvider.PROVIDER_NAME,
|
||||
EdDSAKey.KEY_ALGORITHM,
|
||||
EdDSAEngine.SIGNATURE_ALGORITHM,
|
||||
EdDSANamedCurveTable.getByName("ED25519"),
|
||||
256,
|
||||
"EdDSA signature scheme using the ed25519 twisted Edwards curve."
|
||||
@ -91,13 +92,12 @@ object Crypto {
|
||||
* SPHINCS-256 hash-based signature scheme. It provides 128bit security against post-quantum attackers
|
||||
* at the cost of larger key sizes and loss of compatibility.
|
||||
*/
|
||||
private val SPHINCS256_SHA256 = SignatureScheme(
|
||||
val SPHINCS256_SHA256 = SignatureScheme(
|
||||
5,
|
||||
"SPHINCS-256_SHA512",
|
||||
"SPHINCS-256",
|
||||
Signature.getInstance("SHA512WITHSPHINCS256", "BCPQC"),
|
||||
KeyFactory.getInstance("SPHINCS256", "BCPQC"),
|
||||
KeyPairGenerator.getInstance("SPHINCS256", "BCPQC"),
|
||||
"BCPQC",
|
||||
"SPHINCS256",
|
||||
"SHA512WITHSPHINCS256",
|
||||
SPHINCS256KeyGenParameterSpec(SPHINCS256KeyGenParameterSpec.SHA512_256),
|
||||
256,
|
||||
"SPHINCS-256 hash-based signature scheme. It provides 128bit security against post-quantum attackers " +
|
||||
@ -105,20 +105,19 @@ object Crypto {
|
||||
)
|
||||
|
||||
/** Our default signature scheme if no algorithm is specified (e.g. for key generation). */
|
||||
private val DEFAULT_SIGNATURE_SCHEME = EDDSA_ED25519_SHA512
|
||||
val DEFAULT_SIGNATURE_SCHEME = EDDSA_ED25519_SHA512
|
||||
|
||||
/**
|
||||
* Supported digital signature schemes.
|
||||
* Note: Only the schemes added in this map will be supported (see [Crypto]).
|
||||
* Do not forget to add the DEFAULT_SIGNATURE_SCHEME as well.
|
||||
*/
|
||||
private val supportedSignatureSchemes = mapOf(
|
||||
RSA_SHA256.schemeCodeName to RSA_SHA256,
|
||||
ECDSA_SECP256K1_SHA256.schemeCodeName to ECDSA_SECP256K1_SHA256,
|
||||
ECDSA_SECP256R1_SHA256.schemeCodeName to ECDSA_SECP256R1_SHA256,
|
||||
EDDSA_ED25519_SHA512.schemeCodeName to EDDSA_ED25519_SHA512,
|
||||
SPHINCS256_SHA256.schemeCodeName to SPHINCS256_SHA256
|
||||
)
|
||||
val supportedSignatureSchemes = listOf(
|
||||
RSA_SHA256,
|
||||
ECDSA_SECP256K1_SHA256,
|
||||
ECDSA_SECP256R1_SHA256,
|
||||
EDDSA_ED25519_SHA512,
|
||||
SPHINCS256_SHA256
|
||||
).associateBy { it.schemeCodeName }
|
||||
|
||||
/**
|
||||
* Factory pattern to retrieve the corresponding [SignatureScheme] based on the type of the [String] input.
|
||||
@ -128,17 +127,7 @@ object Crypto {
|
||||
* @return a currently supported SignatureScheme.
|
||||
* @throws IllegalArgumentException if the requested signature scheme is not supported.
|
||||
*/
|
||||
private fun findSignatureScheme(schemeCodeName: String): SignatureScheme = supportedSignatureSchemes[schemeCodeName] ?: throw IllegalArgumentException("Unsupported key/algorithm for metadata schemeCodeName: $schemeCodeName")
|
||||
|
||||
/**
|
||||
* Retrieve the corresponding [SignatureScheme] based on the type of the input [KeyPair].
|
||||
* Note that only the Corda platform standard schemes are supported (see [Crypto]).
|
||||
* This function is usually called when requiring to sign signatures.
|
||||
* @param keyPair a cryptographic [KeyPair].
|
||||
* @return a currently supported SignatureScheme or null.
|
||||
* @throws IllegalArgumentException if the requested signature scheme is not supported.
|
||||
*/
|
||||
private fun findSignatureScheme(keyPair: KeyPair): SignatureScheme = findSignatureScheme(keyPair.private)
|
||||
fun findSignatureScheme(schemeCodeName: String): SignatureScheme = supportedSignatureSchemes[schemeCodeName] ?: throw IllegalArgumentException("Unsupported key/algorithm for metadata schemeCodeName: $schemeCodeName")
|
||||
|
||||
/**
|
||||
* Retrieve the corresponding [SignatureScheme] based on the type of the input [Key].
|
||||
@ -150,9 +139,11 @@ object Crypto {
|
||||
* @return a currently supported SignatureScheme.
|
||||
* @throws IllegalArgumentException if the requested key type is not supported.
|
||||
*/
|
||||
private fun findSignatureScheme(key: Key): SignatureScheme {
|
||||
fun findSignatureScheme(key: Key): SignatureScheme {
|
||||
for (sig in supportedSignatureSchemes.values) {
|
||||
val algorithm = key.algorithm
|
||||
var algorithm = key.algorithm
|
||||
if (algorithm == "EC") algorithm = "ECDSA" // required to read ECC keys from Keystore, because encoding may change algorithm name from ECDSA to EC.
|
||||
if (algorithm == "SPHINCS-256") algorithm = "SPHINCS256" // because encoding may change algorithm name from SPHINCS256 to SPHINCS-256.
|
||||
if (algorithm == sig.algorithmName) {
|
||||
// If more than one ECDSA schemes are supported, we should distinguish between them by checking their curve parameters.
|
||||
// TODO: change 'continue' to 'break' if only one EdDSA curve will be used.
|
||||
@ -170,26 +161,18 @@ object Crypto {
|
||||
throw IllegalArgumentException("Unsupported key/algorithm for the private key: ${key.encoded.toBase58()}")
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the corresponding signature scheme code name based on the type of the input [Key].
|
||||
* See [Crypto] for the supported scheme code names.
|
||||
* @param key either private or public.
|
||||
* @return signatureSchemeCodeName for a [Key].
|
||||
* @throws IllegalArgumentException if the requested key type is not supported.
|
||||
*/
|
||||
fun findSignatureSchemeCodeName(key: Key): String = findSignatureScheme(key).schemeCodeName
|
||||
|
||||
/**
|
||||
* Decode a PKCS8 encoded key to its [PrivateKey] object.
|
||||
* Use this method if the key type is a-priori unknown.
|
||||
* @param encodedKey a PKCS8 encoded private key.
|
||||
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
||||
* is inappropriate for this key factory to produce a private key.
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class)
|
||||
fun decodePrivateKey(encodedKey: ByteArray): PrivateKey {
|
||||
for ((_, _, _, _, keyFactory) in supportedSignatureSchemes.values) {
|
||||
for ((_, _, providerName, algorithmName) in supportedSignatureSchemes.values) {
|
||||
try {
|
||||
return keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey))
|
||||
return KeyFactory.getInstance(algorithmName, providerMap[providerName]).generatePrivate(PKCS8EncodedKeySpec(encodedKey))
|
||||
} catch (ikse: InvalidKeySpecException) {
|
||||
// ignore it - only used to bypass the scheme that causes an exception.
|
||||
}
|
||||
@ -199,17 +182,27 @@ object Crypto {
|
||||
|
||||
/**
|
||||
* Decode a PKCS8 encoded key to its [PrivateKey] object based on the input scheme code name.
|
||||
* This will be used by Kryo deserialisation.
|
||||
* @param encodedKey a PKCS8 encoded private key.
|
||||
* This should be used when the type key is known, e.g. during Kryo deserialisation or with key caches or key managers.
|
||||
* @param schemeCodeName a [String] that should match a key in supportedSignatureSchemes map (e.g. ECDSA_SECP256K1_SHA256).
|
||||
* @param encodedKey a PKCS8 encoded private key.
|
||||
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
||||
* is inappropriate for this key factory to produce a private key.
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class, InvalidKeySpecException::class)
|
||||
fun decodePrivateKey(encodedKey: ByteArray, schemeCodeName: String): PrivateKey {
|
||||
val sig = findSignatureScheme(schemeCodeName)
|
||||
fun decodePrivateKey(schemeCodeName: String, encodedKey: ByteArray): PrivateKey = decodePrivateKey(findSignatureScheme(schemeCodeName), encodedKey)
|
||||
|
||||
/**
|
||||
* Decode a PKCS8 encoded key to its [PrivateKey] object based on the input scheme code name.
|
||||
* This should be used when the type key is known, e.g. during Kryo deserialisation or with key caches or key managers.
|
||||
* @param signatureScheme a signature scheme (e.g. ECDSA_SECP256K1_SHA256).
|
||||
* @param encodedKey a PKCS8 encoded private key.
|
||||
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
||||
* is inappropriate for this key factory to produce a private key.
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class, InvalidKeySpecException::class)
|
||||
fun decodePrivateKey(signatureScheme: SignatureScheme, encodedKey: ByteArray): PrivateKey {
|
||||
try {
|
||||
return sig.keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey))
|
||||
return KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName]).generatePrivate(PKCS8EncodedKeySpec(encodedKey))
|
||||
} catch (ikse: InvalidKeySpecException) {
|
||||
throw InvalidKeySpecException("This private key cannot be decoded, please ensure it is PKCS8 encoded and that it corresponds to the input scheme's code name.", ikse)
|
||||
}
|
||||
@ -217,16 +210,16 @@ object Crypto {
|
||||
|
||||
/**
|
||||
* Decode an X509 encoded key to its [PublicKey] object.
|
||||
* Use this method if the key type is a-priori unknown.
|
||||
* @param encodedKey an X509 encoded public key.
|
||||
* @throws UnsupportedSchemeException on not supported scheme.
|
||||
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
||||
* is inappropriate for this key factory to produce a private key.
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class)
|
||||
fun decodePublicKey(encodedKey: ByteArray): PublicKey {
|
||||
for ((_, _, _, _, keyFactory) in supportedSignatureSchemes.values) {
|
||||
for ((_, _, providerName, algorithmName) in supportedSignatureSchemes.values) {
|
||||
try {
|
||||
return keyFactory.generatePublic(X509EncodedKeySpec(encodedKey))
|
||||
return KeyFactory.getInstance(algorithmName, providerMap[providerName]).generatePublic(X509EncodedKeySpec(encodedKey))
|
||||
} catch (ikse: InvalidKeySpecException) {
|
||||
// ignore it - only used to bypass the scheme that causes an exception.
|
||||
}
|
||||
@ -236,39 +229,34 @@ object Crypto {
|
||||
|
||||
/**
|
||||
* Decode an X509 encoded key to its [PrivateKey] object based on the input scheme code name.
|
||||
* This will be used by Kryo deserialisation.
|
||||
* @param encodedKey an X509 encoded public key.
|
||||
* This should be used when the type key is known, e.g. during Kryo deserialisation or with key caches or key managers.
|
||||
* @param schemeCodeName a [String] that should match a key in supportedSignatureSchemes map (e.g. ECDSA_SECP256K1_SHA256).
|
||||
* @param encodedKey an X509 encoded public key.
|
||||
* @throws IllegalArgumentException if the requested scheme is not supported
|
||||
* @throws InvalidKeySpecException if the given key specification
|
||||
* is inappropriate for this key factory to produce a public key.
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class, InvalidKeySpecException::class)
|
||||
fun decodePublicKey(encodedKey: ByteArray, schemeCodeName: String): PublicKey {
|
||||
val sig = findSignatureScheme(schemeCodeName)
|
||||
fun decodePublicKey(schemeCodeName: String, encodedKey: ByteArray): PublicKey = decodePublicKey(findSignatureScheme(schemeCodeName), encodedKey)
|
||||
|
||||
/**
|
||||
* Decode an X509 encoded key to its [PrivateKey] object based on the input scheme code name.
|
||||
* This should be used when the type key is known, e.g. during Kryo deserialisation or with key caches or key managers.
|
||||
* @param signatureScheme a signature scheme (e.g. ECDSA_SECP256K1_SHA256).
|
||||
* @param encodedKey an X509 encoded public key.
|
||||
* @throws IllegalArgumentException if the requested scheme is not supported
|
||||
* @throws InvalidKeySpecException if the given key specification
|
||||
* is inappropriate for this key factory to produce a public key.
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class, InvalidKeySpecException::class)
|
||||
fun decodePublicKey(signatureScheme: SignatureScheme, encodedKey: ByteArray): PublicKey {
|
||||
try {
|
||||
return sig.keyFactory.generatePublic(X509EncodedKeySpec(encodedKey))
|
||||
return KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName]).generatePublic(X509EncodedKeySpec(encodedKey))
|
||||
} catch (ikse: InvalidKeySpecException) {
|
||||
throw throw InvalidKeySpecException("This public key cannot be decoded, please ensure it is X509 encoded and that it corresponds to the input scheme's code name.", ikse)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to simplify the act of generating keys.
|
||||
* Normally, we don't expect other errors here, assuming that key generation parameters for every supported signature scheme have been unit-tested.
|
||||
* @param schemeCodeName a signature scheme's code name (e.g. ECDSA_SECP256K1_SHA256).
|
||||
* @return a KeyPair for the requested scheme.
|
||||
* @throws IllegalArgumentException if the requested signature scheme is not supported.
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class)
|
||||
fun generateKeyPair(schemeCodeName: String): KeyPair = findSignatureScheme(schemeCodeName).keyPairGenerator.generateKeyPair()
|
||||
|
||||
/**
|
||||
* Generate a KeyPair using the default signature scheme.
|
||||
* @return a new KeyPair.
|
||||
*/
|
||||
fun generateKeyPair(): KeyPair = DEFAULT_SIGNATURE_SCHEME.keyPairGenerator.generateKeyPair()
|
||||
|
||||
/**
|
||||
* Generic way to sign [ByteArray] data with a [PrivateKey]. Strategy on on identifying the actual signing scheme is based
|
||||
* on the [PrivateKey] type, but if the schemeCodeName is known, then better use doSign(signatureScheme: String, privateKey: PrivateKey, clearData: ByteArray).
|
||||
@ -280,7 +268,7 @@ object Crypto {
|
||||
* @throws SignatureException if signing is not possible due to malformed data or private key.
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class, InvalidKeyException::class, SignatureException::class)
|
||||
fun doSign(privateKey: PrivateKey, clearData: ByteArray) = doSign(findSignatureScheme(privateKey).sig, privateKey, clearData)
|
||||
fun doSign(privateKey: PrivateKey, clearData: ByteArray) = doSign(findSignatureScheme(privateKey), privateKey, clearData)
|
||||
|
||||
/**
|
||||
* Generic way to sign [ByteArray] data with a [PrivateKey] and a known schemeCodeName [String].
|
||||
@ -293,11 +281,11 @@ object Crypto {
|
||||
* @throws SignatureException if signing is not possible due to malformed data or private key.
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class, InvalidKeyException::class, SignatureException::class)
|
||||
fun doSign(schemeCodeName: String, privateKey: PrivateKey, clearData: ByteArray) = doSign(findSignatureScheme(schemeCodeName).sig, privateKey, clearData)
|
||||
fun doSign(schemeCodeName: String, privateKey: PrivateKey, clearData: ByteArray) = doSign(findSignatureScheme(schemeCodeName), privateKey, clearData)
|
||||
|
||||
/**
|
||||
* Generic way to sign [ByteArray] data with a [PrivateKey] and a known [Signature].
|
||||
* @param signature a [Signature] object, retrieved from supported signature schemes, see [Crypto].
|
||||
* @param signatureScheme a [SignatureScheme] object, retrieved from supported signature schemes, see [Crypto].
|
||||
* @param privateKey the signer's [PrivateKey].
|
||||
* @param clearData the data/message to be signed in [ByteArray] form (usually the Merkle root).
|
||||
* @return the digital signature (in [ByteArray]) on the input message.
|
||||
@ -306,7 +294,10 @@ object Crypto {
|
||||
* @throws SignatureException if signing is not possible due to malformed data or private key.
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class, InvalidKeyException::class, SignatureException::class)
|
||||
private fun doSign(signature: Signature, privateKey: PrivateKey, clearData: ByteArray): ByteArray {
|
||||
fun doSign(signatureScheme: SignatureScheme, privateKey: PrivateKey, clearData: ByteArray): ByteArray {
|
||||
if (!supportedSignatureSchemes.containsKey(signatureScheme.schemeCodeName))
|
||||
throw IllegalArgumentException("Unsupported key/algorithm for schemeCodeName: $signatureScheme.schemeCodeName")
|
||||
val signature = Signature.getInstance(signatureScheme.signatureName, providerMap[signatureScheme.providerName])
|
||||
if (clearData.isEmpty()) throw Exception("Signing of an empty array is not permitted!")
|
||||
signature.initSign(privateKey)
|
||||
signature.update(clearData)
|
||||
@ -336,6 +327,7 @@ object Crypto {
|
||||
/**
|
||||
* Utility to simplify the act of verifying a digital signature.
|
||||
* It returns true if it succeeds, but it always throws an exception if verification fails.
|
||||
* @param schemeCodeName a signature scheme's code name (e.g. ECDSA_SECP256K1_SHA256).
|
||||
* @param publicKey the signer's [PublicKey].
|
||||
* @param signatureData the signatureData on a message.
|
||||
* @param clearData the clear data/message that was signed (usually the Merkle root).
|
||||
@ -347,7 +339,7 @@ object Crypto {
|
||||
* @throws IllegalArgumentException if the signature scheme is not supported or if any of the clear or signature data is empty.
|
||||
*/
|
||||
@Throws(InvalidKeyException::class, SignatureException::class, IllegalArgumentException::class)
|
||||
fun doVerify(schemeCodeName: String, publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray) = doVerify(findSignatureScheme(schemeCodeName).sig, publicKey, signatureData, clearData)
|
||||
fun doVerify(schemeCodeName: String, publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray) = doVerify(findSignatureScheme(schemeCodeName), publicKey, signatureData, clearData)
|
||||
|
||||
/**
|
||||
* Utility to simplify the act of verifying a digital signature by identifying the signature scheme used from the input public key's type.
|
||||
@ -365,12 +357,12 @@ object Crypto {
|
||||
* @throws IllegalArgumentException if the signature scheme is not supported or if any of the clear or signature data is empty.
|
||||
*/
|
||||
@Throws(InvalidKeyException::class, SignatureException::class, IllegalArgumentException::class)
|
||||
fun doVerify(publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray) = doVerify(findSignatureScheme(publicKey).sig, publicKey, signatureData, clearData)
|
||||
fun doVerify(publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray) = doVerify(findSignatureScheme(publicKey), publicKey, signatureData, clearData)
|
||||
|
||||
/**
|
||||
* Method to verify a digital signature.
|
||||
* It returns true if it succeeds, but it always throws an exception if verification fails.
|
||||
* @param signature a [Signature] object, retrieved from supported signature schemes, see [Crypto].
|
||||
* @param signatureScheme a [SignatureScheme] object, retrieved from supported signature schemes, see [Crypto].
|
||||
* @param publicKey the signer's [PublicKey].
|
||||
* @param signatureData the signatureData on a message.
|
||||
* @param clearData the clear data/message that was signed (usually the Merkle root).
|
||||
@ -379,14 +371,15 @@ object Crypto {
|
||||
* @throws SignatureException if this signatureData object is not initialized properly,
|
||||
* the passed-in signatureData is improperly encoded or of the wrong type,
|
||||
* if this signatureData scheme is unable to process the input data provided, if the verification is not possible.
|
||||
* @throws IllegalArgumentException if any of the clear or signature data is empty.
|
||||
* @throws IllegalArgumentException if the signature scheme is not supported or if any of the clear or signature data is empty.
|
||||
*/
|
||||
private fun doVerify(signature: Signature, publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray): Boolean {
|
||||
@Throws(InvalidKeyException::class, SignatureException::class, IllegalArgumentException::class)
|
||||
fun doVerify(signatureScheme: SignatureScheme, publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray): Boolean {
|
||||
if (!supportedSignatureSchemes.containsKey(signatureScheme.schemeCodeName))
|
||||
throw IllegalArgumentException("Unsupported key/algorithm for schemeCodeName: $signatureScheme.schemeCodeName")
|
||||
if (signatureData.isEmpty()) throw IllegalArgumentException("Signature data is empty!")
|
||||
if (clearData.isEmpty()) throw IllegalArgumentException("Clear data is empty, nothing to verify!")
|
||||
signature.initVerify(publicKey)
|
||||
signature.update(clearData)
|
||||
val verificationResult = signature.verify(signatureData)
|
||||
val verificationResult = isValid(signatureScheme, publicKey, signatureData, clearData)
|
||||
if (verificationResult) {
|
||||
return true
|
||||
} else {
|
||||
@ -413,15 +406,82 @@ object Crypto {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the requested signature scheme is supported by the system.
|
||||
* @param schemeCodeName a signature scheme's code name (e.g. ECDSA_SECP256K1_SHA256).
|
||||
* @return true if the signature scheme is supported.
|
||||
* Utility to simplify the act of verifying a digital signature by identifying the signature scheme used from the input public key's type.
|
||||
* It returns true if it succeeds and false if not. In comparison to [doVerify] if the key and signature
|
||||
* do not match it returns false rather than throwing an exception. Normally you should use the function which throws,
|
||||
* as it avoids the risk of failing to test the result.
|
||||
* Use this method if the signature scheme is not a-priori known.
|
||||
* @param publicKey the signer's [PublicKey].
|
||||
* @param signatureData the signatureData on a message.
|
||||
* @param clearData the clear data/message that was signed (usually the Merkle root).
|
||||
* @return true if verification passes or false if verification fails.
|
||||
* @throws SignatureException if this signatureData object is not initialized properly,
|
||||
* the passed-in signatureData is improperly encoded or of the wrong type,
|
||||
* if this signatureData scheme is unable to process the input data provided, if the verification is not possible.
|
||||
*/
|
||||
fun isSupportedSignatureScheme(schemeCodeName: String): Boolean = schemeCodeName in supportedSignatureSchemes
|
||||
@Throws(SignatureException::class)
|
||||
fun isValid(publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray) = isValid(findSignatureScheme(publicKey), publicKey, signatureData, clearData)
|
||||
|
||||
/** @return the default signature scheme's code name. */
|
||||
fun getDefaultSignatureSchemeCodeName(): String = DEFAULT_SIGNATURE_SCHEME.schemeCodeName
|
||||
|
||||
/** @return a [List] of Strings with the scheme code names defined in [SignatureScheme] for all of our supported signature schemes, see [Crypto]. */
|
||||
fun listSupportedSignatureSchemes(): List<String> = supportedSignatureSchemes.keys.toList()
|
||||
/**
|
||||
* Method to verify a digital signature. In comparison to [doVerify] if the key and signature
|
||||
* do not match it returns false rather than throwing an exception.
|
||||
* Use this method if the signature scheme type is a-priori unknown.
|
||||
* @param signatureScheme a [SignatureScheme] object, retrieved from supported signature schemes, see [Crypto].
|
||||
* @param publicKey the signer's [PublicKey].
|
||||
* @param signatureData the signatureData on a message.
|
||||
* @param clearData the clear data/message that was signed (usually the Merkle root).
|
||||
* @return true if verification passes or false if verification fails.
|
||||
* @throws SignatureException if this signatureData object is not initialized properly,
|
||||
* the passed-in signatureData is improperly encoded or of the wrong type,
|
||||
* if this signatureData scheme is unable to process the input data provided, if the verification is not possible.
|
||||
* @throws IllegalArgumentException if the requested signature scheme is not supported.
|
||||
*/
|
||||
@Throws(SignatureException::class, IllegalArgumentException::class)
|
||||
fun isValid(signatureScheme: SignatureScheme, publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray): Boolean {
|
||||
if (!supportedSignatureSchemes.containsKey(signatureScheme.schemeCodeName))
|
||||
throw IllegalArgumentException("Unsupported key/algorithm for schemeCodeName: $signatureScheme.schemeCodeName")
|
||||
val signature = Signature.getInstance(signatureScheme.signatureName, providerMap[signatureScheme.providerName])
|
||||
signature.initVerify(publicKey)
|
||||
signature.update(clearData)
|
||||
return signature.verify(signatureData)
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to simplify the act of generating keys.
|
||||
* Normally, we don't expect other errors here, assuming that key generation parameters for every supported signature scheme have been unit-tested.
|
||||
* @param schemeCodeName a signature scheme's code name (e.g. ECDSA_SECP256K1_SHA256).
|
||||
* @return a KeyPair for the requested signature scheme code name.
|
||||
* @throws IllegalArgumentException if the requested signature scheme is not supported.
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class)
|
||||
fun generateKeyPair(schemeCodeName: String): KeyPair = generateKeyPair(findSignatureScheme(schemeCodeName))
|
||||
|
||||
/**
|
||||
* Generate a [KeyPair] for the selected [SignatureScheme].
|
||||
* Note that RSA is the sole algorithm initialized specifically by its supported keySize.
|
||||
* @param signatureScheme a supported [SignatureScheme], see [Crypto].
|
||||
* @return a new [KeyPair] for the requested [SignatureScheme].
|
||||
* @throws IllegalArgumentException if the requested signature scheme is not supported.
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class)
|
||||
fun generateKeyPair(signatureScheme: SignatureScheme): KeyPair {
|
||||
if (!supportedSignatureSchemes.containsKey(signatureScheme.schemeCodeName))
|
||||
throw IllegalArgumentException("Unsupported key/algorithm for schemeCodeName: $signatureScheme.schemeCodeName")
|
||||
val keyPairGenerator = KeyPairGenerator.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName])
|
||||
if (signatureScheme.algSpec != null)
|
||||
keyPairGenerator.initialize(signatureScheme.algSpec, newSecureRandom())
|
||||
else
|
||||
keyPairGenerator.initialize(signatureScheme.keySize, newSecureRandom())
|
||||
return keyPairGenerator.generateKeyPair()
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a [KeyPair] using the default signature scheme.
|
||||
* @return a new [KeyPair].
|
||||
*/
|
||||
fun generateKeyPair(): KeyPair = generateKeyPair(DEFAULT_SIGNATURE_SCHEME)
|
||||
|
||||
/** Check if the requested signature scheme is supported by the system. */
|
||||
fun isSupportedSignatureScheme(schemeCodeName: String): Boolean = schemeCodeName in supportedSignatureSchemes
|
||||
fun isSupportedSignatureScheme(signatureScheme: SignatureScheme): Boolean = signatureScheme.schemeCodeName in supportedSignatureSchemes
|
||||
}
|
||||
|
@ -4,11 +4,8 @@ package net.corda.core.crypto
|
||||
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.OpaqueBytes
|
||||
import net.i2p.crypto.eddsa.EdDSAEngine
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey
|
||||
import net.i2p.crypto.eddsa.KeyPairGenerator
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec
|
||||
@ -40,34 +37,45 @@ class DummyPublicKey(val s: String) : PublicKey, Comparable<PublicKey> {
|
||||
@CordaSerializable
|
||||
object NullSignature : DigitalSignature.WithKey(NullPublicKey, ByteArray(32))
|
||||
|
||||
/** Utility to simplify the act of signing a byte array */
|
||||
fun PrivateKey.signWithECDSA(bytes: ByteArray): DigitalSignature {
|
||||
val signer = EdDSAEngine()
|
||||
signer.initSign(this)
|
||||
signer.update(bytes)
|
||||
val sig = signer.sign()
|
||||
return DigitalSignature(sig)
|
||||
/**
|
||||
* Utility to simplify the act of signing a byte array.
|
||||
* @param bytesToSign the data/message to be signed in [ByteArray] form (usually the Merkle root).
|
||||
* @return the [DigitalSignature] object on the input message.
|
||||
* @throws IllegalArgumentException if the signature scheme is not supported for this private key.
|
||||
* @throws InvalidKeyException if the private key is invalid.
|
||||
* @throws SignatureException if signing is not possible due to malformed data or private key.
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class, InvalidKeyException::class, SignatureException::class)
|
||||
fun PrivateKey.sign(bytesToSign: ByteArray): DigitalSignature {
|
||||
return DigitalSignature(Crypto.doSign(this, bytesToSign))
|
||||
}
|
||||
|
||||
fun PrivateKey.signWithECDSA(bytesToSign: ByteArray, publicKey: PublicKey): DigitalSignature.WithKey {
|
||||
return DigitalSignature.WithKey(publicKey, signWithECDSA(bytesToSign).bytes)
|
||||
fun PrivateKey.sign(bytesToSign: ByteArray, publicKey: PublicKey): DigitalSignature.WithKey {
|
||||
return DigitalSignature.WithKey(publicKey, this.sign(bytesToSign).bytes)
|
||||
}
|
||||
|
||||
val ed25519Curve: EdDSANamedCurveSpec = EdDSANamedCurveTable.getByName("ED25519")
|
||||
/**
|
||||
* Helper function to sign with a key pair.
|
||||
* @param bytesToSign the data/message to be signed in [ByteArray] form (usually the Merkle root).
|
||||
* @return the digital signature (in [ByteArray]) on the input message.
|
||||
* @throws IllegalArgumentException if the signature scheme is not supported for this private key.
|
||||
* @throws InvalidKeyException if the private key is invalid.
|
||||
* @throws SignatureException if signing is not possible due to malformed data or private key.
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class, InvalidKeyException::class, SignatureException::class)
|
||||
fun KeyPair.sign(bytesToSign: ByteArray) = private.sign(bytesToSign, public)
|
||||
fun KeyPair.sign(bytesToSign: OpaqueBytes) = private.sign(bytesToSign.bytes, public)
|
||||
fun KeyPair.sign(bytesToSign: OpaqueBytes, party: Party) = sign(bytesToSign.bytes, party)
|
||||
|
||||
fun KeyPair.signWithECDSA(bytesToSign: ByteArray) = private.signWithECDSA(bytesToSign, public)
|
||||
fun KeyPair.signWithECDSA(bytesToSign: OpaqueBytes) = private.signWithECDSA(bytesToSign.bytes, public)
|
||||
fun KeyPair.signWithECDSA(bytesToSign: OpaqueBytes, party: Party) = signWithECDSA(bytesToSign.bytes, party)
|
||||
// TODO This case will need more careful thinking, as party owningKey can be a CompositeKey. One way of doing that is
|
||||
// implementation of CompositeSignature.
|
||||
@Throws(InvalidKeyException::class)
|
||||
fun KeyPair.signWithECDSA(bytesToSign: ByteArray, party: Party): DigitalSignature.LegallyIdentifiable {
|
||||
val sig = signWithECDSA(bytesToSign)
|
||||
fun KeyPair.sign(bytesToSign: ByteArray, party: Party): DigitalSignature.LegallyIdentifiable {
|
||||
val sig = sign(bytesToSign)
|
||||
val sigKey = when (party.owningKey) { // Quick workaround when we have CompositeKey as Party owningKey.
|
||||
is CompositeKey -> throw InvalidKeyException("Signing for parties with CompositeKey not supported.")
|
||||
else -> party.owningKey
|
||||
}
|
||||
sigKey.verifyWithECDSA(bytesToSign, sig)
|
||||
return DigitalSignature.LegallyIdentifiable(party, sig.bytes)
|
||||
}
|
||||
|
||||
@ -77,18 +85,14 @@ fun KeyPair.signWithECDSA(bytesToSign: ByteArray, party: Party): DigitalSignatur
|
||||
* @throws InvalidKeyException if the key to verify the signature with is not valid (i.e. wrong key type for the
|
||||
* signature).
|
||||
* @throws SignatureException if the signature is invalid (i.e. damaged), or does not match the key (incorrect).
|
||||
* @throws IllegalArgumentException if the signature scheme is not supported or if any of the clear or signature data is empty.
|
||||
*/
|
||||
// TODO: SignatureException should be used only for a damaged signature, as per `java.security.Signature.verify()`,
|
||||
// we should use another exception (perhaps IllegalArgumentException) for indicating the signature is valid but does
|
||||
// not match.
|
||||
@Throws(IllegalStateException::class, SignatureException::class)
|
||||
fun PublicKey.verifyWithECDSA(content: ByteArray, signature: DigitalSignature) {
|
||||
if (!isValidForECDSA(content, signature))
|
||||
throw SignatureException("Signature did not match")
|
||||
}
|
||||
@Throws(SignatureException::class, IllegalArgumentException::class, InvalidKeyException::class)
|
||||
fun PublicKey.verify(content: ByteArray, signature: DigitalSignature) = Crypto.doVerify(this, signature.bytes, content)
|
||||
|
||||
/**
|
||||
* Utility to simplify the act of verifying a signature. In comparison to [verifyWithECDSA] if the key and signature
|
||||
* Utility to simplify the act of verifying a signature. In comparison to [verify] if the key and signature
|
||||
* do not match it returns false rather than throwing an exception. Normally you should use the function which throws,
|
||||
* as it avoids the risk of failing to test the result, but this is for uses such as [java.security.Signature.verify]
|
||||
* implementations.
|
||||
@ -96,18 +100,14 @@ fun PublicKey.verifyWithECDSA(content: ByteArray, signature: DigitalSignature) {
|
||||
* @throws InvalidKeyException if the key to verify the signature with is not valid (i.e. wrong key type for the
|
||||
* signature).
|
||||
* @throws SignatureException if the signature is invalid (i.e. damaged).
|
||||
* @throws IllegalArgumentException if the signature scheme is not supported or if any of the clear or signature data is empty.
|
||||
* @return whether the signature is correct for this key.
|
||||
*/
|
||||
@Throws(IllegalStateException::class, SignatureException::class)
|
||||
fun PublicKey.isValidForECDSA(content: ByteArray, signature: DigitalSignature) : Boolean {
|
||||
val pubKey = when (this) {
|
||||
is CompositeKey -> throw IllegalStateException("Verification of CompositeKey signatures currently not supported.") // TODO CompositeSignature verification.
|
||||
else -> this
|
||||
}
|
||||
val verifier = EdDSAEngine()
|
||||
verifier.initVerify(pubKey)
|
||||
verifier.update(content)
|
||||
return verifier.verify(signature.bytes)
|
||||
@Throws(IllegalStateException::class, SignatureException::class, IllegalArgumentException::class)
|
||||
fun PublicKey.isValid(content: ByteArray, signature: DigitalSignature) : Boolean {
|
||||
if (this is CompositeKey)
|
||||
throw IllegalStateException("Verification of CompositeKey signatures currently not supported.") // TODO CompositeSignature verification.
|
||||
return Crypto.isValid(this, signature.bytes, content)
|
||||
}
|
||||
|
||||
/** Render a public key to a string, using a short form if it's an elliptic curve public key */
|
||||
@ -148,27 +148,17 @@ fun generateKeyPair(): KeyPair = Crypto.generateKeyPair()
|
||||
/**
|
||||
* Returns a key pair derived from the given private key entropy. This is useful for unit tests and other cases where
|
||||
* you want hard-coded private keys.
|
||||
* This currently works for EdDSA ED25519 only.
|
||||
*/
|
||||
fun entropyToKeyPair(entropy: BigInteger): KeyPair {
|
||||
val params = ed25519Curve
|
||||
val params = EdDSANamedCurveTable.getByName("ED25519")
|
||||
val bytes = entropy.toByteArray().copyOf(params.curve.field.getb() / 8)
|
||||
val priv = EdDSAPrivateKeySpec(bytes, params)
|
||||
val pub = EdDSAPublicKeySpec(priv.a, params)
|
||||
val key = KeyPair(EdDSAPublicKey(pub), EdDSAPrivateKey(priv))
|
||||
return key
|
||||
val keyPair = KeyPair(EdDSAPublicKey(pub), EdDSAPrivateKey(priv))
|
||||
return keyPair
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for signing.
|
||||
* @param clearData the data/message to be signed in [ByteArray] form (usually the Merkle root).
|
||||
* @return the digital signature (in [ByteArray]) on the input message.
|
||||
* @throws IllegalArgumentException if the signature scheme is not supported for this private key.
|
||||
* @throws InvalidKeyException if the private key is invalid.
|
||||
* @throws SignatureException if signing is not possible due to malformed data or private key.
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class, InvalidKeyException::class, SignatureException::class)
|
||||
fun PrivateKey.sign(clearData: ByteArray): ByteArray = Crypto.doSign(this, clearData)
|
||||
|
||||
/**
|
||||
* Helper function for signing.
|
||||
* @param metaData tha attached MetaData object.
|
||||
@ -180,17 +170,6 @@ fun PrivateKey.sign(clearData: ByteArray): ByteArray = Crypto.doSign(this, clear
|
||||
@Throws(InvalidKeyException::class, SignatureException::class, IllegalArgumentException::class)
|
||||
fun PrivateKey.sign(metaData: MetaData): TransactionSignature = Crypto.doSign(this, metaData)
|
||||
|
||||
/**
|
||||
* Helper function to sign with a key pair.
|
||||
* @param clearData the data/message to be signed in [ByteArray] form (usually the Merkle root).
|
||||
* @return the digital signature (in [ByteArray]) on the input message.
|
||||
* @throws IllegalArgumentException if the signature scheme is not supported for this private key.
|
||||
* @throws InvalidKeyException if the private key is invalid.
|
||||
* @throws SignatureException if signing is not possible due to malformed data or private key.
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class, InvalidKeyException::class, SignatureException::class)
|
||||
fun KeyPair.sign(clearData: ByteArray): ByteArray = Crypto.doSign(this.private, clearData)
|
||||
|
||||
/**
|
||||
* Helper function to verify a signature.
|
||||
* @param signatureData the signature on a message.
|
||||
|
@ -22,7 +22,7 @@ open class DigitalSignature(bits: ByteArray) : OpaqueBytes(bits) {
|
||||
* @throws SignatureException if the signature is invalid (i.e. damaged), or does not match the key (incorrect).
|
||||
*/
|
||||
@Throws(InvalidKeyException::class, SignatureException::class)
|
||||
fun verifyWithECDSA(content: ByteArray) = by.verifyWithECDSA(content, this)
|
||||
fun verify(content: ByteArray) = by.verify(content, this)
|
||||
/**
|
||||
* Utility to simplify the act of verifying a signature.
|
||||
*
|
||||
@ -31,9 +31,9 @@ open class DigitalSignature(bits: ByteArray) : OpaqueBytes(bits) {
|
||||
* @throws SignatureException if the signature is invalid (i.e. damaged), or does not match the key (incorrect).
|
||||
*/
|
||||
@Throws(InvalidKeyException::class, SignatureException::class)
|
||||
fun verifyWithECDSA(content: OpaqueBytes) = by.verifyWithECDSA(content.bytes, this)
|
||||
fun verify(content: OpaqueBytes) = by.verify(content.bytes, this)
|
||||
/**
|
||||
* Utility to simplify the act of verifying a signature. In comparison to [verifyWithECDSA] doesn't throw an
|
||||
* Utility to simplify the act of verifying a signature. In comparison to [verify] doesn't throw an
|
||||
* exception, making it more suitable where a boolean is required, but normally you should use the function
|
||||
* which throws, as it avoids the risk of failing to test the result.
|
||||
*
|
||||
@ -43,7 +43,7 @@ open class DigitalSignature(bits: ByteArray) : OpaqueBytes(bits) {
|
||||
* @return whether the signature is correct for this key.
|
||||
*/
|
||||
@Throws(InvalidKeyException::class, SignatureException::class)
|
||||
fun isValidForECDSA(content: ByteArray) = by.isValidForECDSA(content, this)
|
||||
fun isValid(content: ByteArray) = by.isValid(content, this)
|
||||
}
|
||||
|
||||
// TODO: consider removing this as whoever needs to identify the signer should be able to derive it from the public key
|
||||
|
@ -1,34 +0,0 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import java.security.Provider
|
||||
|
||||
/**
|
||||
* A simple I2P [Provider] that supports the EdDSA signature scheme.
|
||||
*/
|
||||
class I2PProvider : Provider("I2P", 0.1, "I2P Security Provider v0.1, implementing I2P's EdDSA 25519.") {
|
||||
|
||||
init { setup() }
|
||||
|
||||
private fun setup() {
|
||||
// Key OID: 1.3.101.100; Sig OID: 1.3.101.101
|
||||
put("KeyFactory.EdDSA", "net.i2p.crypto.eddsa.KeyFactory")
|
||||
put("KeyPairGenerator.EdDSA", "net.i2p.crypto.eddsa.KeyPairGenerator")
|
||||
put("Signature.SHA512withEdDSA", "net.i2p.crypto.eddsa.EdDSAEngine")
|
||||
|
||||
// without these, Certificate.verify() fails.
|
||||
put("Alg.Alias.KeyFactory.1.3.101.100", "EdDSA")
|
||||
put("Alg.Alias.KeyFactory.OID.1.3.101.100", "EdDSA")
|
||||
|
||||
// Without these, keytool fails with:
|
||||
// keytool error: java.security.NoSuchAlgorithmException: unrecognized algorithm name: SHA512withEdDSA.
|
||||
put("Alg.Alias.KeyPairGenerator.1.3.101.100", "EdDSA")
|
||||
put("Alg.Alias.KeyPairGenerator.OID.1.3.101.100", "EdDSA")
|
||||
|
||||
// with this setting, keytool's keygen doesn't work.
|
||||
// java.security.cert.CertificateException: Signature algorithm mismatch.
|
||||
// It must match the key setting (1.3.101.100) to work,
|
||||
// but this works fine with programmatic cert generation.
|
||||
put("Alg.Alias.Signature.1.3.101.101", "SHA512withEdDSA")
|
||||
put("Alg.Alias.Signature.OID.1.3.101.101", "SHA512withEdDSA")
|
||||
}
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import java.security.KeyFactory
|
||||
import java.security.KeyPairGeneratorSpi
|
||||
import java.security.Signature
|
||||
import java.security.spec.AlgorithmParameterSpec
|
||||
|
||||
@ -9,12 +7,9 @@ import java.security.spec.AlgorithmParameterSpec
|
||||
* This class is used to define a digital signature scheme.
|
||||
* @param schemeNumberID we assign a number ID for more efficient on-wire serialisation. Please ensure uniqueness between schemes.
|
||||
* @param schemeCodeName code name for this signature scheme (e.g. RSA_SHA256, ECDSA_SECP256K1_SHA256, ECDSA_SECP256R1_SHA256, EDDSA_ED25519_SHA512, SPHINCS-256_SHA512).
|
||||
* @param providerName the provider's name (e.g. "BC").
|
||||
* @param algorithmName which signature algorithm is used (e.g. RSA, ECDSA. EdDSA, SPHINCS-256).
|
||||
* @param sig the [Signature] class that provides the functionality of a digital signature scheme.
|
||||
* eg. Signature.getInstance("SHA256withECDSA", "BC").
|
||||
* @param keyFactory the KeyFactory for this scheme (e.g. KeyFactory.getInstance("RSA", "BC")).
|
||||
* @param keyPairGenerator defines the <i>Service Provider Interface</i> (<b>SPI</b>) for the {@code KeyPairGenerator} class.
|
||||
* e.g. KeyPairGenerator.getInstance("ECDSA", "BC").
|
||||
* @param signatureName a signature-scheme name as required to create [Signature] objects (e.g. "SHA256withECDSA")
|
||||
* @param algSpec parameter specs for the underlying algorithm. Note that RSA is defined by the key size rather than algSpec.
|
||||
* eg. ECGenParameterSpec("secp256k1").
|
||||
* @param keySize the private key size (currently used for RSA only).
|
||||
@ -23,22 +18,9 @@ import java.security.spec.AlgorithmParameterSpec
|
||||
data class SignatureScheme(
|
||||
val schemeNumberID: Int,
|
||||
val schemeCodeName: String,
|
||||
val providerName: String,
|
||||
val algorithmName: String,
|
||||
val sig: Signature,
|
||||
val keyFactory: KeyFactory,
|
||||
val keyPairGenerator: KeyPairGeneratorSpi,
|
||||
val signatureName: String,
|
||||
val algSpec: AlgorithmParameterSpec?,
|
||||
val keySize: Int,
|
||||
val desc: String) {
|
||||
|
||||
/**
|
||||
* KeyPair generators are always initialized once we create them, as no re-initialization is required.
|
||||
* Note that RSA is the sole algorithm initialized specifically by its supported keySize.
|
||||
*/
|
||||
init {
|
||||
if (algSpec != null)
|
||||
keyPairGenerator.initialize(algSpec, newSecureRandom())
|
||||
else
|
||||
keyPairGenerator.initialize(keySize, newSecureRandom())
|
||||
}
|
||||
}
|
||||
val desc: String)
|
||||
|
@ -22,7 +22,7 @@ open class SignedData<T : Any>(val raw: SerializedBytes<T>, val sig: DigitalSign
|
||||
*/
|
||||
@Throws(SignatureException::class)
|
||||
fun verified(): T {
|
||||
sig.by.verifyWithECDSA(raw.bytes, sig)
|
||||
sig.by.verify(raw.bytes, sig)
|
||||
val data = raw.deserialize()
|
||||
verifyData(data)
|
||||
return data
|
||||
|
@ -18,6 +18,12 @@ import net.corda.core.utilities.NonEmptySetSerializer
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey
|
||||
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PrivateKey
|
||||
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PublicKey
|
||||
import org.objenesis.strategy.StdInstantiatorStrategy
|
||||
import org.slf4j.Logger
|
||||
import java.io.BufferedInputStream
|
||||
@ -93,6 +99,13 @@ object DefaultKryoCustomizer {
|
||||
|
||||
register(X500Name::class.java, X500NameSerializer)
|
||||
|
||||
register(BCECPrivateKey::class.java, PrivateKeySerializer)
|
||||
register(BCECPublicKey::class.java, PublicKeySerializer)
|
||||
register(BCRSAPrivateCrtKey::class.java, PrivateKeySerializer)
|
||||
register(BCRSAPublicKey::class.java, PublicKeySerializer)
|
||||
register(BCSphincs256PrivateKey::class.java, PrivateKeySerializer)
|
||||
register(BCSphincs256PublicKey::class.java, PublicKeySerializer)
|
||||
|
||||
val customization = KryoSerializationCustomization(this)
|
||||
pluginRegistries.forEach { it.customizeSerialization(customization) }
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import net.corda.core.node.AttachmentsClassLoader
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec
|
||||
import org.bouncycastle.asn1.ASN1InputStream
|
||||
@ -22,6 +23,7 @@ import java.io.*
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.security.PrivateKey
|
||||
import java.security.PublicKey
|
||||
import java.security.spec.InvalidKeySpecException
|
||||
import java.time.Instant
|
||||
@ -340,13 +342,13 @@ object WireTransactionSerializer : Serializer<WireTransaction>() {
|
||||
@ThreadSafe
|
||||
object Ed25519PrivateKeySerializer : Serializer<EdDSAPrivateKey>() {
|
||||
override fun write(kryo: Kryo, output: Output, obj: EdDSAPrivateKey) {
|
||||
check(obj.params == ed25519Curve)
|
||||
check(obj.params == Crypto.EDDSA_ED25519_SHA512.algSpec )
|
||||
output.writeBytesWithLength(obj.seed)
|
||||
}
|
||||
|
||||
override fun read(kryo: Kryo, input: Input, type: Class<EdDSAPrivateKey>): EdDSAPrivateKey {
|
||||
val seed = input.readBytesWithLength()
|
||||
return EdDSAPrivateKey(EdDSAPrivateKeySpec(seed, ed25519Curve))
|
||||
return EdDSAPrivateKey(EdDSAPrivateKeySpec(seed, Crypto.EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec))
|
||||
}
|
||||
}
|
||||
|
||||
@ -354,13 +356,13 @@ object Ed25519PrivateKeySerializer : Serializer<EdDSAPrivateKey>() {
|
||||
@ThreadSafe
|
||||
object Ed25519PublicKeySerializer : Serializer<EdDSAPublicKey>() {
|
||||
override fun write(kryo: Kryo, output: Output, obj: EdDSAPublicKey) {
|
||||
check(obj.params == ed25519Curve)
|
||||
check(obj.params == Crypto.EDDSA_ED25519_SHA512.algSpec)
|
||||
output.writeBytesWithLength(obj.abyte)
|
||||
}
|
||||
|
||||
override fun read(kryo: Kryo, input: Input, type: Class<EdDSAPublicKey>): EdDSAPublicKey {
|
||||
val A = input.readBytesWithLength()
|
||||
return EdDSAPublicKey(EdDSAPublicKeySpec(A, ed25519Curve))
|
||||
return EdDSAPublicKey(EdDSAPublicKeySpec(A, Crypto.EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec))
|
||||
}
|
||||
}
|
||||
|
||||
@ -382,6 +384,31 @@ object CompositeKeySerializer : Serializer<CompositeKey>() {
|
||||
}
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
object PrivateKeySerializer : Serializer<PrivateKey>() {
|
||||
override fun write(kryo: Kryo, output: Output, obj: PrivateKey) {
|
||||
output.writeBytesWithLength(obj.encoded)
|
||||
}
|
||||
|
||||
override fun read(kryo: Kryo, input: Input, type: Class<PrivateKey>): PrivateKey {
|
||||
val A = input.readBytesWithLength()
|
||||
return Crypto.decodePrivateKey(A)
|
||||
}
|
||||
}
|
||||
|
||||
/** For serialising a public key */
|
||||
@ThreadSafe
|
||||
object PublicKeySerializer : Serializer<PublicKey>() {
|
||||
override fun write(kryo: Kryo, output: Output, obj: PublicKey) {
|
||||
output.writeBytesWithLength(obj.encoded)
|
||||
}
|
||||
|
||||
override fun read(kryo: Kryo, input: Input, type: Class<PublicKey>): PublicKey {
|
||||
val A = input.readBytesWithLength()
|
||||
return Crypto.decodePublicKey(A)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for reading lists with number of elements at the beginning.
|
||||
* @param minLen minimum number of elements we expect for list to include, defaults to 1
|
||||
@ -525,7 +552,7 @@ object MetaDataSerializer : Serializer<MetaData>() {
|
||||
val visibleInputs = kryo.readClassAndObject(input) as BitSet?
|
||||
val signedInputs = kryo.readClassAndObject(input) as BitSet?
|
||||
val merkleRoot = input.readBytesWithLength()
|
||||
val publicKey = Crypto.decodePublicKey(input.readBytesWithLength(), schemeCodeName)
|
||||
val publicKey = Crypto.decodePublicKey(schemeCodeName, input.readBytesWithLength())
|
||||
return MetaData(schemeCodeName, versionID, signatureType, timestamp, visibleInputs, signedInputs, merkleRoot, publicKey)
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.isFulfilledBy
|
||||
import net.corda.core.crypto.signWithECDSA
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
import java.security.KeyPair
|
||||
@ -93,7 +93,7 @@ data class SignedTransaction(val txBits: SerializedBytes<WireTransaction>,
|
||||
@Throws(SignatureException::class)
|
||||
fun checkSignaturesAreValid() {
|
||||
for (sig in sigs) {
|
||||
sig.verifyWithECDSA(id.bytes)
|
||||
sig.verify(id.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,7 +153,7 @@ data class SignedTransaction(val txBits: SerializedBytes<WireTransaction>,
|
||||
*
|
||||
* @return a digital signature of the transaction.
|
||||
*/
|
||||
fun signWithECDSA(keyPair: KeyPair) = keyPair.signWithECDSA(this.id.bytes)
|
||||
fun signWithECDSA(keyPair: KeyPair) = keyPair.sign(this.id.bytes)
|
||||
|
||||
override fun toString(): String = "${javaClass.simpleName}(id=$id)"
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ open class TransactionBuilder(
|
||||
fun signWith(key: KeyPair): TransactionBuilder {
|
||||
check(currentSigs.none { it.by == key.public }) { "This partial transaction was already signed by ${key.public}" }
|
||||
val data = toWireTransaction().id
|
||||
addSignatureUnchecked(key.signWithECDSA(data.bytes))
|
||||
addSignatureUnchecked(key.sign(data.bytes))
|
||||
return this
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ open class TransactionBuilder(
|
||||
*/
|
||||
fun checkSignature(sig: DigitalSignature.WithKey) {
|
||||
require(commands.any { it.signers.any { sig.by in it.keys } }) { "Signature key doesn't match any command" }
|
||||
sig.verifyWithECDSA(toWireTransaction().id)
|
||||
sig.verify(toWireTransaction().id)
|
||||
}
|
||||
|
||||
/** Adds the signature directly to the transaction, without checking it for validity. */
|
||||
|
@ -98,7 +98,7 @@ abstract class AbstractStateReplacementFlow {
|
||||
val response = sendAndReceive<DigitalSignature.WithKey>(party, proposal)
|
||||
return response.unwrap {
|
||||
check(party.owningKey.isFulfilledBy(it.by)) { "Not signed by the required participant" }
|
||||
it.verifyWithECDSA(stx.id)
|
||||
it.verify(stx.id)
|
||||
it
|
||||
}
|
||||
}
|
||||
@ -157,7 +157,7 @@ abstract class AbstractStateReplacementFlow {
|
||||
|
||||
// TODO: This step should not be necessary, as signatures are re-checked in verifySignatures.
|
||||
val allSignatures = swapSignatures.unwrap { signatures ->
|
||||
signatures.forEach { it.verifyWithECDSA(stx.id) }
|
||||
signatures.forEach { it.verify(stx.id) }
|
||||
signatures
|
||||
}
|
||||
|
||||
@ -187,7 +187,7 @@ abstract class AbstractStateReplacementFlow {
|
||||
|
||||
private fun sign(stx: SignedTransaction): DigitalSignature.WithKey {
|
||||
val myKey = serviceHub.legalIdentityKey
|
||||
return myKey.signWithECDSA(stx.id)
|
||||
return myKey.sign(stx.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ object NotaryFlow {
|
||||
|
||||
private fun validateSignature(sig: DigitalSignature.WithKey, data: ByteArray) {
|
||||
check(sig.by in notaryParty.owningKey.keys) { "Invalid signer for the notary result" }
|
||||
sig.verifyWithECDSA(data)
|
||||
sig.verify(data)
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,7 +142,7 @@ object NotaryFlow {
|
||||
|
||||
private fun sign(bits: ByteArray): DigitalSignature.WithKey {
|
||||
val mySigningKey = serviceHub.notaryIdentityKey
|
||||
return mySigningKey.signWithECDSA(bits)
|
||||
return mySigningKey.sign(bits)
|
||||
}
|
||||
|
||||
private fun notaryException(txId: SecureHash, e: UniquenessException): NotaryException {
|
||||
|
@ -144,7 +144,7 @@ object TwoPartyDealFlow {
|
||||
|
||||
open fun computeOurSignature(partialTX: SignedTransaction): DigitalSignature.WithKey {
|
||||
progressTracker.currentStep = SIGNING
|
||||
return myKeyPair.signWithECDSA(partialTX.id)
|
||||
return myKeyPair.sign(partialTX.id)
|
||||
}
|
||||
|
||||
@Suspendable
|
||||
|
@ -5,7 +5,7 @@ import net.corda.core.crypto.CompositeKey
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.crypto.signWithECDSA
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
import net.corda.core.transactions.LedgerTransaction
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
@ -26,7 +26,7 @@ class TransactionTests {
|
||||
|
||||
private fun makeSigned(wtx: WireTransaction, vararg keys: KeyPair): SignedTransaction {
|
||||
val bytes: SerializedBytes<WireTransaction> = wtx.serialized
|
||||
return SignedTransaction(bytes, keys.map { it.signWithECDSA(wtx.id.bytes) })
|
||||
return SignedTransaction(bytes, keys.map { it.sign(wtx.id.bytes) })
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -4,7 +4,6 @@ import net.corda.core.serialization.OpaqueBytes
|
||||
import net.corda.core.serialization.serialize
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@ -19,9 +18,9 @@ class CompositeKeyTests {
|
||||
|
||||
val message = OpaqueBytes("Transaction".toByteArray())
|
||||
|
||||
val aliceSignature = aliceKey.signWithECDSA(message)
|
||||
val bobSignature = bobKey.signWithECDSA(message)
|
||||
val charlieSignature = charlieKey.signWithECDSA(message)
|
||||
val aliceSignature = aliceKey.sign(message)
|
||||
val bobSignature = bobKey.sign(message)
|
||||
val charlieSignature = charlieKey.sign(message)
|
||||
val compositeAliceSignature = CompositeSignaturesWithKeys(listOf(aliceSignature))
|
||||
|
||||
@Test
|
||||
|
@ -11,9 +11,6 @@ import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PrivateKey
|
||||
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PublicKey
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Test
|
||||
import java.security.KeyFactory
|
||||
import java.security.spec.PKCS8EncodedKeySpec
|
||||
import java.security.spec.X509EncodedKeySpec
|
||||
import java.util.*
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
@ -32,11 +29,11 @@ class CryptoUtilsTest {
|
||||
@Test
|
||||
fun `Generate key pairs`() {
|
||||
// testing supported algorithms
|
||||
val rsaKeyPair = Crypto.generateKeyPair("RSA_SHA256")
|
||||
val ecdsaKKeyPair = Crypto.generateKeyPair("ECDSA_SECP256K1_SHA256")
|
||||
val ecdsaRKeyPair = Crypto.generateKeyPair("ECDSA_SECP256R1_SHA256")
|
||||
val eddsaKeyPair = Crypto.generateKeyPair("EDDSA_ED25519_SHA512")
|
||||
val sphincsKeyPair = Crypto.generateKeyPair("SPHINCS-256_SHA512")
|
||||
val rsaKeyPair = Crypto.generateKeyPair(Crypto.RSA_SHA256)
|
||||
val ecdsaKKeyPair = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
|
||||
val ecdsaRKeyPair = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256)
|
||||
val eddsaKeyPair = Crypto.generateKeyPair(Crypto.EDDSA_ED25519_SHA512)
|
||||
val sphincsKeyPair = Crypto.generateKeyPair(Crypto.SPHINCS256_SHA256)
|
||||
|
||||
// not null private keys
|
||||
assertNotNull(rsaKeyPair.private)
|
||||
@ -65,17 +62,16 @@ class CryptoUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `RSA full process keygen-sign-verify`() {
|
||||
|
||||
val keyPair = Crypto.generateKeyPair("RSA_SHA256")
|
||||
|
||||
val keyPair = Crypto.generateKeyPair(Crypto.RSA_SHA256)
|
||||
val (privKey, pubKey) = keyPair
|
||||
// test for some data
|
||||
val signedData = keyPair.sign(testBytes)
|
||||
val verification = keyPair.verify(signedData, testBytes)
|
||||
val signedData = Crypto.doSign(privKey, testBytes)
|
||||
val verification = Crypto.doVerify(pubKey, signedData, testBytes)
|
||||
assertTrue(verification)
|
||||
|
||||
// test for empty data signing
|
||||
try {
|
||||
keyPair.sign(ByteArray(0))
|
||||
Crypto.doSign(privKey, ByteArray(0))
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
@ -83,7 +79,7 @@ class CryptoUtilsTest {
|
||||
|
||||
// test for empty source data when verifying
|
||||
try {
|
||||
keyPair.verify(testBytes, ByteArray(0))
|
||||
Crypto.doVerify(pubKey, testBytes, ByteArray(0))
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
@ -91,88 +87,83 @@ class CryptoUtilsTest {
|
||||
|
||||
// test for empty signed data when verifying
|
||||
try {
|
||||
keyPair.verify(ByteArray(0), testBytes)
|
||||
Crypto.doVerify(pubKey, ByteArray(0), testBytes)
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// test for zero bytes data
|
||||
val signedDataZeros = keyPair.sign(ByteArray(100))
|
||||
val verificationZeros = keyPair.verify(signedDataZeros, ByteArray(100))
|
||||
val signedDataZeros = Crypto.doSign(privKey, ByteArray(100))
|
||||
val verificationZeros = Crypto.doVerify(pubKey, signedDataZeros, ByteArray(100))
|
||||
assertTrue(verificationZeros)
|
||||
|
||||
// test for 1MB of data (I successfully tested it locally for 1GB as well)
|
||||
val MBbyte = ByteArray(1000000) // 1.000.000
|
||||
Random().nextBytes(MBbyte)
|
||||
val signedDataBig = keyPair.sign(MBbyte)
|
||||
val verificationBig = keyPair.verify(signedDataBig, MBbyte)
|
||||
assertTrue(verificationBig)
|
||||
|
||||
// test on malformed signatures (even if they change for 1 bit)
|
||||
for (i in 0..signedData.size - 1) {
|
||||
val b = signedData[i]
|
||||
signedData[i] = b.inc()
|
||||
try {
|
||||
keyPair.verify(signedData, testBytes)
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
}
|
||||
signedData[i] = b.dec()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ECDSA secp256k1 full process keygen-sign-verify`() {
|
||||
|
||||
val keyPair = Crypto.generateKeyPair("ECDSA_SECP256K1_SHA256")
|
||||
|
||||
// test for some data
|
||||
val signedData = keyPair.sign(testBytes)
|
||||
val verification = keyPair.verify(signedData, testBytes)
|
||||
assertTrue(verification)
|
||||
|
||||
// test for empty data signing
|
||||
try {
|
||||
keyPair.sign(ByteArray(0))
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// test for empty source data when verifying
|
||||
try {
|
||||
keyPair.verify(testBytes, ByteArray(0))
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// test for empty signed data when verifying
|
||||
try {
|
||||
keyPair.verify(ByteArray(0), testBytes)
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// test for zero bytes data
|
||||
val signedDataZeros = keyPair.sign(ByteArray(100))
|
||||
val verificationZeros = keyPair.verify(signedDataZeros, ByteArray(100))
|
||||
assertTrue(verificationZeros)
|
||||
|
||||
// test for 1MB of data (I successfully tested it locally for 1GB as well)
|
||||
val MBbyte = ByteArray(1000000) // 1.000.000
|
||||
Random().nextBytes(MBbyte)
|
||||
val signedDataBig = keyPair.sign(MBbyte)
|
||||
val verificationBig = keyPair.verify(signedDataBig, MBbyte)
|
||||
val signedDataBig = Crypto.doSign(privKey, MBbyte)
|
||||
val verificationBig = Crypto.doVerify(pubKey, signedDataBig, MBbyte)
|
||||
assertTrue(verificationBig)
|
||||
|
||||
// test on malformed signatures (even if they change for 1 bit)
|
||||
signedData[0] = signedData[0].inc()
|
||||
try {
|
||||
keyPair.verify(signedData, testBytes)
|
||||
Crypto.doVerify(pubKey, signedData, testBytes)
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ECDSA secp256k1 full process keygen-sign-verify`() {
|
||||
val keyPair = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
|
||||
val (privKey, pubKey) = keyPair
|
||||
// test for some data
|
||||
val signedData = Crypto.doSign(privKey, testBytes)
|
||||
val verification = Crypto.doVerify(pubKey, signedData, testBytes)
|
||||
assertTrue(verification)
|
||||
|
||||
// test for empty data signing
|
||||
try {
|
||||
Crypto.doSign(privKey, ByteArray(0))
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// test for empty source data when verifying
|
||||
try {
|
||||
Crypto.doVerify(pubKey, testBytes, ByteArray(0))
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// test for empty signed data when verifying
|
||||
try {
|
||||
Crypto.doVerify(pubKey, ByteArray(0), testBytes)
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// test for zero bytes data
|
||||
val signedDataZeros = Crypto.doSign(privKey, ByteArray(100))
|
||||
val verificationZeros = Crypto.doVerify(pubKey, signedDataZeros, ByteArray(100))
|
||||
assertTrue(verificationZeros)
|
||||
|
||||
// test for 1MB of data (I successfully tested it locally for 1GB as well)
|
||||
val MBbyte = ByteArray(1000000) // 1.000.000
|
||||
Random().nextBytes(MBbyte)
|
||||
val signedDataBig = Crypto.doSign(privKey, MBbyte)
|
||||
val verificationBig = Crypto.doVerify(pubKey, signedDataBig, MBbyte)
|
||||
assertTrue(verificationBig)
|
||||
|
||||
// test on malformed signatures (even if they change for 1 bit)
|
||||
signedData[0] = signedData[0].inc()
|
||||
try {
|
||||
Crypto.doVerify(pubKey, signedData, testBytes)
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
@ -181,17 +172,16 @@ class CryptoUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `ECDSA secp256r1 full process keygen-sign-verify`() {
|
||||
|
||||
val keyPair = Crypto.generateKeyPair("ECDSA_SECP256R1_SHA256")
|
||||
|
||||
val keyPair = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256)
|
||||
val (privKey, pubKey) = keyPair
|
||||
// test for some data
|
||||
val signedData = keyPair.sign(testBytes)
|
||||
val verification = keyPair.verify(signedData, testBytes)
|
||||
val signedData = Crypto.doSign(privKey, testBytes)
|
||||
val verification = Crypto.doVerify(pubKey, signedData, testBytes)
|
||||
assertTrue(verification)
|
||||
|
||||
// test for empty data signing
|
||||
try {
|
||||
keyPair.sign(ByteArray(0))
|
||||
Crypto.doSign(privKey, ByteArray(0))
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
@ -199,7 +189,7 @@ class CryptoUtilsTest {
|
||||
|
||||
// test for empty source data when verifying
|
||||
try {
|
||||
keyPair.verify(testBytes, ByteArray(0))
|
||||
Crypto.doVerify(pubKey, testBytes, ByteArray(0))
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
@ -207,28 +197,28 @@ class CryptoUtilsTest {
|
||||
|
||||
// test for empty signed data when verifying
|
||||
try {
|
||||
keyPair.verify(ByteArray(0), testBytes)
|
||||
Crypto.doVerify(pubKey, ByteArray(0), testBytes)
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// test for zero bytes data
|
||||
val signedDataZeros = keyPair.sign(ByteArray(100))
|
||||
val verificationZeros = keyPair.verify(signedDataZeros, ByteArray(100))
|
||||
val signedDataZeros = Crypto.doSign(privKey, ByteArray(100))
|
||||
val verificationZeros = Crypto.doVerify(pubKey, signedDataZeros, ByteArray(100))
|
||||
assertTrue(verificationZeros)
|
||||
|
||||
// test for 1MB of data (I successfully tested it locally for 1GB as well)
|
||||
val MBbyte = ByteArray(1000000) // 1.000.000
|
||||
Random().nextBytes(MBbyte)
|
||||
val signedDataBig = keyPair.sign(MBbyte)
|
||||
val verificationBig = keyPair.verify(signedDataBig, MBbyte)
|
||||
val signedDataBig = Crypto.doSign(privKey, MBbyte)
|
||||
val verificationBig = Crypto.doVerify(pubKey, signedDataBig, MBbyte)
|
||||
assertTrue(verificationBig)
|
||||
|
||||
// test on malformed signatures (even if they change for 1 bit)
|
||||
signedData[0] = signedData[0].inc()
|
||||
try {
|
||||
keyPair.verify(signedData, testBytes)
|
||||
Crypto.doVerify(pubKey, signedData, testBytes)
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
@ -237,17 +227,16 @@ class CryptoUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `EDDSA ed25519 full process keygen-sign-verify`() {
|
||||
|
||||
val keyPair = Crypto.generateKeyPair("EDDSA_ED25519_SHA512")
|
||||
|
||||
val keyPair = Crypto.generateKeyPair(Crypto.EDDSA_ED25519_SHA512)
|
||||
val (privKey, pubKey) = keyPair
|
||||
// test for some data
|
||||
val signedData = keyPair.sign(testBytes)
|
||||
val verification = keyPair.verify(signedData, testBytes)
|
||||
val signedData = Crypto.doSign(privKey, testBytes)
|
||||
val verification = Crypto.doVerify(pubKey, signedData, testBytes)
|
||||
assertTrue(verification)
|
||||
|
||||
// test for empty data signing
|
||||
try {
|
||||
keyPair.sign(ByteArray(0))
|
||||
Crypto.doSign(privKey, ByteArray(0))
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
@ -255,7 +244,7 @@ class CryptoUtilsTest {
|
||||
|
||||
// test for empty source data when verifying
|
||||
try {
|
||||
keyPair.verify(testBytes, ByteArray(0))
|
||||
Crypto.doVerify(pubKey, testBytes, ByteArray(0))
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
@ -263,28 +252,28 @@ class CryptoUtilsTest {
|
||||
|
||||
// test for empty signed data when verifying
|
||||
try {
|
||||
keyPair.verify(ByteArray(0), testBytes)
|
||||
Crypto.doVerify(pubKey, ByteArray(0), testBytes)
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// test for zero bytes data
|
||||
val signedDataZeros = keyPair.sign(ByteArray(100))
|
||||
val verificationZeros = keyPair.verify(signedDataZeros, ByteArray(100))
|
||||
val signedDataZeros = Crypto.doSign(privKey, ByteArray(100))
|
||||
val verificationZeros = Crypto.doVerify(pubKey, signedDataZeros, ByteArray(100))
|
||||
assertTrue(verificationZeros)
|
||||
|
||||
// test for 1MB of data (I successfully tested it locally for 1GB as well)
|
||||
val MBbyte = ByteArray(1000000) // 1.000.000
|
||||
Random().nextBytes(MBbyte)
|
||||
val signedDataBig = keyPair.sign(MBbyte)
|
||||
val verificationBig = keyPair.verify(signedDataBig, MBbyte)
|
||||
val signedDataBig = Crypto.doSign(privKey, MBbyte)
|
||||
val verificationBig = Crypto.doVerify(pubKey, signedDataBig, MBbyte)
|
||||
assertTrue(verificationBig)
|
||||
|
||||
// test on malformed signatures (even if they change for 1 bit)
|
||||
signedData[0] = signedData[0].inc()
|
||||
try {
|
||||
keyPair.verify(signedData, testBytes)
|
||||
Crypto.doVerify(pubKey, signedData, testBytes)
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
@ -293,17 +282,16 @@ class CryptoUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `SPHINCS-256 full process keygen-sign-verify`() {
|
||||
|
||||
val keyPair = Crypto.generateKeyPair("SPHINCS-256_SHA512")
|
||||
|
||||
val keyPair = Crypto.generateKeyPair(Crypto.SPHINCS256_SHA256)
|
||||
val (privKey, pubKey) = keyPair
|
||||
// test for some data
|
||||
val signedData = keyPair.sign(testBytes)
|
||||
val verification = keyPair.verify(signedData, testBytes)
|
||||
val signedData = Crypto.doSign(privKey, testBytes)
|
||||
val verification = Crypto.doVerify(pubKey, signedData, testBytes)
|
||||
assertTrue(verification)
|
||||
|
||||
// test for empty data signing
|
||||
try {
|
||||
keyPair.sign(ByteArray(0))
|
||||
Crypto.doSign(privKey, ByteArray(0))
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
@ -311,7 +299,7 @@ class CryptoUtilsTest {
|
||||
|
||||
// test for empty source data when verifying
|
||||
try {
|
||||
keyPair.verify(testBytes, ByteArray(0))
|
||||
Crypto.doVerify(pubKey, testBytes, ByteArray(0))
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
@ -319,28 +307,28 @@ class CryptoUtilsTest {
|
||||
|
||||
// test for empty signed data when verifying
|
||||
try {
|
||||
keyPair.verify(ByteArray(0), testBytes)
|
||||
Crypto.doVerify(pubKey, ByteArray(0), testBytes)
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// test for zero bytes data
|
||||
val signedDataZeros = keyPair.sign(ByteArray(100))
|
||||
val verificationZeros = keyPair.verify(signedDataZeros, ByteArray(100))
|
||||
val signedDataZeros = Crypto.doSign(privKey, ByteArray(100))
|
||||
val verificationZeros = Crypto.doVerify(pubKey, signedDataZeros, ByteArray(100))
|
||||
assertTrue(verificationZeros)
|
||||
|
||||
// test for 1MB of data (I successfully tested it locally for 1GB as well)
|
||||
val MBbyte = ByteArray(1000000) // 1.000.000
|
||||
Random().nextBytes(MBbyte)
|
||||
val signedDataBig = keyPair.sign(MBbyte)
|
||||
val verificationBig = keyPair.verify(signedDataBig, MBbyte)
|
||||
val signedDataBig = Crypto.doSign(privKey, MBbyte)
|
||||
val verificationBig = Crypto.doVerify(pubKey, signedDataBig, MBbyte)
|
||||
assertTrue(verificationBig)
|
||||
|
||||
// test on malformed signatures (even if they change for 1 bit)
|
||||
signedData[0] = signedData[0].inc()
|
||||
try {
|
||||
keyPair.verify(signedData, testBytes)
|
||||
Crypto.doVerify(pubKey, signedData, testBytes)
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
@ -350,7 +338,7 @@ class CryptoUtilsTest {
|
||||
// test list of supported algorithms
|
||||
@Test
|
||||
fun `Check supported algorithms`() {
|
||||
val algList: List<String> = Crypto.listSupportedSignatureSchemes()
|
||||
val algList: List<String> = Crypto.supportedSignatureSchemes.keys.toList()
|
||||
val expectedAlgSet = setOf("RSA_SHA256", "ECDSA_SECP256K1_SHA256", "ECDSA_SECP256R1_SHA256", "EDDSA_ED25519_SHA512", "SPHINCS-256_SHA512")
|
||||
assertTrue { Sets.symmetricDifference(expectedAlgSet, algList.toSet()).isEmpty(); }
|
||||
}
|
||||
@ -359,88 +347,76 @@ class CryptoUtilsTest {
|
||||
@Test
|
||||
fun `RSA encode decode keys - required for serialization`() {
|
||||
// Generate key pair.
|
||||
val keyPair = Crypto.generateKeyPair("RSA_SHA256")
|
||||
val keyPair = Crypto.generateKeyPair(Crypto.RSA_SHA256)
|
||||
val (privKey, pubKey) = keyPair
|
||||
|
||||
val keyFactory = KeyFactory.getInstance("RSA", "BC")
|
||||
|
||||
// Encode and decode private key.
|
||||
val privKey2 = keyFactory.generatePrivate(PKCS8EncodedKeySpec(privKey.encoded))
|
||||
val privKey2 = Crypto.decodePrivateKey(privKey.encoded)
|
||||
assertEquals(privKey2, privKey)
|
||||
|
||||
// Encode and decode public key.
|
||||
val pubKey2 = keyFactory.generatePublic(X509EncodedKeySpec(pubKey.encoded))
|
||||
val pubKey2 = Crypto.decodePublicKey(pubKey.encoded)
|
||||
assertEquals(pubKey2, pubKey)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ECDSA secp256k1 encode decode keys - required for serialization`() {
|
||||
// Generate key pair.
|
||||
val keyPair = Crypto.generateKeyPair("ECDSA_SECP256K1_SHA256")
|
||||
val keyPair = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
|
||||
val (privKey, pubKey) = keyPair
|
||||
|
||||
val kf = KeyFactory.getInstance("ECDSA", "BC")
|
||||
|
||||
// Encode and decode private key.
|
||||
val privKey2 = kf.generatePrivate(PKCS8EncodedKeySpec(privKey.encoded))
|
||||
val privKey2 = Crypto.decodePrivateKey(privKey.encoded)
|
||||
assertEquals(privKey2, privKey)
|
||||
|
||||
// Encode and decode public key.
|
||||
val pubKey2 = kf.generatePublic(X509EncodedKeySpec(pubKey.encoded))
|
||||
val pubKey2 = Crypto.decodePublicKey(pubKey.encoded)
|
||||
assertEquals(pubKey2, pubKey)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ECDSA secp256r1 encode decode keys - required for serialization`() {
|
||||
// Generate key pair.
|
||||
val keyPair = Crypto.generateKeyPair("ECDSA_SECP256R1_SHA256")
|
||||
val keyPair = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256)
|
||||
val (privKey, pubKey) = keyPair
|
||||
|
||||
val kf = KeyFactory.getInstance("ECDSA", "BC")
|
||||
|
||||
// Encode and decode private key.
|
||||
val privKey2 = kf.generatePrivate(PKCS8EncodedKeySpec(privKey.encoded))
|
||||
val privKey2 = Crypto.decodePrivateKey(privKey.encoded)
|
||||
assertEquals(privKey2, privKey)
|
||||
|
||||
// Encode and decode public key.
|
||||
val pubKey2 = kf.generatePublic(X509EncodedKeySpec(pubKey.encoded))
|
||||
val pubKey2 = Crypto.decodePublicKey(pubKey.encoded)
|
||||
assertEquals(pubKey2, pubKey)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `EdDSA encode decode keys - required for serialization`() {
|
||||
// Generate key pair.
|
||||
val keyPair = Crypto.generateKeyPair("EDDSA_ED25519_SHA512")
|
||||
val keyPair = Crypto.generateKeyPair(Crypto.EDDSA_ED25519_SHA512)
|
||||
val (privKey, pubKey) = keyPair
|
||||
|
||||
val kf = KeyFactory.getInstance("EDDSA", "I2P")
|
||||
|
||||
// Encode and decode private key.
|
||||
val privKey2 = kf.generatePrivate(PKCS8EncodedKeySpec(privKey.encoded))
|
||||
val privKey2 = Crypto.decodePrivateKey(privKey.encoded)
|
||||
assertEquals(privKey2, privKey)
|
||||
|
||||
// Encode and decode public key.
|
||||
val pubKey2 = kf.generatePublic(X509EncodedKeySpec(pubKey.encoded))
|
||||
val pubKey2 = Crypto.decodePublicKey(pubKey.encoded)
|
||||
assertEquals(pubKey2, pubKey)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `SPHINCS-256 encode decode keys - required for serialization`() {
|
||||
// Generate key pair.
|
||||
val keyPair = Crypto.generateKeyPair("SPHINCS-256_SHA512")
|
||||
val keyPair = Crypto.generateKeyPair(Crypto.SPHINCS256_SHA256)
|
||||
val privKey: BCSphincs256PrivateKey = keyPair.private as BCSphincs256PrivateKey
|
||||
val pubKey: BCSphincs256PublicKey = keyPair.public as BCSphincs256PublicKey
|
||||
|
||||
//1st method for encoding/decoding
|
||||
|
||||
val keyFactory = KeyFactory.getInstance("SPHINCS256", "BCPQC")
|
||||
|
||||
// Encode and decode private key.
|
||||
val privKey2 = keyFactory.generatePrivate(PKCS8EncodedKeySpec(privKey.encoded))
|
||||
val privKey2 = Crypto.decodePrivateKey(privKey.encoded)
|
||||
assertEquals(privKey2, privKey)
|
||||
|
||||
// Encode and decode public key.
|
||||
val pubKey2 = keyFactory.generatePublic(X509EncodedKeySpec(pubKey.encoded))
|
||||
val pubKey2 = Crypto.decodePublicKey(pubKey.encoded)
|
||||
assertEquals(pubKey2, pubKey)
|
||||
|
||||
//2nd method for encoding/decoding
|
||||
@ -453,14 +429,14 @@ class CryptoUtilsTest {
|
||||
|
||||
// Encode and decode public key.
|
||||
val pubKeyInfo: SubjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(pubKey.encoded)
|
||||
val extractedPubKey = BCSphincs256PublicKey(pubKeyInfo)
|
||||
val decodedPubKey = BCSphincs256PublicKey(pubKeyInfo)
|
||||
// Check that decoded private key is equal to the initial one.
|
||||
assertEquals(extractedPubKey, pubKey)
|
||||
assertEquals(decodedPubKey, pubKey)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `RSA scheme finder by key type`() {
|
||||
val keyPairRSA = Crypto.generateKeyPair("RSA_SHA256")
|
||||
val keyPairRSA = Crypto.generateKeyPair(Crypto.RSA_SHA256)
|
||||
val (privRSA, pubRSA) = keyPairRSA
|
||||
assertEquals(privRSA.algorithm, "RSA")
|
||||
assertEquals(pubRSA.algorithm, "RSA")
|
||||
@ -468,23 +444,22 @@ class CryptoUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `ECDSA secp256k1 scheme finder by key type`() {
|
||||
val keyPairK1 = Crypto.generateKeyPair("ECDSA_SECP256K1_SHA256")
|
||||
val (privK1, pubK1) = keyPairK1
|
||||
val keyPair = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
|
||||
val (privKey, pubKey) = keyPair
|
||||
|
||||
// Encode and decode keys as they would be transferred.
|
||||
val kf = KeyFactory.getInstance("ECDSA", "BC")
|
||||
val privK1Decoded = kf.generatePrivate(PKCS8EncodedKeySpec(privK1.encoded))
|
||||
val pubK1Decoded = kf.generatePublic(X509EncodedKeySpec(pubK1.encoded))
|
||||
// Encode and decode private key.
|
||||
val privKeyDecoded = Crypto.decodePrivateKey(privKey.encoded)
|
||||
val pubKeyDecoded = Crypto.decodePublicKey(pubKey.encoded)
|
||||
|
||||
assertEquals(privK1Decoded.algorithm, "ECDSA")
|
||||
assertEquals((privK1Decoded as ECKey).parameters, ECNamedCurveTable.getParameterSpec("secp256k1"))
|
||||
assertEquals(pubK1Decoded.algorithm, "ECDSA")
|
||||
assertEquals((pubK1Decoded as ECKey).parameters, ECNamedCurveTable.getParameterSpec("secp256k1"))
|
||||
assertEquals(privKeyDecoded.algorithm, "ECDSA")
|
||||
assertEquals((privKeyDecoded as ECKey).parameters, ECNamedCurveTable.getParameterSpec("secp256k1"))
|
||||
assertEquals(pubKeyDecoded.algorithm, "ECDSA")
|
||||
assertEquals((pubKeyDecoded as ECKey).parameters, ECNamedCurveTable.getParameterSpec("secp256k1"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ECDSA secp256r1 scheme finder by key type`() {
|
||||
val keyPairR1 = Crypto.generateKeyPair("ECDSA_SECP256R1_SHA256")
|
||||
val keyPairR1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256)
|
||||
val (privR1, pubR1) = keyPairR1
|
||||
assertEquals(privR1.algorithm, "ECDSA")
|
||||
assertEquals((privR1 as ECKey).parameters, ECNamedCurveTable.getParameterSpec("secp256r1"))
|
||||
@ -494,7 +469,7 @@ class CryptoUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `EdDSA scheme finder by key type`() {
|
||||
val keyPairEd = Crypto.generateKeyPair("EDDSA_ED25519_SHA512")
|
||||
val keyPairEd = Crypto.generateKeyPair(Crypto.EDDSA_ED25519_SHA512)
|
||||
val (privEd, pubEd) = keyPairEd
|
||||
|
||||
assertEquals(privEd.algorithm, "EdDSA")
|
||||
@ -505,7 +480,7 @@ class CryptoUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `SPHINCS-256 scheme finder by key type`() {
|
||||
val keyPairSP = Crypto.generateKeyPair("SPHINCS-256_SHA512")
|
||||
val keyPairSP = Crypto.generateKeyPair(Crypto.SPHINCS256_SHA256)
|
||||
val (privSP, pubSP) = keyPairSP
|
||||
assertEquals(privSP.algorithm, "SPHINCS-256")
|
||||
assertEquals(pubSP.algorithm, "SPHINCS-256")
|
||||
@ -513,7 +488,7 @@ class CryptoUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `Automatic EdDSA key-type detection and decoding`() {
|
||||
val keyPairEd = Crypto.generateKeyPair("EDDSA_ED25519_SHA512")
|
||||
val keyPairEd = Crypto.generateKeyPair(Crypto.EDDSA_ED25519_SHA512)
|
||||
val (privEd, pubEd) = keyPairEd
|
||||
val encodedPrivEd = privEd.encoded
|
||||
val encodedPubEd = pubEd.encoded
|
||||
@ -529,7 +504,7 @@ class CryptoUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `Automatic ECDSA secp256k1 key-type detection and decoding`() {
|
||||
val keyPairK1 = Crypto.generateKeyPair("ECDSA_SECP256K1_SHA256")
|
||||
val keyPairK1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
|
||||
val (privK1, pubK1) = keyPairK1
|
||||
val encodedPrivK1 = privK1.encoded
|
||||
val encodedPubK1 = pubK1.encoded
|
||||
@ -545,7 +520,7 @@ class CryptoUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `Automatic ECDSA secp256r1 key-type detection and decoding`() {
|
||||
val keyPairR1 = Crypto.generateKeyPair("ECDSA_SECP256R1_SHA256")
|
||||
val keyPairR1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256)
|
||||
val (privR1, pubR1) = keyPairR1
|
||||
val encodedPrivR1 = privR1.encoded
|
||||
val encodedPubR1 = pubR1.encoded
|
||||
@ -561,7 +536,7 @@ class CryptoUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `Automatic RSA key-type detection and decoding`() {
|
||||
val keyPairRSA = Crypto.generateKeyPair("RSA_SHA256")
|
||||
val keyPairRSA = Crypto.generateKeyPair(Crypto.RSA_SHA256)
|
||||
val (privRSA, pubRSA) = keyPairRSA
|
||||
val encodedPrivRSA = privRSA.encoded
|
||||
val encodedPubRSA = pubRSA.encoded
|
||||
@ -577,7 +552,7 @@ class CryptoUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `Automatic SPHINCS-256 key-type detection and decoding`() {
|
||||
val keyPairSP = Crypto.generateKeyPair("SPHINCS-256_SHA512")
|
||||
val keyPairSP = Crypto.generateKeyPair(Crypto.SPHINCS256_SHA256)
|
||||
val (privSP, pubSP) = keyPairSP
|
||||
val encodedPrivSP = privSP.encoded
|
||||
val encodedPubSP = pubSP.encoded
|
||||
@ -593,12 +568,12 @@ class CryptoUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `Failure test between K1 and R1 keys`() {
|
||||
val keyPairK1 = Crypto.generateKeyPair("ECDSA_SECP256K1_SHA256")
|
||||
val keyPairK1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
|
||||
val privK1 = keyPairK1.private
|
||||
val encodedPrivK1 = privK1.encoded
|
||||
val decodedPrivK1 = Crypto.decodePrivateKey(encodedPrivK1)
|
||||
|
||||
val keyPairR1 = Crypto.generateKeyPair("ECDSA_SECP256R1_SHA256")
|
||||
val keyPairR1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256)
|
||||
val privR1 = keyPairR1.private
|
||||
val encodedPrivR1 = privR1.encoded
|
||||
val decodedPrivR1 = Crypto.decodePrivateKey(encodedPrivR1)
|
||||
@ -608,7 +583,7 @@ class CryptoUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `Decoding Failure on randomdata as key`() {
|
||||
val keyPairK1 = Crypto.generateKeyPair("ECDSA_SECP256K1_SHA256")
|
||||
val keyPairK1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
|
||||
val privK1 = keyPairK1.private
|
||||
val encodedPrivK1 = privK1.encoded
|
||||
|
||||
@ -628,7 +603,7 @@ class CryptoUtilsTest {
|
||||
|
||||
@Test
|
||||
fun `Decoding Failure on malformed keys`() {
|
||||
val keyPairK1 = Crypto.generateKeyPair("ECDSA_SECP256K1_SHA256")
|
||||
val keyPairK1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
|
||||
val privK1 = keyPairK1.private
|
||||
val encodedPrivK1 = privK1.encoded
|
||||
|
||||
|
@ -12,7 +12,7 @@ class SignedDataTest {
|
||||
@Test
|
||||
fun `make sure correctly signed data is released`() {
|
||||
val keyPair = generateKeyPair()
|
||||
val sig = keyPair.private.signWithECDSA(serialized.bytes, keyPair.public)
|
||||
val sig = keyPair.private.sign(serialized.bytes, keyPair.public)
|
||||
val wrappedData = SignedData(serialized, sig)
|
||||
val unwrappedData = wrappedData.verified()
|
||||
|
||||
@ -23,7 +23,7 @@ class SignedDataTest {
|
||||
fun `make sure incorrectly signed data raises an exception`() {
|
||||
val keyPairA = generateKeyPair()
|
||||
val keyPairB = generateKeyPair()
|
||||
val sig = keyPairA.private.signWithECDSA(serialized.bytes, keyPairB.public)
|
||||
val sig = keyPairA.private.sign(serialized.bytes, keyPairB.public)
|
||||
val wrappedData = SignedData(serialized, sig)
|
||||
wrappedData.verified()
|
||||
}
|
||||
|
@ -76,15 +76,14 @@ class KryoTests {
|
||||
val keyPair = generateKeyPair()
|
||||
val bitsToSign: ByteArray = Ints.toByteArray(0x01234567)
|
||||
val wrongBits: ByteArray = Ints.toByteArray(0x76543210)
|
||||
val signature = keyPair.signWithECDSA(bitsToSign)
|
||||
signature.verifyWithECDSA(bitsToSign)
|
||||
assertThatThrownBy { signature.verifyWithECDSA(wrongBits) }
|
||||
val signature = keyPair.sign(bitsToSign)
|
||||
signature.verify(bitsToSign)
|
||||
assertThatThrownBy { signature.verify(wrongBits) }
|
||||
|
||||
val deserialisedKeyPair = keyPair.serialize(kryo).deserialize(kryo)
|
||||
val deserialisedSignature = deserialisedKeyPair.signWithECDSA(bitsToSign)
|
||||
assertThat(deserialisedSignature).isEqualTo(signature)
|
||||
deserialisedSignature.verifyWithECDSA(bitsToSign)
|
||||
assertThatThrownBy { deserialisedSignature.verifyWithECDSA(wrongBits) }
|
||||
val deserialisedSignature = deserialisedKeyPair.sign(bitsToSign)
|
||||
deserialisedSignature.verify(bitsToSign)
|
||||
assertThatThrownBy { deserialisedSignature.verify(wrongBits) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -9,7 +9,7 @@ import net.corda.core.contracts.TransactionType
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.signWithECDSA
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.node.PluginServiceHub
|
||||
import net.corda.core.node.ServiceHub
|
||||
@ -258,7 +258,7 @@ class ForeignExchangeRemoteFlow(val source: Party) : FlowLogic<Unit>() {
|
||||
}
|
||||
|
||||
// assuming we have completed state and business level validation we can sign the trade
|
||||
val ourSignature = serviceHub.legalIdentityKey.signWithECDSA(proposedTrade.id)
|
||||
val ourSignature = serviceHub.legalIdentityKey.sign(proposedTrade.id)
|
||||
|
||||
// send the other side our signature.
|
||||
send(source, ourSignature)
|
||||
|
@ -250,7 +250,7 @@ class RecordCompletionFlow(val source: Party) : FlowLogic<Unit>() {
|
||||
}
|
||||
// DOCEND 3
|
||||
// Having verified the SignedTransaction passed to us we can sign it too
|
||||
val ourSignature = serviceHub.legalIdentityKey.signWithECDSA(completeTx.tx.id)
|
||||
val ourSignature = serviceHub.legalIdentityKey.sign(completeTx.tx.id)
|
||||
// Send our signature to the other party.
|
||||
send(source, ourSignature)
|
||||
// N.B. The FinalityProtocol will be responsible for Notarising the SignedTransaction
|
||||
|
@ -135,7 +135,7 @@ object TwoPartyTradeFlow {
|
||||
|
||||
open fun calculateOurSignature(partialTX: SignedTransaction): DigitalSignature.WithKey {
|
||||
progressTracker.currentStep = SIGNING
|
||||
return myKeyPair.signWithECDSA(partialTX.id)
|
||||
return myKeyPair.sign(partialTX.id)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -323,7 +323,7 @@ data class NodeRegistration(val node: NodeInfo, val serial: Long, val type: AddO
|
||||
*/
|
||||
fun toWire(privateKey: PrivateKey): WireNodeRegistration {
|
||||
val regSerialized = this.serialize()
|
||||
val regSig = privateKey.signWithECDSA(regSerialized.bytes, node.legalIdentity.owningKey)
|
||||
val regSig = privateKey.sign(regSerialized.bytes, node.legalIdentity.owningKey)
|
||||
|
||||
return WireNodeRegistration(regSerialized, regSig)
|
||||
}
|
||||
|
@ -198,7 +198,7 @@ object BFTSMaRt {
|
||||
|
||||
protected fun sign(bytes: ByteArray): DigitalSignature.WithKey {
|
||||
val mySigningKey = db.transaction { services.notaryIdentityKey }
|
||||
return mySigningKey.signWithECDSA(bytes)
|
||||
return mySigningKey.sign(bytes)
|
||||
}
|
||||
|
||||
// TODO:
|
||||
|
@ -54,7 +54,7 @@ class NotaryServiceTests {
|
||||
|
||||
val future = runNotaryClient(stx)
|
||||
val signatures = future.getOrThrow()
|
||||
signatures.forEach { it.verifyWithECDSA(stx.id) }
|
||||
signatures.forEach { it.verify(stx.id) }
|
||||
}
|
||||
|
||||
@Test fun `should sign a unique transaction without a timestamp`() {
|
||||
@ -67,7 +67,7 @@ class NotaryServiceTests {
|
||||
|
||||
val future = runNotaryClient(stx)
|
||||
val signatures = future.getOrThrow()
|
||||
signatures.forEach { it.verifyWithECDSA(stx.id) }
|
||||
signatures.forEach { it.verify(stx.id) }
|
||||
}
|
||||
|
||||
@Test fun `should report error for transaction with an invalid timestamp`() {
|
||||
|
@ -7,7 +7,7 @@ import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.MerkleTreeException
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.keys
|
||||
import net.corda.core.crypto.signWithECDSA
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.math.CubicSplineInterpolator
|
||||
import net.corda.core.math.Interpolator
|
||||
@ -224,7 +224,7 @@ object NodeInterestRates {
|
||||
// Note that we will happily sign an invalid transaction, as we are only being presented with a filtered
|
||||
// version so we can't resolve or check it ourselves. However, that doesn't matter much, as if we sign
|
||||
// an invalid transaction the signature is worthless.
|
||||
return signingKey.signWithECDSA(ftx.rootHash.bytes, identity)
|
||||
return signingKey.sign(ftx.rootHash.bytes, identity)
|
||||
}
|
||||
// DOCEND 1
|
||||
}
|
||||
|
@ -337,7 +337,7 @@ fun signAll(transactionsToSign: List<WireTransaction>, extraKeys: List<KeyPair>)
|
||||
}
|
||||
wtx.mustSign.expandedCompositeKeys.forEach {
|
||||
val key = keyLookup[it] ?: throw IllegalArgumentException("Missing required key for ${it.toStringShort()}")
|
||||
signatures += key.signWithECDSA(wtx.id)
|
||||
signatures += key.sign(wtx.id)
|
||||
}
|
||||
SignedTransaction(bits, signatures)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user