mirror of
https://github.com/corda/corda.git
synced 2025-02-20 17:33:15 +00:00
Clean up Crypto (#1866)
clean up Crypto comments + PublicKey.toSHA256Bytes() uses .encoded
This commit is contained in:
parent
de391dc9f0
commit
ed79db6864
@ -2,7 +2,10 @@ package net.corda.core.crypto
|
||||
|
||||
import net.corda.core.internal.X509EdDSAEngine
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.i2p.crypto.eddsa.*
|
||||
import net.i2p.crypto.eddsa.EdDSAEngine
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey
|
||||
import net.i2p.crypto.eddsa.EdDSASecurityProvider
|
||||
import net.i2p.crypto.eddsa.math.GroupElement
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable
|
||||
@ -39,8 +42,6 @@ import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PublicKey
|
||||
import org.bouncycastle.pqc.jcajce.spec.SPHINCS256KeyGenParameterSpec
|
||||
import java.math.BigInteger
|
||||
import java.security.*
|
||||
import java.security.KeyFactory
|
||||
import java.security.KeyPairGenerator
|
||||
import java.security.spec.InvalidKeySpecException
|
||||
import java.security.spec.PKCS8EncodedKeySpec
|
||||
import java.security.spec.X509EncodedKeySpec
|
||||
@ -148,7 +149,7 @@ object Crypto {
|
||||
"at the cost of larger key sizes and loss of compatibility."
|
||||
)
|
||||
|
||||
/** Corda composite key type */
|
||||
/** Corda composite key type. */
|
||||
@JvmField
|
||||
val COMPOSITE_KEY = SignatureScheme(
|
||||
6,
|
||||
@ -823,7 +824,7 @@ object Crypto {
|
||||
@JvmStatic
|
||||
fun deriveKeyPairFromEntropy(entropy: BigInteger): KeyPair = deriveKeyPairFromEntropy(DEFAULT_SIGNATURE_SCHEME, entropy)
|
||||
|
||||
// custom key pair generator from entropy.
|
||||
// Custom key pair generator from entropy.
|
||||
private fun deriveEdDSAKeyPairFromEntropy(entropy: BigInteger): KeyPair {
|
||||
val params = EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec
|
||||
val bytes = entropy.toByteArray().copyOf(params.curve.field.getb() / 8) // Need to pad the entropy to the valid seed length.
|
||||
@ -882,7 +883,7 @@ object Crypto {
|
||||
}
|
||||
}
|
||||
|
||||
// return true if EdDSA publicKey is point at infinity.
|
||||
// Return true if EdDSA publicKey is point at infinity.
|
||||
// For EdDSA a custom function is required as it is not supported by the I2P implementation.
|
||||
private fun isEdDSAPointAtInfinity(publicKey: EdDSAPublicKey): Boolean {
|
||||
return publicKey.a.toP3() == (EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec).curve.getZero(GroupElement.Representation.P3)
|
||||
@ -894,7 +895,7 @@ object Crypto {
|
||||
return signatureScheme.schemeCodeName in signatureSchemeMap
|
||||
}
|
||||
|
||||
// validate a key, by checking its algorithmic params.
|
||||
// Validate a key, by checking its algorithmic params.
|
||||
private fun validateKey(signatureScheme: SignatureScheme, key: Key): Boolean {
|
||||
return when (key) {
|
||||
is PublicKey -> validatePublicKey(signatureScheme, key)
|
||||
@ -903,7 +904,7 @@ object Crypto {
|
||||
}
|
||||
}
|
||||
|
||||
// check if a public key satisfies algorithm specs (for ECC: key should lie on the curve and not being point-at-infinity).
|
||||
// Check if a public key satisfies algorithm specs (for ECC: key should lie on the curve and not being point-at-infinity).
|
||||
private fun validatePublicKey(signatureScheme: SignatureScheme, key: PublicKey): Boolean {
|
||||
return when (key) {
|
||||
is BCECPublicKey, is EdDSAPublicKey -> publicKeyOnCurve(signatureScheme, key)
|
||||
@ -912,7 +913,7 @@ object Crypto {
|
||||
}
|
||||
}
|
||||
|
||||
// check if a private key satisfies algorithm specs.
|
||||
// Check if a private key satisfies algorithm specs.
|
||||
private fun validatePrivateKey(signatureScheme: SignatureScheme, key: PrivateKey): Boolean {
|
||||
return when (key) {
|
||||
is BCECPrivateKey -> key.parameters == signatureScheme.algSpec
|
||||
@ -924,7 +925,6 @@ object Crypto {
|
||||
|
||||
/**
|
||||
* Convert a public key to a supported implementation.
|
||||
*
|
||||
* @param key a public key.
|
||||
* @return a supported implementation of the input public key.
|
||||
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
||||
|
@ -20,9 +20,19 @@ import java.security.*
|
||||
* @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)
|
||||
@Throws(InvalidKeyException::class, SignatureException::class)
|
||||
fun PrivateKey.sign(bytesToSign: ByteArray): DigitalSignature = DigitalSignature(Crypto.doSign(this, bytesToSign))
|
||||
|
||||
/**
|
||||
* Utility to simplify the act of signing a byte array and return a [DigitalSignature.WithKey] object.
|
||||
* Note that there is no check if the public key matches with the signing private key.
|
||||
* @param bytesToSign the data/message to be signed in [ByteArray] form (usually the Merkle root).
|
||||
* @return the [DigitalSignature.WithKey] object on the input message [bytesToSign] and [publicKey].
|
||||
* @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(InvalidKeyException::class, SignatureException::class)
|
||||
fun PrivateKey.sign(bytesToSign: ByteArray, publicKey: PublicKey) = DigitalSignature.WithKey(publicKey, this.sign(bytesToSign).bytes)
|
||||
|
||||
/**
|
||||
@ -33,10 +43,13 @@ fun PrivateKey.sign(bytesToSign: ByteArray, publicKey: PublicKey) = DigitalSigna
|
||||
* @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)
|
||||
@Throws(InvalidKeyException::class, SignatureException::class)
|
||||
fun KeyPair.sign(bytesToSign: ByteArray) = private.sign(bytesToSign, public)
|
||||
|
||||
/** Helper function to sign the bytes of [bytesToSign] with a key pair. */
|
||||
@Throws(InvalidKeyException::class, SignatureException::class)
|
||||
fun KeyPair.sign(bytesToSign: OpaqueBytes) = sign(bytesToSign.bytes)
|
||||
|
||||
/**
|
||||
* Helper function for signing a [SignableData] object.
|
||||
* @param signableData the object to be signed.
|
||||
@ -56,8 +69,8 @@ fun KeyPair.sign(signableData: SignableData): TransactionSignature = Crypto.doSi
|
||||
* @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()`,
|
||||
@Throws(SignatureException::class, IllegalArgumentException::class, InvalidKeyException::class)
|
||||
// TODO: SignatureException should be used only for a damaged signature, as per `java.security.Signature.verify()`.
|
||||
@Throws(SignatureException::class, InvalidKeyException::class)
|
||||
fun PublicKey.verify(content: ByteArray, signature: DigitalSignature) = Crypto.doVerify(this, signature.bytes, content)
|
||||
|
||||
/**
|
||||
@ -70,9 +83,10 @@ fun PublicKey.verify(content: ByteArray, signature: DigitalSignature) = Crypto.d
|
||||
* 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.
|
||||
* @throws IllegalStateException if this is a [CompositeKey], because verification of composite key signatures is not supported.
|
||||
* @return whether the signature is correct for this key.
|
||||
*/
|
||||
@Throws(IllegalStateException::class, SignatureException::class, IllegalArgumentException::class)
|
||||
@Throws(SignatureException::class, InvalidKeyException::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.
|
||||
@ -82,9 +96,12 @@ fun PublicKey.isValid(content: ByteArray, signature: DigitalSignature): Boolean
|
||||
/** Render a public key to its hash (in Base58) of its serialised form using the DL prefix. */
|
||||
fun PublicKey.toStringShort(): String = "DL" + this.toSHA256Bytes().toBase58()
|
||||
|
||||
/** Return a [Set] of the contained keys if this is a [CompositeKey]; otherwise, return a [Set] with a single element (this [PublicKey]). */
|
||||
val PublicKey.keys: Set<PublicKey> get() = (this as? CompositeKey)?.leafKeys ?: setOf(this)
|
||||
|
||||
/** Return true if [otherKey] fulfils the requirements of this [PublicKey]. */
|
||||
fun PublicKey.isFulfilledBy(otherKey: PublicKey): Boolean = isFulfilledBy(setOf(otherKey))
|
||||
/** Return true if [otherKeys] fulfil the requirements of this [PublicKey]. */
|
||||
fun PublicKey.isFulfilledBy(otherKeys: Iterable<PublicKey>): Boolean = (this as? CompositeKey)?.isFulfilledBy(otherKeys) ?: (this in otherKeys)
|
||||
|
||||
/** Checks whether any of the given [keys] matches a leaf on the [CompositeKey] tree or a single [PublicKey]. */
|
||||
@ -98,8 +115,9 @@ fun Iterable<TransactionSignature>.byKeys() = map { it.by }.toSet()
|
||||
|
||||
// Allow Kotlin destructuring:
|
||||
// val (private, public) = keyPair
|
||||
/* The [PrivateKey] of this [KeyPair] .*/
|
||||
operator fun KeyPair.component1(): PrivateKey = this.private
|
||||
|
||||
/* The [PublicKey] of this [KeyPair] .*/
|
||||
operator fun KeyPair.component2(): PublicKey = this.public
|
||||
|
||||
/** A simple wrapper that will make it easier to swap out the EC algorithm we use in future. */
|
||||
@ -122,7 +140,7 @@ fun entropyToKeyPair(entropy: BigInteger): KeyPair = Crypto.deriveKeyPairFromEnt
|
||||
* if this signatureData algorithm is unable to process the input data provided, etc.
|
||||
* @throws IllegalArgumentException if the signature scheme is not supported for this private key or if any of the clear or signature data is empty.
|
||||
*/
|
||||
@Throws(InvalidKeyException::class, SignatureException::class, IllegalArgumentException::class)
|
||||
@Throws(InvalidKeyException::class, SignatureException::class)
|
||||
fun PublicKey.verify(signatureData: ByteArray, clearData: ByteArray): Boolean = Crypto.doVerify(this, signatureData, clearData)
|
||||
|
||||
/**
|
||||
@ -135,7 +153,7 @@ fun PublicKey.verify(signatureData: ByteArray, clearData: ByteArray): Boolean =
|
||||
* if this signatureData algorithm is unable to process the input data provided, etc.
|
||||
* @throws IllegalArgumentException if the signature scheme is not supported for this private key or if any of the clear or signature data is empty.
|
||||
*/
|
||||
@Throws(InvalidKeyException::class, SignatureException::class, IllegalArgumentException::class)
|
||||
@Throws(InvalidKeyException::class, SignatureException::class)
|
||||
fun KeyPair.verify(signatureData: ByteArray, clearData: ByteArray): Boolean = Crypto.doVerify(this.public, signatureData, clearData)
|
||||
|
||||
/**
|
||||
|
@ -3,9 +3,8 @@
|
||||
package net.corda.core.utilities
|
||||
|
||||
import net.corda.core.crypto.Base58
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.serialization.serialize
|
||||
import java.nio.charset.Charset
|
||||
import java.security.PublicKey
|
||||
import java.util.*
|
||||
@ -15,11 +14,13 @@ import javax.xml.bind.DatatypeConverter
|
||||
|
||||
// [ByteArray] encoders
|
||||
|
||||
/** Convert a byte array to a Base58 encoded [String]. */
|
||||
fun ByteArray.toBase58(): String = Base58.encode(this)
|
||||
|
||||
/** Convert a byte array to a Base64 encoded [String]. */
|
||||
fun ByteArray.toBase64(): String = Base64.getEncoder().encodeToString(this)
|
||||
|
||||
/** Convert a byte array to a hex (base 16) capitalized encoded string.*/
|
||||
/** Convert a byte array to a hex (Base16) capitalized encoded [String]. */
|
||||
fun ByteArray.toHex(): String = DatatypeConverter.printHexBinary(this)
|
||||
|
||||
|
||||
@ -65,7 +66,15 @@ fun String.hexToBase64(): String = hexToByteArray().toBase64()
|
||||
// TODO We use for both CompositeKeys and EdDSAPublicKey custom serializers and deserializers. We need to specify encoding.
|
||||
// TODO: follow the crypto-conditions ASN.1 spec, some changes are needed to be compatible with the condition
|
||||
// structure, e.g. mapping a PublicKey to a condition with the specific feature (ED25519).
|
||||
fun parsePublicKeyBase58(base58String: String): PublicKey = base58String.base58ToByteArray().deserialize<PublicKey>()
|
||||
/**
|
||||
* Method to return the [PublicKey] object given its Base58-[String] representation.
|
||||
* @param base58String the Base58 encoded format of the serialised [PublicKey].
|
||||
* @return the resulted [PublicKey] after decoding the [base58String] input and then deserialising to a [PublicKey] object.
|
||||
*/
|
||||
fun parsePublicKeyBase58(base58String: String): PublicKey = Crypto.decodePublicKey(base58String.base58ToByteArray())
|
||||
|
||||
fun PublicKey.toBase58String(): String = this.serialize().bytes.toBase58()
|
||||
fun PublicKey.toSHA256Bytes(): ByteArray = this.serialize().bytes.sha256().bytes // TODO: decide on the format of hashed key (encoded Vs serialised).
|
||||
/** Return the Base58 representation of the serialised public key. */
|
||||
fun PublicKey.toBase58String(): String = this.encoded.toBase58()
|
||||
|
||||
/** Return the bytes of the SHA-256 output for this public key. */
|
||||
fun PublicKey.toSHA256Bytes(): ByteArray = this.encoded.sha256().bytes
|
||||
|
Loading…
x
Reference in New Issue
Block a user