[CORDA-2063] Ensure signatures and BC operations always use newSecureRandom (#4020)

* special handling for Sphincs due a BC implementation issue

* delete all sign operations from DJVM and stub out BC's default RNG

* copy Crypto signing functions to deterministic.crypto.CryptoSignUtils as they are required for testing transaction signatures.
This commit is contained in:
Konstantinos Chalkias
2018-10-05 12:01:16 +01:00
committed by GitHub
parent d75fd7bd8a
commit fa4c54a080
6 changed files with 108 additions and 4 deletions

View File

@ -0,0 +1,68 @@
@file:JvmName("CryptoSignUtils")
package net.corda.deterministic.crypto
import net.corda.core.crypto.*
import net.corda.core.crypto.Crypto.findSignatureScheme
import net.corda.core.crypto.Crypto.isSupportedSignatureScheme
import net.corda.core.serialization.serialize
import java.security.*
/**
* This is a slightly modified copy of signing utils from net.corda.core.crypto.Crypto, which are normally removed from DJVM.
* However, we need those for TransactionSignatureTest.
*/
object CryptoSignUtils {
@JvmStatic
@Throws(InvalidKeyException::class, SignatureException::class)
fun doSign(schemeCodeName: String, privateKey: PrivateKey, clearData: ByteArray): ByteArray {
return doSign(findSignatureScheme(schemeCodeName), privateKey, clearData)
}
/**
* Generic way to sign [ByteArray] data with a [PrivateKey] and a known [Signature].
* @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.
* @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.
*/
@JvmStatic
@Throws(InvalidKeyException::class, SignatureException::class)
fun doSign(signatureScheme: SignatureScheme, privateKey: PrivateKey, clearData: ByteArray): ByteArray {
require(isSupportedSignatureScheme(signatureScheme)) {
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
}
require(clearData.isNotEmpty()) { "Signing of an empty array is not permitted!" }
val signature = Signature.getInstance(signatureScheme.signatureName, signatureScheme.providerName)
signature.initSign(privateKey)
signature.update(clearData)
return signature.sign()
}
/**
* Generic way to sign [SignableData] objects with a [PrivateKey].
* [SignableData] is a wrapper over the transaction's id (Merkle root) in order to attach extra information, such as
* a timestamp or partial and blind signature indicators.
* @param keyPair the signer's [KeyPair].
* @param signableData a [SignableData] object that adds extra information to a transaction.
* @return a [TransactionSignature] object than contains the output of a successful signing, signer's public key and
* the signature metadata.
* @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.
*/
@JvmStatic
@Throws(InvalidKeyException::class, SignatureException::class)
fun doSign(keyPair: KeyPair, signableData: SignableData): TransactionSignature {
val sigKey: SignatureScheme = findSignatureScheme(keyPair.private)
val sigMetaData: SignatureScheme = findSignatureScheme(keyPair.public)
require(sigKey == sigMetaData) {
"Metadata schemeCodeName: ${sigMetaData.schemeCodeName} is not aligned with the key type: ${sigKey.schemeCodeName}."
}
val signatureBytes = doSign(sigKey.schemeCodeName, keyPair.private, signableData.serialize().bytes)
return TransactionSignature(signatureBytes, keyPair.public, signableData.signatureMetadata)
}
}

View File

@ -37,7 +37,7 @@ class TransactionSignatureTest {
// Sign the meta object.
val transactionSignature: TransactionSignature = CheatingSecurityProvider().use {
keyPair.sign(signableData)
CryptoSignUtils.doSign(keyPair, signableData)
}
// Check auto-verification.
@ -52,7 +52,7 @@ class TransactionSignatureTest {
fun `Signature metadata full failure clearData has changed`() {
val signableData = SignableData(testBytes.sha256(), SignatureMetadata(1, Crypto.findSignatureScheme(keyPair.public).schemeNumberID))
val transactionSignature = CheatingSecurityProvider().use {
keyPair.sign(signableData)
CryptoSignUtils.doSign(keyPair, signableData)
}
Crypto.doVerify((testBytes + testBytes).sha256(), transactionSignature)
}
@ -137,7 +137,8 @@ class TransactionSignatureTest {
private fun signOneTx(txId: SecureHash, keyPair: KeyPair): TransactionSignature {
val signableData = SignableData(txId, SignatureMetadata(3, Crypto.findSignatureScheme(keyPair.public).schemeNumberID))
return CheatingSecurityProvider().use {
keyPair.sign(signableData)
CryptoSignUtils.doSign(keyPair, signableData)
}
}
}