mirror of
https://github.com/corda/corda.git
synced 2025-06-10 19:31:46 +00:00
Made all the members of Crypto.kt static so that Java users aren't forced to use Crypto.INSTANCE.
This commit is contained in:
parent
576e1c3c20
commit
3860b22339
@ -13,7 +13,7 @@ import java.security.Signature
|
|||||||
* This builder will use bouncy castle's JcaContentSignerBuilder as fallback for unknown algorithm.
|
* This builder will use bouncy castle's JcaContentSignerBuilder as fallback for unknown algorithm.
|
||||||
*/
|
*/
|
||||||
object ContentSignerBuilder {
|
object ContentSignerBuilder {
|
||||||
fun build(signatureScheme: SignatureScheme, privateKey: PrivateKey, provider: Provider?, random: SecureRandom? = null): ContentSigner {
|
fun build(signatureScheme: SignatureScheme, privateKey: PrivateKey, provider: Provider, random: SecureRandom? = null): ContentSigner {
|
||||||
val sigAlgId = signatureScheme.signatureOID
|
val sigAlgId = signatureScheme.signatureOID
|
||||||
val sig = Signature.getInstance(signatureScheme.signatureName, provider).apply {
|
val sig = Signature.getInstance(signatureScheme.signatureName, provider).apply {
|
||||||
if (random != null) {
|
if (random != null) {
|
||||||
|
@ -70,6 +70,7 @@ object Crypto {
|
|||||||
* RSA_SHA256 signature scheme using SHA256 as hash algorithm and MGF1 (with SHA256) as mask generation function.
|
* RSA_SHA256 signature scheme using SHA256 as hash algorithm and MGF1 (with SHA256) as mask generation function.
|
||||||
* Note: Recommended key size >= 3072 bits.
|
* Note: Recommended key size >= 3072 bits.
|
||||||
*/
|
*/
|
||||||
|
@JvmField
|
||||||
val RSA_SHA256 = SignatureScheme(
|
val RSA_SHA256 = SignatureScheme(
|
||||||
1,
|
1,
|
||||||
"RSA_SHA256",
|
"RSA_SHA256",
|
||||||
@ -84,6 +85,7 @@ object Crypto {
|
|||||||
)
|
)
|
||||||
|
|
||||||
/** ECDSA signature scheme using the secp256k1 Koblitz curve. */
|
/** ECDSA signature scheme using the secp256k1 Koblitz curve. */
|
||||||
|
@JvmField
|
||||||
val ECDSA_SECP256K1_SHA256 = SignatureScheme(
|
val ECDSA_SECP256K1_SHA256 = SignatureScheme(
|
||||||
2,
|
2,
|
||||||
"ECDSA_SECP256K1_SHA256",
|
"ECDSA_SECP256K1_SHA256",
|
||||||
@ -98,6 +100,7 @@ object Crypto {
|
|||||||
)
|
)
|
||||||
|
|
||||||
/** ECDSA signature scheme using the secp256r1 (NIST P-256) curve. */
|
/** ECDSA signature scheme using the secp256r1 (NIST P-256) curve. */
|
||||||
|
@JvmField
|
||||||
val ECDSA_SECP256R1_SHA256 = SignatureScheme(
|
val ECDSA_SECP256R1_SHA256 = SignatureScheme(
|
||||||
3,
|
3,
|
||||||
"ECDSA_SECP256R1_SHA256",
|
"ECDSA_SECP256R1_SHA256",
|
||||||
@ -112,6 +115,7 @@ object Crypto {
|
|||||||
)
|
)
|
||||||
|
|
||||||
/** EdDSA signature scheme using the ed255519 twisted Edwards curve. */
|
/** EdDSA signature scheme using the ed255519 twisted Edwards curve. */
|
||||||
|
@JvmField
|
||||||
val EDDSA_ED25519_SHA512 = SignatureScheme(
|
val EDDSA_ED25519_SHA512 = SignatureScheme(
|
||||||
4,
|
4,
|
||||||
"EDDSA_ED25519_SHA512",
|
"EDDSA_ED25519_SHA512",
|
||||||
@ -131,7 +135,10 @@ object Crypto {
|
|||||||
* SPHINCS-256 hash-based signature scheme. It provides 128bit security against post-quantum attackers
|
* 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.
|
* at the cost of larger key sizes and loss of compatibility.
|
||||||
*/
|
*/
|
||||||
|
@JvmField
|
||||||
val SHA512_256 = DLSequence(arrayOf(NISTObjectIdentifiers.id_sha512_256))
|
val SHA512_256 = DLSequence(arrayOf(NISTObjectIdentifiers.id_sha512_256))
|
||||||
|
|
||||||
|
@JvmField
|
||||||
val SPHINCS256_SHA256 = SignatureScheme(
|
val SPHINCS256_SHA256 = SignatureScheme(
|
||||||
5,
|
5,
|
||||||
"SPHINCS-256_SHA512",
|
"SPHINCS-256_SHA512",
|
||||||
@ -146,13 +153,12 @@ object Crypto {
|
|||||||
"at the cost of larger key sizes and loss of compatibility."
|
"at the cost of larger key sizes and loss of compatibility."
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/** Corda composite key type */
|
||||||
* Corda composite key type
|
@JvmField
|
||||||
*/
|
|
||||||
val COMPOSITE_KEY = SignatureScheme(
|
val COMPOSITE_KEY = SignatureScheme(
|
||||||
6,
|
6,
|
||||||
"COMPOSITE",
|
"COMPOSITE",
|
||||||
AlgorithmIdentifier(CordaObjectIdentifier.compositeKey),
|
AlgorithmIdentifier(CordaObjectIdentifier.COMPOSITE_KEY),
|
||||||
emptyList(),
|
emptyList(),
|
||||||
CordaSecurityProvider.PROVIDER_NAME,
|
CordaSecurityProvider.PROVIDER_NAME,
|
||||||
CompositeKey.KEY_ALGORITHM,
|
CompositeKey.KEY_ALGORITHM,
|
||||||
@ -163,13 +169,14 @@ object Crypto {
|
|||||||
)
|
)
|
||||||
|
|
||||||
/** Our default signature scheme if no algorithm is specified (e.g. for key generation). */
|
/** Our default signature scheme if no algorithm is specified (e.g. for key generation). */
|
||||||
|
@JvmField
|
||||||
val DEFAULT_SIGNATURE_SCHEME = EDDSA_ED25519_SHA512
|
val DEFAULT_SIGNATURE_SCHEME = EDDSA_ED25519_SHA512
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Supported digital signature schemes.
|
* Supported digital signature schemes.
|
||||||
* Note: Only the schemes added in this map will be supported (see [Crypto]).
|
* Note: Only the schemes added in this map will be supported (see [Crypto]).
|
||||||
*/
|
*/
|
||||||
val supportedSignatureSchemes = listOf(
|
private val signatureSchemeMap: Map<String, SignatureScheme> = listOf(
|
||||||
RSA_SHA256,
|
RSA_SHA256,
|
||||||
ECDSA_SECP256K1_SHA256,
|
ECDSA_SECP256K1_SHA256,
|
||||||
ECDSA_SECP256R1_SHA256,
|
ECDSA_SECP256R1_SHA256,
|
||||||
@ -183,15 +190,15 @@ object Crypto {
|
|||||||
* algorithm identifiers.
|
* algorithm identifiers.
|
||||||
*/
|
*/
|
||||||
private val algorithmMap: Map<AlgorithmIdentifier, SignatureScheme>
|
private val algorithmMap: Map<AlgorithmIdentifier, SignatureScheme>
|
||||||
= (supportedSignatureSchemes.values.flatMap { scheme -> scheme.alternativeOIDs.map { oid -> Pair(oid, scheme) } }
|
= (signatureSchemeMap.values.flatMap { scheme -> scheme.alternativeOIDs.map { Pair(it, scheme) } }
|
||||||
+ supportedSignatureSchemes.values.map { Pair(it.signatureOID, it) })
|
+ signatureSchemeMap.values.map { Pair(it.signatureOID, it) })
|
||||||
.toMap()
|
.toMap()
|
||||||
|
|
||||||
// This map is required to defend against users that forcibly call Security.addProvider / Security.removeProvider
|
// This map is required to defend against users that forcibly call Security.addProvider / Security.removeProvider
|
||||||
// that could cause unexpected and suspicious behaviour.
|
// 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.
|
// 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.
|
// The val is private to avoid any harmful state changes.
|
||||||
val providerMap: Map<String, Provider> = mapOf(
|
private val providerMap: Map<String, Provider> = mapOf(
|
||||||
BouncyCastleProvider.PROVIDER_NAME to getBouncyCastleProvider(),
|
BouncyCastleProvider.PROVIDER_NAME to getBouncyCastleProvider(),
|
||||||
CordaSecurityProvider.PROVIDER_NAME to CordaSecurityProvider(),
|
CordaSecurityProvider.PROVIDER_NAME to CordaSecurityProvider(),
|
||||||
"BCPQC" to BouncyCastlePQCProvider()) // unfortunately, provider's name is not final in BouncyCastlePQCProvider, so we explicitly set it.
|
"BCPQC" to BouncyCastlePQCProvider()) // unfortunately, provider's name is not final in BouncyCastlePQCProvider, so we explicitly set it.
|
||||||
@ -201,6 +208,14 @@ object Crypto {
|
|||||||
addKeyInfoConverter(EDDSA_ED25519_SHA512.signatureOID.algorithm, KeyInfoConverter(EDDSA_ED25519_SHA512))
|
addKeyInfoConverter(EDDSA_ED25519_SHA512.signatureOID.algorithm, KeyInfoConverter(EDDSA_ED25519_SHA512))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun supportedSignatureSchemes(): List<SignatureScheme> = ArrayList(signatureSchemeMap.values)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun findProvider(name: String): Provider {
|
||||||
|
return providerMap[name] ?: throw IllegalArgumentException("Unrecognised provider: $name")
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// This registration is needed for reading back EdDSA key from java keystore.
|
// This registration is needed for reading back EdDSA key from java keystore.
|
||||||
// TODO: Find a way to make JKS work with bouncy castle provider or implement our own provide so we don't have to register bouncy castle provider.
|
// TODO: Find a way to make JKS work with bouncy castle provider or implement our own provide so we don't have to register bouncy castle provider.
|
||||||
@ -219,8 +234,10 @@ object Crypto {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
fun findSignatureScheme(algorithm: AlgorithmIdentifier): SignatureScheme {
|
fun findSignatureScheme(algorithm: AlgorithmIdentifier): SignatureScheme {
|
||||||
return algorithmMap[normaliseAlgorithmIdentifier(algorithm)] ?: throw IllegalArgumentException("Unrecognised algorithm: ${algorithm.algorithm.id}")
|
return algorithmMap[normaliseAlgorithmIdentifier(algorithm)]
|
||||||
|
?: throw IllegalArgumentException("Unrecognised algorithm: ${algorithm.algorithm.id}")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -231,8 +248,11 @@ object Crypto {
|
|||||||
* @return a currently supported SignatureScheme.
|
* @return a currently supported SignatureScheme.
|
||||||
* @throws IllegalArgumentException if the requested signature scheme is not supported.
|
* @throws IllegalArgumentException if the requested signature scheme is not supported.
|
||||||
*/
|
*/
|
||||||
@Throws(IllegalArgumentException::class)
|
@JvmStatic
|
||||||
fun findSignatureScheme(schemeCodeName: String): SignatureScheme = supportedSignatureSchemes[schemeCodeName] ?: throw IllegalArgumentException("Unsupported key/algorithm for schemeCodeName: $schemeCodeName")
|
fun findSignatureScheme(schemeCodeName: String): SignatureScheme {
|
||||||
|
return signatureSchemeMap[schemeCodeName]
|
||||||
|
?: throw IllegalArgumentException("Unsupported key/algorithm for schemeCodeName: $schemeCodeName")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the corresponding [SignatureScheme] based on the type of the input [Key].
|
* Retrieve the corresponding [SignatureScheme] based on the type of the input [Key].
|
||||||
@ -242,7 +262,7 @@ object Crypto {
|
|||||||
* @return a currently supported SignatureScheme.
|
* @return a currently supported SignatureScheme.
|
||||||
* @throws IllegalArgumentException if the requested key type is not supported.
|
* @throws IllegalArgumentException if the requested key type is not supported.
|
||||||
*/
|
*/
|
||||||
@Throws(IllegalArgumentException::class)
|
@JvmStatic
|
||||||
fun findSignatureScheme(key: PublicKey): SignatureScheme {
|
fun findSignatureScheme(key: PublicKey): SignatureScheme {
|
||||||
val keyInfo = SubjectPublicKeyInfo.getInstance(key.encoded)
|
val keyInfo = SubjectPublicKeyInfo.getInstance(key.encoded)
|
||||||
return findSignatureScheme(keyInfo.algorithm)
|
return findSignatureScheme(keyInfo.algorithm)
|
||||||
@ -256,7 +276,7 @@ object Crypto {
|
|||||||
* @return a currently supported SignatureScheme.
|
* @return a currently supported SignatureScheme.
|
||||||
* @throws IllegalArgumentException if the requested key type is not supported.
|
* @throws IllegalArgumentException if the requested key type is not supported.
|
||||||
*/
|
*/
|
||||||
@Throws(IllegalArgumentException::class)
|
@JvmStatic
|
||||||
fun findSignatureScheme(key: PrivateKey): SignatureScheme {
|
fun findSignatureScheme(key: PrivateKey): SignatureScheme {
|
||||||
val keyInfo = PrivateKeyInfo.getInstance(key.encoded)
|
val keyInfo = PrivateKeyInfo.getInstance(key.encoded)
|
||||||
return findSignatureScheme(keyInfo.privateKeyAlgorithm)
|
return findSignatureScheme(keyInfo.privateKeyAlgorithm)
|
||||||
@ -269,11 +289,12 @@ object Crypto {
|
|||||||
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
||||||
* is inappropriate for this key factory to produce a private key.
|
* is inappropriate for this key factory to produce a private key.
|
||||||
*/
|
*/
|
||||||
@Throws(IllegalArgumentException::class)
|
@JvmStatic
|
||||||
fun decodePrivateKey(encodedKey: ByteArray): PrivateKey {
|
fun decodePrivateKey(encodedKey: ByteArray): PrivateKey {
|
||||||
val keyInfo = PrivateKeyInfo.getInstance(encodedKey)
|
val keyInfo = PrivateKeyInfo.getInstance(encodedKey)
|
||||||
val signatureScheme = findSignatureScheme(keyInfo.privateKeyAlgorithm)
|
val signatureScheme = findSignatureScheme(keyInfo.privateKeyAlgorithm)
|
||||||
return KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName]).generatePrivate(PKCS8EncodedKeySpec(encodedKey))
|
val keyFactory = KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName])
|
||||||
|
return keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -284,8 +305,11 @@ object Crypto {
|
|||||||
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
||||||
* is inappropriate for this key factory to produce a private key.
|
* is inappropriate for this key factory to produce a private key.
|
||||||
*/
|
*/
|
||||||
@Throws(IllegalArgumentException::class, InvalidKeySpecException::class)
|
@JvmStatic
|
||||||
fun decodePrivateKey(schemeCodeName: String, encodedKey: ByteArray): PrivateKey = decodePrivateKey(findSignatureScheme(schemeCodeName), encodedKey)
|
@Throws(InvalidKeySpecException::class)
|
||||||
|
fun decodePrivateKey(schemeCodeName: String, encodedKey: ByteArray): PrivateKey {
|
||||||
|
return decodePrivateKey(findSignatureScheme(schemeCodeName), encodedKey)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode a PKCS8 encoded key to its [PrivateKey] object based on the input scheme code name.
|
* Decode a PKCS8 encoded key to its [PrivateKey] object based on the input scheme code name.
|
||||||
@ -295,13 +319,18 @@ object Crypto {
|
|||||||
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
||||||
* is inappropriate for this key factory to produce a private key.
|
* is inappropriate for this key factory to produce a private key.
|
||||||
*/
|
*/
|
||||||
@Throws(IllegalArgumentException::class, InvalidKeySpecException::class)
|
@JvmStatic
|
||||||
|
@Throws(InvalidKeySpecException::class)
|
||||||
fun decodePrivateKey(signatureScheme: SignatureScheme, encodedKey: ByteArray): PrivateKey {
|
fun decodePrivateKey(signatureScheme: SignatureScheme, encodedKey: ByteArray): PrivateKey {
|
||||||
require(isSupportedSignatureScheme(signatureScheme)) { "Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}" }
|
require(isSupportedSignatureScheme(signatureScheme)) {
|
||||||
|
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
return KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName]).generatePrivate(PKCS8EncodedKeySpec(encodedKey))
|
val keyFactory = KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName])
|
||||||
|
return keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey))
|
||||||
} catch (ikse: InvalidKeySpecException) {
|
} 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)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,11 +341,12 @@ object Crypto {
|
|||||||
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
||||||
* is inappropriate for this key factory to produce a private key.
|
* is inappropriate for this key factory to produce a private key.
|
||||||
*/
|
*/
|
||||||
@Throws(IllegalArgumentException::class)
|
@JvmStatic
|
||||||
fun decodePublicKey(encodedKey: ByteArray): PublicKey {
|
fun decodePublicKey(encodedKey: ByteArray): PublicKey {
|
||||||
val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(encodedKey)
|
val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(encodedKey)
|
||||||
val signatureScheme = findSignatureScheme(subjectPublicKeyInfo.algorithm)
|
val signatureScheme = findSignatureScheme(subjectPublicKeyInfo.algorithm)
|
||||||
return KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName]).generatePublic(X509EncodedKeySpec(encodedKey))
|
val keyFactory = KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName])
|
||||||
|
return keyFactory.generatePublic(X509EncodedKeySpec(encodedKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -328,8 +358,11 @@ object Crypto {
|
|||||||
* @throws InvalidKeySpecException if the given key specification
|
* @throws InvalidKeySpecException if the given key specification
|
||||||
* is inappropriate for this key factory to produce a public key.
|
* is inappropriate for this key factory to produce a public key.
|
||||||
*/
|
*/
|
||||||
@Throws(IllegalArgumentException::class, InvalidKeySpecException::class)
|
@JvmStatic
|
||||||
fun decodePublicKey(schemeCodeName: String, encodedKey: ByteArray): PublicKey = decodePublicKey(findSignatureScheme(schemeCodeName), encodedKey)
|
@Throws(InvalidKeySpecException::class)
|
||||||
|
fun decodePublicKey(schemeCodeName: String, encodedKey: ByteArray): PublicKey {
|
||||||
|
return decodePublicKey(findSignatureScheme(schemeCodeName), encodedKey)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode an X509 encoded key to its [PrivateKey] object based on the input scheme code name.
|
* Decode an X509 encoded key to its [PrivateKey] object based on the input scheme code name.
|
||||||
@ -340,19 +373,25 @@ object Crypto {
|
|||||||
* @throws InvalidKeySpecException if the given key specification
|
* @throws InvalidKeySpecException if the given key specification
|
||||||
* is inappropriate for this key factory to produce a public key.
|
* is inappropriate for this key factory to produce a public key.
|
||||||
*/
|
*/
|
||||||
@Throws(IllegalArgumentException::class, InvalidKeySpecException::class)
|
@JvmStatic
|
||||||
|
@Throws(InvalidKeySpecException::class)
|
||||||
fun decodePublicKey(signatureScheme: SignatureScheme, encodedKey: ByteArray): PublicKey {
|
fun decodePublicKey(signatureScheme: SignatureScheme, encodedKey: ByteArray): PublicKey {
|
||||||
require(isSupportedSignatureScheme(signatureScheme)) { "Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}" }
|
require(isSupportedSignatureScheme(signatureScheme)) {
|
||||||
|
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
return KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName]).generatePublic(X509EncodedKeySpec(encodedKey))
|
val keyFactory = KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName])
|
||||||
|
return keyFactory.generatePublic(X509EncodedKeySpec(encodedKey))
|
||||||
} catch (ikse: InvalidKeySpecException) {
|
} 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)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic way to sign [ByteArray] data with a [PrivateKey]. Strategy on on identifying the actual signing scheme is based
|
* 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).
|
* on the [PrivateKey] type, but if the schemeCodeName is known, then better use
|
||||||
|
* doSign(signatureScheme: String, privateKey: PrivateKey, clearData: ByteArray).
|
||||||
* @param privateKey the signer's [PrivateKey].
|
* @param privateKey the signer's [PrivateKey].
|
||||||
* @param clearData the data/message to be signed in [ByteArray] form (usually the Merkle root).
|
* @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.
|
* @return the digital signature (in [ByteArray]) on the input message.
|
||||||
@ -360,7 +399,8 @@ object Crypto {
|
|||||||
* @throws InvalidKeyException if the private key is invalid.
|
* @throws InvalidKeyException if the private key is invalid.
|
||||||
* @throws SignatureException if signing is not possible due to malformed data or private key.
|
* @throws SignatureException if signing is not possible due to malformed data or private key.
|
||||||
*/
|
*/
|
||||||
@Throws(IllegalArgumentException::class, InvalidKeyException::class, SignatureException::class)
|
@JvmStatic
|
||||||
|
@Throws(InvalidKeyException::class, SignatureException::class)
|
||||||
fun doSign(privateKey: PrivateKey, clearData: ByteArray) = doSign(findSignatureScheme(privateKey), privateKey, clearData)
|
fun doSign(privateKey: PrivateKey, clearData: ByteArray) = doSign(findSignatureScheme(privateKey), privateKey, clearData)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -373,8 +413,11 @@ object Crypto {
|
|||||||
* @throws InvalidKeyException if the private key is invalid.
|
* @throws InvalidKeyException if the private key is invalid.
|
||||||
* @throws SignatureException if signing is not possible due to malformed data or private key.
|
* @throws SignatureException if signing is not possible due to malformed data or private key.
|
||||||
*/
|
*/
|
||||||
@Throws(IllegalArgumentException::class, InvalidKeyException::class, SignatureException::class)
|
@JvmStatic
|
||||||
fun doSign(schemeCodeName: String, privateKey: PrivateKey, clearData: ByteArray) = doSign(findSignatureScheme(schemeCodeName), privateKey, clearData)
|
@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].
|
* Generic way to sign [ByteArray] data with a [PrivateKey] and a known [Signature].
|
||||||
@ -386,11 +429,14 @@ object Crypto {
|
|||||||
* @throws InvalidKeyException if the private key is invalid.
|
* @throws InvalidKeyException if the private key is invalid.
|
||||||
* @throws SignatureException if signing is not possible due to malformed data or private key.
|
* @throws SignatureException if signing is not possible due to malformed data or private key.
|
||||||
*/
|
*/
|
||||||
@Throws(IllegalArgumentException::class, InvalidKeyException::class, SignatureException::class)
|
@JvmStatic
|
||||||
|
@Throws(InvalidKeyException::class, SignatureException::class)
|
||||||
fun doSign(signatureScheme: SignatureScheme, privateKey: PrivateKey, clearData: ByteArray): ByteArray {
|
fun doSign(signatureScheme: SignatureScheme, privateKey: PrivateKey, clearData: ByteArray): ByteArray {
|
||||||
require(isSupportedSignatureScheme(signatureScheme)) { "Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}" }
|
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, providerMap[signatureScheme.providerName])
|
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.initSign(privateKey)
|
||||||
signature.update(clearData)
|
signature.update(clearData)
|
||||||
return signature.sign()
|
return signature.sign()
|
||||||
@ -398,20 +444,24 @@ object Crypto {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic way to sign [SignableData] objects with a [PrivateKey].
|
* 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.
|
* [SignableData] is a wrapper over the transaction's id (Merkle root) in order to attach extra information, such as
|
||||||
* @param privateKey the signer's [PrivateKey].
|
* 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.
|
* @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.
|
* @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 IllegalArgumentException if the signature scheme is not supported for this private key.
|
||||||
* @throws InvalidKeyException if the private key is invalid.
|
* @throws InvalidKeyException if the private key is invalid.
|
||||||
* @throws SignatureException if signing is not possible due to malformed data or private key.
|
* @throws SignatureException if signing is not possible due to malformed data or private key.
|
||||||
*/
|
*/
|
||||||
@Throws(IllegalArgumentException::class, InvalidKeyException::class, SignatureException::class)
|
@JvmStatic
|
||||||
|
@Throws(InvalidKeyException::class, SignatureException::class)
|
||||||
fun doSign(keyPair: KeyPair, signableData: SignableData): TransactionSignature {
|
fun doSign(keyPair: KeyPair, signableData: SignableData): TransactionSignature {
|
||||||
val sigKey: SignatureScheme = findSignatureScheme(keyPair.private)
|
val sigKey: SignatureScheme = findSignatureScheme(keyPair.private)
|
||||||
val sigMetaData: SignatureScheme = findSignatureScheme(keyPair.public)
|
val sigMetaData: SignatureScheme = findSignatureScheme(keyPair.public)
|
||||||
if (sigKey != sigMetaData) throw IllegalArgumentException("Metadata schemeCodeName: ${sigMetaData.schemeCodeName}" +
|
require(sigKey == sigMetaData) {
|
||||||
" is not aligned with the key type: ${sigKey.schemeCodeName}.")
|
"Metadata schemeCodeName: ${sigMetaData.schemeCodeName} is not aligned with the key type: ${sigKey.schemeCodeName}."
|
||||||
|
}
|
||||||
val signatureBytes = doSign(sigKey.schemeCodeName, keyPair.private, signableData.serialize().bytes)
|
val signatureBytes = doSign(sigKey.schemeCodeName, keyPair.private, signableData.serialize().bytes)
|
||||||
return TransactionSignature(signatureBytes, keyPair.public, signableData.signatureMetadata)
|
return TransactionSignature(signatureBytes, keyPair.public, signableData.signatureMetadata)
|
||||||
}
|
}
|
||||||
@ -430,8 +480,11 @@ object Crypto {
|
|||||||
* if this signatureData scheme is unable to process the input data provided, if the verification is not possible.
|
* if this signatureData scheme is unable to process the input data provided, if the verification is not possible.
|
||||||
* @throws IllegalArgumentException if the signature scheme is not supported or 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.
|
||||||
*/
|
*/
|
||||||
|
@JvmStatic
|
||||||
@Throws(InvalidKeyException::class, SignatureException::class)
|
@Throws(InvalidKeyException::class, SignatureException::class)
|
||||||
fun doVerify(schemeCodeName: String, publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray) = doVerify(findSignatureScheme(schemeCodeName), publicKey, signatureData, clearData)
|
fun doVerify(schemeCodeName: String, publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray): Boolean {
|
||||||
|
return 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.
|
* Utility to simplify the act of verifying a digital signature by identifying the signature scheme used from the input public key's type.
|
||||||
@ -448,8 +501,11 @@ object Crypto {
|
|||||||
* if this signatureData scheme is unable to process the input data provided, if the verification is not possible.
|
* if this signatureData scheme is unable to process the input data provided, if the verification is not possible.
|
||||||
* @throws IllegalArgumentException if the signature scheme is not supported or 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.
|
||||||
*/
|
*/
|
||||||
@Throws(InvalidKeyException::class, SignatureException::class, IllegalArgumentException::class)
|
@JvmStatic
|
||||||
fun doVerify(publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray) = doVerify(findSignatureScheme(publicKey), publicKey, signatureData, clearData)
|
@Throws(InvalidKeyException::class, SignatureException::class)
|
||||||
|
fun doVerify(publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray): Boolean {
|
||||||
|
return doVerify(findSignatureScheme(publicKey), publicKey, signatureData, clearData)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to verify a digital signature.
|
* Method to verify a digital signature.
|
||||||
@ -465,9 +521,12 @@ object Crypto {
|
|||||||
* if this signatureData scheme is unable to process the input data provided, if the verification is not possible.
|
* if this signatureData scheme is unable to process the input data provided, if the verification is not possible.
|
||||||
* @throws IllegalArgumentException if the signature scheme is not supported or 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.
|
||||||
*/
|
*/
|
||||||
@Throws(InvalidKeyException::class, SignatureException::class, IllegalArgumentException::class)
|
@JvmStatic
|
||||||
|
@Throws(InvalidKeyException::class, SignatureException::class)
|
||||||
fun doVerify(signatureScheme: SignatureScheme, publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray): Boolean {
|
fun doVerify(signatureScheme: SignatureScheme, publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray): Boolean {
|
||||||
require(isSupportedSignatureScheme(signatureScheme)) { "Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}" }
|
require(isSupportedSignatureScheme(signatureScheme)) {
|
||||||
|
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
|
||||||
|
}
|
||||||
if (signatureData.isEmpty()) throw IllegalArgumentException("Signature data is empty!")
|
if (signatureData.isEmpty()) throw IllegalArgumentException("Signature data is empty!")
|
||||||
if (clearData.isEmpty()) throw IllegalArgumentException("Clear data is empty, nothing to verify!")
|
if (clearData.isEmpty()) throw IllegalArgumentException("Clear data is empty, nothing to verify!")
|
||||||
val verificationResult = isValid(signatureScheme, publicKey, signatureData, clearData)
|
val verificationResult = isValid(signatureScheme, publicKey, signatureData, clearData)
|
||||||
@ -490,14 +549,16 @@ object Crypto {
|
|||||||
* if this signatureData scheme is unable to process the input data provided, if the verification is not possible.
|
* if this signatureData scheme is unable to process the input data provided, if the verification is not possible.
|
||||||
* @throws IllegalArgumentException if the signature scheme is not supported or 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.
|
||||||
*/
|
*/
|
||||||
@Throws(InvalidKeyException::class, SignatureException::class, IllegalArgumentException::class)
|
@JvmStatic
|
||||||
|
@Throws(InvalidKeyException::class, SignatureException::class)
|
||||||
fun doVerify(txId: SecureHash, transactionSignature: TransactionSignature): Boolean {
|
fun doVerify(txId: SecureHash, transactionSignature: TransactionSignature): Boolean {
|
||||||
val signableData = SignableData(txId, transactionSignature.signatureMetadata)
|
val signableData = SignableData(txId, transactionSignature.signatureMetadata)
|
||||||
return Crypto.doVerify(transactionSignature.by, transactionSignature.bytes, signableData.serialize().bytes)
|
return Crypto.doVerify(transactionSignature.by, transactionSignature.bytes, signableData.serialize().bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility to simplify the act of verifying a digital signature by identifying the signature scheme used from the input public key's type.
|
* 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
|
* 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,
|
* 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.
|
* as it avoids the risk of failing to test the result.
|
||||||
@ -507,14 +568,20 @@ object Crypto {
|
|||||||
* the passed-in signatureData is improperly encoded or of the wrong type,
|
* 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.
|
* if this signatureData scheme is unable to process the input data provided, if the verification is not possible.
|
||||||
*/
|
*/
|
||||||
|
@JvmStatic
|
||||||
@Throws(SignatureException::class)
|
@Throws(SignatureException::class)
|
||||||
fun isValid(txId: SecureHash, transactionSignature: TransactionSignature): Boolean {
|
fun isValid(txId: SecureHash, transactionSignature: TransactionSignature): Boolean {
|
||||||
val signableData = SignableData(txId, transactionSignature.signatureMetadata)
|
val signableData = SignableData(txId, transactionSignature.signatureMetadata)
|
||||||
return isValid(findSignatureScheme(transactionSignature.by), transactionSignature.by, transactionSignature.bytes, signableData.serialize().bytes)
|
return isValid(
|
||||||
|
findSignatureScheme(transactionSignature.by),
|
||||||
|
transactionSignature.by,
|
||||||
|
transactionSignature.bytes,
|
||||||
|
signableData.serialize().bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility to simplify the act of verifying a digital signature by identifying the signature scheme used from the input public key's type.
|
* 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
|
* 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,
|
* 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.
|
* as it avoids the risk of failing to test the result.
|
||||||
@ -527,8 +594,11 @@ object Crypto {
|
|||||||
* the passed-in signatureData is improperly encoded or of the wrong type,
|
* 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.
|
* if this signatureData scheme is unable to process the input data provided, if the verification is not possible.
|
||||||
*/
|
*/
|
||||||
|
@JvmStatic
|
||||||
@Throws(SignatureException::class)
|
@Throws(SignatureException::class)
|
||||||
fun isValid(publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray) = isValid(findSignatureScheme(publicKey), publicKey, signatureData, clearData)
|
fun isValid(publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray): Boolean {
|
||||||
|
return isValid(findSignatureScheme(publicKey), publicKey, signatureData, clearData)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to verify a digital signature. In comparison to [doVerify] if the key and signature
|
* Method to verify a digital signature. In comparison to [doVerify] if the key and signature
|
||||||
@ -544,9 +614,12 @@ object Crypto {
|
|||||||
* if this signatureData scheme is unable to process the input data provided, if the verification is not possible.
|
* 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 IllegalArgumentException if the requested signature scheme is not supported.
|
||||||
*/
|
*/
|
||||||
@Throws(SignatureException::class, IllegalArgumentException::class)
|
@JvmStatic
|
||||||
|
@Throws(SignatureException::class)
|
||||||
fun isValid(signatureScheme: SignatureScheme, publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray): Boolean {
|
fun isValid(signatureScheme: SignatureScheme, publicKey: PublicKey, signatureData: ByteArray, clearData: ByteArray): Boolean {
|
||||||
require(isSupportedSignatureScheme(signatureScheme)) { "Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}" }
|
require(isSupportedSignatureScheme(signatureScheme)) {
|
||||||
|
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
|
||||||
|
}
|
||||||
val signature = Signature.getInstance(signatureScheme.signatureName, providerMap[signatureScheme.providerName])
|
val signature = Signature.getInstance(signatureScheme.signatureName, providerMap[signatureScheme.providerName])
|
||||||
signature.initVerify(publicKey)
|
signature.initVerify(publicKey)
|
||||||
signature.update(clearData)
|
signature.update(clearData)
|
||||||
@ -560,7 +633,7 @@ object Crypto {
|
|||||||
* @return a KeyPair for the requested signature scheme code name.
|
* @return a KeyPair for the requested signature scheme code name.
|
||||||
* @throws IllegalArgumentException if the requested signature scheme is not supported.
|
* @throws IllegalArgumentException if the requested signature scheme is not supported.
|
||||||
*/
|
*/
|
||||||
@Throws(IllegalArgumentException::class)
|
@JvmStatic
|
||||||
fun generateKeyPair(schemeCodeName: String): KeyPair = generateKeyPair(findSignatureScheme(schemeCodeName))
|
fun generateKeyPair(schemeCodeName: String): KeyPair = generateKeyPair(findSignatureScheme(schemeCodeName))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -570,10 +643,12 @@ object Crypto {
|
|||||||
* @return a new [KeyPair] for the requested [SignatureScheme].
|
* @return a new [KeyPair] for the requested [SignatureScheme].
|
||||||
* @throws IllegalArgumentException if the requested signature scheme is not supported.
|
* @throws IllegalArgumentException if the requested signature scheme is not supported.
|
||||||
*/
|
*/
|
||||||
@Throws(IllegalArgumentException::class)
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
|
@JvmStatic
|
||||||
fun generateKeyPair(signatureScheme: SignatureScheme = DEFAULT_SIGNATURE_SCHEME): KeyPair {
|
fun generateKeyPair(signatureScheme: SignatureScheme = DEFAULT_SIGNATURE_SCHEME): KeyPair {
|
||||||
require(isSupportedSignatureScheme(signatureScheme)) { "Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}" }
|
require(isSupportedSignatureScheme(signatureScheme)) {
|
||||||
|
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
|
||||||
|
}
|
||||||
val keyPairGenerator = KeyPairGenerator.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName])
|
val keyPairGenerator = KeyPairGenerator.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName])
|
||||||
if (signatureScheme.algSpec != null)
|
if (signatureScheme.algSpec != null)
|
||||||
keyPairGenerator.initialize(signatureScheme.algSpec, newSecureRandom())
|
keyPairGenerator.initialize(signatureScheme.algSpec, newSecureRandom())
|
||||||
@ -638,13 +713,17 @@ object Crypto {
|
|||||||
* @throws IllegalArgumentException if the requested signature scheme is not supported.
|
* @throws IllegalArgumentException if the requested signature scheme is not supported.
|
||||||
* @throws UnsupportedOperationException if deterministic key generation is not supported for this particular scheme.
|
* @throws UnsupportedOperationException if deterministic key generation is not supported for this particular scheme.
|
||||||
*/
|
*/
|
||||||
|
@JvmStatic
|
||||||
fun deriveKeyPair(signatureScheme: SignatureScheme, privateKey: PrivateKey, seed: ByteArray): KeyPair {
|
fun deriveKeyPair(signatureScheme: SignatureScheme, privateKey: PrivateKey, seed: ByteArray): KeyPair {
|
||||||
require(isSupportedSignatureScheme(signatureScheme)) { "Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}" }
|
require(isSupportedSignatureScheme(signatureScheme)) {
|
||||||
when (signatureScheme) {
|
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
|
||||||
ECDSA_SECP256R1_SHA256, ECDSA_SECP256K1_SHA256 -> return deriveKeyPairECDSA(signatureScheme.algSpec as ECParameterSpec, privateKey, seed)
|
}
|
||||||
EDDSA_ED25519_SHA512 -> return deriveKeyPairEdDSA(privateKey, seed)
|
return when (signatureScheme) {
|
||||||
|
ECDSA_SECP256R1_SHA256, ECDSA_SECP256K1_SHA256 -> deriveKeyPairECDSA(signatureScheme.algSpec as ECParameterSpec, privateKey, seed)
|
||||||
|
EDDSA_ED25519_SHA512 -> deriveKeyPairEdDSA(privateKey, seed)
|
||||||
|
else -> throw UnsupportedOperationException("Although supported for signing, deterministic key derivation is " +
|
||||||
|
"not currently implemented for ${signatureScheme.schemeCodeName}")
|
||||||
}
|
}
|
||||||
throw UnsupportedOperationException("Although supported for signing, deterministic key derivation is not currently implemented for ${signatureScheme.schemeCodeName}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -656,6 +735,7 @@ object Crypto {
|
|||||||
* @throws IllegalArgumentException if the requested signature scheme is not supported.
|
* @throws IllegalArgumentException if the requested signature scheme is not supported.
|
||||||
* @throws UnsupportedOperationException if deterministic key generation is not supported for this particular scheme.
|
* @throws UnsupportedOperationException if deterministic key generation is not supported for this particular scheme.
|
||||||
*/
|
*/
|
||||||
|
@JvmStatic
|
||||||
fun deriveKeyPair(privateKey: PrivateKey, seed: ByteArray): KeyPair {
|
fun deriveKeyPair(privateKey: PrivateKey, seed: ByteArray): KeyPair {
|
||||||
return deriveKeyPair(findSignatureScheme(privateKey), privateKey, seed)
|
return deriveKeyPair(findSignatureScheme(privateKey), privateKey, seed)
|
||||||
}
|
}
|
||||||
@ -728,11 +808,13 @@ object Crypto {
|
|||||||
* @return a new [KeyPair] from an entropy input.
|
* @return a new [KeyPair] from an entropy input.
|
||||||
* @throws IllegalArgumentException if the requested signature scheme is not supported for KeyPair generation using an entropy input.
|
* @throws IllegalArgumentException if the requested signature scheme is not supported for KeyPair generation using an entropy input.
|
||||||
*/
|
*/
|
||||||
|
@JvmStatic
|
||||||
fun deriveKeyPairFromEntropy(signatureScheme: SignatureScheme, entropy: BigInteger): KeyPair {
|
fun deriveKeyPairFromEntropy(signatureScheme: SignatureScheme, entropy: BigInteger): KeyPair {
|
||||||
when (signatureScheme) {
|
return when (signatureScheme) {
|
||||||
EDDSA_ED25519_SHA512 -> return deriveEdDSAKeyPairFromEntropy(entropy)
|
EDDSA_ED25519_SHA512 -> deriveEdDSAKeyPairFromEntropy(entropy)
|
||||||
|
else -> throw IllegalArgumentException("Unsupported signature scheme for fixed entropy-based key pair " +
|
||||||
|
"generation: ${signatureScheme.schemeCodeName}")
|
||||||
}
|
}
|
||||||
throw IllegalArgumentException("Unsupported signature scheme for fixed entropy-based key pair generation: ${signatureScheme.schemeCodeName}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -740,6 +822,7 @@ object Crypto {
|
|||||||
* @param entropy a [BigInteger] value.
|
* @param entropy a [BigInteger] value.
|
||||||
* @return a new [KeyPair] from an entropy input.
|
* @return a new [KeyPair] from an entropy input.
|
||||||
*/
|
*/
|
||||||
|
@JvmStatic
|
||||||
fun deriveKeyPairFromEntropy(entropy: BigInteger): KeyPair = deriveKeyPairFromEntropy(DEFAULT_SIGNATURE_SCHEME, entropy)
|
fun deriveKeyPairFromEntropy(entropy: BigInteger): KeyPair = deriveKeyPairFromEntropy(DEFAULT_SIGNATURE_SCHEME, entropy)
|
||||||
|
|
||||||
// custom key pair generator from entropy.
|
// custom key pair generator from entropy.
|
||||||
@ -766,8 +849,12 @@ object Crypto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class KeyInfoConverter(val signatureScheme: SignatureScheme) : AsymmetricKeyInfoConverter {
|
private class KeyInfoConverter(val signatureScheme: SignatureScheme) : AsymmetricKeyInfoConverter {
|
||||||
override fun generatePublic(keyInfo: SubjectPublicKeyInfo?): PublicKey? = keyInfo?.let { decodePublicKey(signatureScheme, it.encoded) }
|
override fun generatePublic(keyInfo: SubjectPublicKeyInfo?): PublicKey? {
|
||||||
override fun generatePrivate(keyInfo: PrivateKeyInfo?): PrivateKey? = keyInfo?.let { decodePrivateKey(signatureScheme, it.encoded) }
|
return keyInfo?.let { decodePublicKey(signatureScheme, it.encoded) }
|
||||||
|
}
|
||||||
|
override fun generatePrivate(keyInfo: PrivateKeyInfo?): PrivateKey? {
|
||||||
|
return keyInfo?.let { decodePrivateKey(signatureScheme, it.encoded) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -784,22 +871,29 @@ object Crypto {
|
|||||||
* @return true if the point lies on the curve or false if it doesn't.
|
* @return true if the point lies on the curve or false if it doesn't.
|
||||||
* @throws IllegalArgumentException if the requested signature scheme or the key type is not supported.
|
* @throws IllegalArgumentException if the requested signature scheme or the key type is not supported.
|
||||||
*/
|
*/
|
||||||
@Throws(IllegalArgumentException::class)
|
@JvmStatic
|
||||||
fun publicKeyOnCurve(signatureScheme: SignatureScheme, publicKey: PublicKey): Boolean {
|
fun publicKeyOnCurve(signatureScheme: SignatureScheme, publicKey: PublicKey): Boolean {
|
||||||
require(isSupportedSignatureScheme(signatureScheme)) { "Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}" }
|
require(isSupportedSignatureScheme(signatureScheme)) {
|
||||||
when (publicKey) {
|
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
|
||||||
is BCECPublicKey -> return (publicKey.parameters == signatureScheme.algSpec && !publicKey.q.isInfinity && publicKey.q.isValid)
|
}
|
||||||
is EdDSAPublicKey -> return (publicKey.params == signatureScheme.algSpec && !isEdDSAPointAtInfinity(publicKey) && publicKey.a.isOnCurve)
|
return when (publicKey) {
|
||||||
|
is BCECPublicKey -> publicKey.parameters == signatureScheme.algSpec && !publicKey.q.isInfinity && publicKey.q.isValid
|
||||||
|
is EdDSAPublicKey -> publicKey.params == signatureScheme.algSpec && !isEdDSAPointAtInfinity(publicKey) && publicKey.a.isOnCurve
|
||||||
else -> throw IllegalArgumentException("Unsupported key type: ${publicKey::class}")
|
else -> throw IllegalArgumentException("Unsupported key type: ${publicKey::class}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
// For EdDSA a custom function is required as it is not supported by the I2P implementation.
|
||||||
private fun isEdDSAPointAtInfinity(publicKey: EdDSAPublicKey) = publicKey.a.toP3() == (EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec).curve.getZero(GroupElement.Representation.P3)
|
private fun isEdDSAPointAtInfinity(publicKey: EdDSAPublicKey): Boolean {
|
||||||
|
return publicKey.a.toP3() == (EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec).curve.getZero(GroupElement.Representation.P3)
|
||||||
|
}
|
||||||
|
|
||||||
/** Check if the requested [SignatureScheme] is supported by the system. */
|
/** Check if the requested [SignatureScheme] is supported by the system. */
|
||||||
fun isSupportedSignatureScheme(signatureScheme: SignatureScheme): Boolean = supportedSignatureSchemes[signatureScheme.schemeCodeName] === signatureScheme
|
@JvmStatic
|
||||||
|
fun isSupportedSignatureScheme(signatureScheme: SignatureScheme): Boolean {
|
||||||
|
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 {
|
private fun validateKey(signatureScheme: SignatureScheme, key: Key): Boolean {
|
||||||
@ -812,19 +906,19 @@ 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 {
|
private fun validatePublicKey(signatureScheme: SignatureScheme, key: PublicKey): Boolean {
|
||||||
when (key) {
|
return when (key) {
|
||||||
is BCECPublicKey, is EdDSAPublicKey -> return publicKeyOnCurve(signatureScheme, key)
|
is BCECPublicKey, is EdDSAPublicKey -> publicKeyOnCurve(signatureScheme, key)
|
||||||
is BCRSAPublicKey, is BCSphincs256PublicKey -> return true // TODO: Check if non-ECC keys satisfy params (i.e. approved/valid RSA modulus size).
|
is BCRSAPublicKey, is BCSphincs256PublicKey -> true // TODO: Check if non-ECC keys satisfy params (i.e. approved/valid RSA modulus size).
|
||||||
else -> throw IllegalArgumentException("Unsupported key type: ${key::class}")
|
else -> throw IllegalArgumentException("Unsupported key type: ${key::class}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if a private key satisfies algorithm specs.
|
// check if a private key satisfies algorithm specs.
|
||||||
private fun validatePrivateKey(signatureScheme: SignatureScheme, key: PrivateKey): Boolean {
|
private fun validatePrivateKey(signatureScheme: SignatureScheme, key: PrivateKey): Boolean {
|
||||||
when (key) {
|
return when (key) {
|
||||||
is BCECPrivateKey -> return key.parameters == signatureScheme.algSpec
|
is BCECPrivateKey -> key.parameters == signatureScheme.algSpec
|
||||||
is EdDSAPrivateKey -> return key.params == signatureScheme.algSpec
|
is EdDSAPrivateKey -> key.params == signatureScheme.algSpec
|
||||||
is BCRSAPrivateKey, is BCSphincs256PrivateKey -> return true // TODO: Check if non-ECC keys satisfy params (i.e. approved/valid RSA modulus size).
|
is BCRSAPrivateKey, is BCSphincs256PrivateKey -> true // TODO: Check if non-ECC keys satisfy params (i.e. approved/valid RSA modulus size).
|
||||||
else -> throw IllegalArgumentException("Unsupported key type: ${key::class}")
|
else -> throw IllegalArgumentException("Unsupported key type: ${key::class}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -838,21 +932,20 @@ object Crypto {
|
|||||||
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
||||||
* is inappropriate for a supported key factory to produce a private key.
|
* is inappropriate for a supported key factory to produce a private key.
|
||||||
*/
|
*/
|
||||||
fun toSupportedPublicKey(key: SubjectPublicKeyInfo): PublicKey {
|
@JvmStatic
|
||||||
return Crypto.decodePublicKey(key.encoded)
|
fun toSupportedPublicKey(key: SubjectPublicKeyInfo): PublicKey = decodePublicKey(key.encoded)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a public key to a supported implementation. This can be used to convert a SUN's EC key to an BC key.
|
* Convert a public key to a supported implementation. This can be used to convert a SUN's EC key to an BC key.
|
||||||
* This method is usually required to retrieve a key (via its corresponding cert) from JKS keystores that by default return SUN implementations.
|
* This method is usually required to retrieve a key (via its corresponding cert) from JKS keystores that by default
|
||||||
|
* return SUN implementations.
|
||||||
* @param key a public key.
|
* @param key a public key.
|
||||||
* @return a supported implementation of the input public key.
|
* @return a supported implementation of the input public key.
|
||||||
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
||||||
* is inappropriate for a supported key factory to produce a private key.
|
* is inappropriate for a supported key factory to produce a private key.
|
||||||
*/
|
*/
|
||||||
fun toSupportedPublicKey(key: PublicKey): PublicKey {
|
@JvmStatic
|
||||||
return Crypto.decodePublicKey(key.encoded)
|
fun toSupportedPublicKey(key: PublicKey): PublicKey = decodePublicKey(key.encoded)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a private key to a supported implementation. This can be used to convert a SUN's EC key to an BC key.
|
* Convert a private key to a supported implementation. This can be used to convert a SUN's EC key to an BC key.
|
||||||
@ -862,7 +955,6 @@ object Crypto {
|
|||||||
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
* @throws IllegalArgumentException on not supported scheme or if the given key specification
|
||||||
* is inappropriate for a supported key factory to produce a private key.
|
* is inappropriate for a supported key factory to produce a private key.
|
||||||
*/
|
*/
|
||||||
fun toSupportedPrivateKey(key: PrivateKey): PrivateKey {
|
@JvmStatic
|
||||||
return Crypto.decodePrivateKey(key.encoded)
|
fun toSupportedPrivateKey(key: PrivateKey): PrivateKey = decodePrivateKey(key.encoded)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ class CompositeKey private constructor(val threshold: Int, children: List<NodeAn
|
|||||||
|
|
||||||
fun getInstance(asn1: ASN1Primitive): PublicKey {
|
fun getInstance(asn1: ASN1Primitive): PublicKey {
|
||||||
val keyInfo = SubjectPublicKeyInfo.getInstance(asn1)
|
val keyInfo = SubjectPublicKeyInfo.getInstance(asn1)
|
||||||
require(keyInfo.algorithm.algorithm == CordaObjectIdentifier.compositeKey)
|
require(keyInfo.algorithm.algorithm == CordaObjectIdentifier.COMPOSITE_KEY)
|
||||||
val sequence = ASN1Sequence.getInstance(keyInfo.parsePublicKey())
|
val sequence = ASN1Sequence.getInstance(keyInfo.parsePublicKey())
|
||||||
val threshold = ASN1Integer.getInstance(sequence.getObjectAt(0)).positiveValue.toInt()
|
val threshold = ASN1Integer.getInstance(sequence.getObjectAt(0)).positiveValue.toInt()
|
||||||
val sequenceOfChildren = ASN1Sequence.getInstance(sequence.getObjectAt(1))
|
val sequenceOfChildren = ASN1Sequence.getInstance(sequence.getObjectAt(1))
|
||||||
@ -177,7 +177,7 @@ class CompositeKey private constructor(val threshold: Int, children: List<NodeAn
|
|||||||
}
|
}
|
||||||
keyVector.add(ASN1Integer(threshold.toLong()))
|
keyVector.add(ASN1Integer(threshold.toLong()))
|
||||||
keyVector.add(DERSequence(childrenVector))
|
keyVector.add(DERSequence(childrenVector))
|
||||||
return SubjectPublicKeyInfo(AlgorithmIdentifier(CordaObjectIdentifier.compositeKey), DERSequence(keyVector)).encoded
|
return SubjectPublicKeyInfo(AlgorithmIdentifier(CordaObjectIdentifier.COMPOSITE_KEY), DERSequence(keyVector)).encoded
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFormat() = ASN1Encoding.DER
|
override fun getFormat() = ASN1Encoding.DER
|
||||||
|
@ -11,7 +11,7 @@ import java.security.spec.AlgorithmParameterSpec
|
|||||||
*/
|
*/
|
||||||
class CompositeSignature : Signature(SIGNATURE_ALGORITHM) {
|
class CompositeSignature : Signature(SIGNATURE_ALGORITHM) {
|
||||||
companion object {
|
companion object {
|
||||||
val SIGNATURE_ALGORITHM = "COMPOSITESIG"
|
const val SIGNATURE_ALGORITHM = "COMPOSITESIG"
|
||||||
fun getService(provider: Provider) = Provider.Service(provider, "Signature", SIGNATURE_ALGORITHM, CompositeSignature::class.java.name, emptyList(), emptyMap())
|
fun getService(provider: Provider) = Provider.Service(provider, "Signature", SIGNATURE_ALGORITHM, CompositeSignature::class.java.name, emptyList(), emptyMap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,14 +3,13 @@ package net.corda.core.crypto.provider
|
|||||||
import net.corda.core.crypto.composite.CompositeKey
|
import net.corda.core.crypto.composite.CompositeKey
|
||||||
import net.corda.core.crypto.composite.CompositeSignature
|
import net.corda.core.crypto.composite.CompositeSignature
|
||||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier
|
import org.bouncycastle.asn1.ASN1ObjectIdentifier
|
||||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier
|
|
||||||
import java.security.AccessController
|
import java.security.AccessController
|
||||||
import java.security.PrivilegedAction
|
import java.security.PrivilegedAction
|
||||||
import java.security.Provider
|
import java.security.Provider
|
||||||
|
|
||||||
class CordaSecurityProvider : Provider(PROVIDER_NAME, 0.1, "$PROVIDER_NAME security provider wrapper") {
|
class CordaSecurityProvider : Provider(PROVIDER_NAME, 0.1, "$PROVIDER_NAME security provider wrapper") {
|
||||||
companion object {
|
companion object {
|
||||||
val PROVIDER_NAME = "Corda"
|
const val PROVIDER_NAME = "Corda"
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -21,7 +20,7 @@ class CordaSecurityProvider : Provider(PROVIDER_NAME, 0.1, "$PROVIDER_NAME secur
|
|||||||
put("KeyFactory.${CompositeKey.KEY_ALGORITHM}", "net.corda.core.crypto.composite.KeyFactory")
|
put("KeyFactory.${CompositeKey.KEY_ALGORITHM}", "net.corda.core.crypto.composite.KeyFactory")
|
||||||
put("Signature.${CompositeSignature.SIGNATURE_ALGORITHM}", "net.corda.core.crypto.composite.CompositeSignature")
|
put("Signature.${CompositeSignature.SIGNATURE_ALGORITHM}", "net.corda.core.crypto.composite.CompositeSignature")
|
||||||
|
|
||||||
val compositeKeyOID = CordaObjectIdentifier.compositeKey.id
|
val compositeKeyOID = CordaObjectIdentifier.COMPOSITE_KEY.id
|
||||||
put("Alg.Alias.KeyFactory.$compositeKeyOID", CompositeKey.KEY_ALGORITHM)
|
put("Alg.Alias.KeyFactory.$compositeKeyOID", CompositeKey.KEY_ALGORITHM)
|
||||||
put("Alg.Alias.KeyFactory.OID.$compositeKeyOID", CompositeKey.KEY_ALGORITHM)
|
put("Alg.Alias.KeyFactory.OID.$compositeKeyOID", CompositeKey.KEY_ALGORITHM)
|
||||||
put("Alg.Alias.Signature.$compositeKeyOID", CompositeSignature.SIGNATURE_ALGORITHM)
|
put("Alg.Alias.Signature.$compositeKeyOID", CompositeSignature.SIGNATURE_ALGORITHM)
|
||||||
@ -32,6 +31,6 @@ class CordaSecurityProvider : Provider(PROVIDER_NAME, 0.1, "$PROVIDER_NAME secur
|
|||||||
object CordaObjectIdentifier {
|
object CordaObjectIdentifier {
|
||||||
// UUID-based OID
|
// UUID-based OID
|
||||||
// TODO: Register for an OID space and issue our own shorter OID
|
// TODO: Register for an OID space and issue our own shorter OID
|
||||||
val compositeKey = ASN1ObjectIdentifier("2.25.30086077608615255153862931087626791002")
|
@JvmField val COMPOSITE_KEY = ASN1ObjectIdentifier("2.25.30086077608615255153862931087626791002")
|
||||||
val compositeSignature = ASN1ObjectIdentifier("2.25.30086077608615255153862931087626791003")
|
@JvmField val COMPOSITE_SIGNATURE = ASN1ObjectIdentifier("2.25.30086077608615255153862931087626791003")
|
||||||
}
|
}
|
||||||
|
@ -343,7 +343,7 @@ class CryptoUtilsTest {
|
|||||||
// test list of supported algorithms
|
// test list of supported algorithms
|
||||||
@Test
|
@Test
|
||||||
fun `Check supported algorithms`() {
|
fun `Check supported algorithms`() {
|
||||||
val algList: List<String> = Crypto.supportedSignatureSchemes.keys.toList()
|
val algList: List<String> = Crypto.supportedSignatureSchemes().map { it.schemeCodeName }
|
||||||
val expectedAlgSet = setOf("RSA_SHA256", "ECDSA_SECP256K1_SHA256", "ECDSA_SECP256R1_SHA256", "EDDSA_ED25519_SHA512", "SPHINCS-256_SHA512", "COMPOSITE")
|
val expectedAlgSet = setOf("RSA_SHA256", "ECDSA_SECP256K1_SHA256", "ECDSA_SECP256R1_SHA256", "EDDSA_ED25519_SHA512", "SPHINCS-256_SHA512", "COMPOSITE")
|
||||||
assertTrue { Sets.symmetricDifference(expectedAlgSet, algList.toSet()).isEmpty(); }
|
assertTrue { Sets.symmetricDifference(expectedAlgSet, algList.toSet()).isEmpty(); }
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ object X509Utilities {
|
|||||||
nameConstraints: NameConstraints? = null): X509CertificateHolder {
|
nameConstraints: NameConstraints? = null): X509CertificateHolder {
|
||||||
|
|
||||||
val signatureScheme = Crypto.findSignatureScheme(issuerKeyPair.private)
|
val signatureScheme = Crypto.findSignatureScheme(issuerKeyPair.private)
|
||||||
val provider = Crypto.providerMap[signatureScheme.providerName]
|
val provider = Crypto.findProvider(signatureScheme.providerName)
|
||||||
val builder = createCertificate(certificateType, issuer, subject, subjectPublicKey, validityWindow, nameConstraints)
|
val builder = createCertificate(certificateType, issuer, subject, subjectPublicKey, validityWindow, nameConstraints)
|
||||||
|
|
||||||
val signer = ContentSignerBuilder.build(signatureScheme, issuerKeyPair.private, provider)
|
val signer = ContentSignerBuilder.build(signatureScheme, issuerKeyPair.private, provider)
|
||||||
@ -225,7 +225,7 @@ object X509Utilities {
|
|||||||
* Create certificate signing request using provided information.
|
* Create certificate signing request using provided information.
|
||||||
*/
|
*/
|
||||||
fun createCertificateSigningRequest(subject: X500Name, keyPair: KeyPair, signatureScheme: SignatureScheme): PKCS10CertificationRequest {
|
fun createCertificateSigningRequest(subject: X500Name, keyPair: KeyPair, signatureScheme: SignatureScheme): PKCS10CertificationRequest {
|
||||||
val signer = ContentSignerBuilder.build(signatureScheme, keyPair.private, Crypto.providerMap[signatureScheme.providerName])
|
val signer = ContentSignerBuilder.build(signatureScheme, keyPair.private, Crypto.findProvider(signatureScheme.providerName))
|
||||||
return JcaPKCS10CertificationRequestBuilder(subject, keyPair.public).build(signer)
|
return JcaPKCS10CertificationRequestBuilder(subject, keyPair.public).build(signer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user