From 2ff8d14491539440fb6a6f1c51457f3fbdacd87a Mon Sep 17 00:00:00 2001 From: Konstantinos Chalkias Date: Thu, 20 Apr 2017 15:25:28 +0100 Subject: [PATCH] add EdDSA Provider and update i2p dependency to 0.2.0 --- core/build.gradle | 2 +- .../kotlin/net/corda/core/crypto/Crypto.kt | 9 ++--- .../net/corda/core/crypto/CryptoUtils.kt | 4 +-- .../net/corda/core/crypto/EdDSAKeyFactory.kt | 10 ------ .../net/corda/core/crypto/CryptoUtilsTest.kt | 15 ++++---- .../net/corda/core/crypto/I2PProvider.kt | 34 +++++++++++++++++++ 6 files changed, 49 insertions(+), 25 deletions(-) delete mode 100644 core/src/main/kotlin/net/corda/core/crypto/EdDSAKeyFactory.kt create mode 100644 core/src/test/kotlin/net/corda/core/crypto/I2PProvider.kt diff --git a/core/build.gradle b/core/build.gradle index 70723cd41d..88ffa00d20 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -71,7 +71,7 @@ dependencies { compile "com.fasterxml.jackson.core:jackson-databind:${jackson_version}" // Java ed25519 implementation. See https://github.com/str4d/ed25519-java/ - compile 'net.i2p.crypto:eddsa:0.1.0' + compile 'net.i2p.crypto:eddsa:0.2.0' // Bouncy castle support needed for X509 certificate manipulation compile "org.bouncycastle:bcprov-jdk15on:${bouncycastle_version}" diff --git a/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt b/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt index d0e9f4b817..de19f3fb5e 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt @@ -29,6 +29,7 @@ import java.security.spec.X509EncodedKeySpec object Crypto { 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). } @@ -79,10 +80,10 @@ object Crypto { 4, "EDDSA_ED25519_SHA512", "EdDSA", - EdDSAEngine(), - EdDSAKeyFactory, - net.i2p.crypto.eddsa.KeyPairGenerator(), // EdDSA engine uses a custom KeyPairGenerator Vs BouncyCastle. - EdDSANamedCurveTable.getByName("ed25519-sha-512"), + Signature.getInstance("SHA512withEdDSA", "I2P"), + KeyFactory.getInstance("EdDSA", "I2P"), + KeyPairGenerator.getInstance("EdDSA", "I2P"), + EdDSANamedCurveTable.getByName("ED25519"), 256, "EdDSA signature scheme using the ed25519 twisted Edwards curve." ) diff --git a/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt b/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt index d2aee4fa2c..361ee1e752 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt @@ -53,7 +53,7 @@ fun PrivateKey.signWithECDSA(bytesToSign: ByteArray, publicKey: PublicKey): Digi return DigitalSignature.WithKey(publicKey, signWithECDSA(bytesToSign).bytes) } -val ed25519Curve: EdDSANamedCurveSpec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512) +val ed25519Curve: EdDSANamedCurveSpec = EdDSANamedCurveTable.getByName("ED25519") fun KeyPair.signWithECDSA(bytesToSign: ByteArray) = private.signWithECDSA(bytesToSign, public) fun KeyPair.signWithECDSA(bytesToSign: OpaqueBytes) = private.signWithECDSA(bytesToSign.bytes, public) @@ -150,7 +150,7 @@ fun generateKeyPair(): KeyPair = Crypto.generateKeyPair() * you want hard-coded private keys. */ fun entropyToKeyPair(entropy: BigInteger): KeyPair { - val params = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512) + val params = ed25519Curve val bytes = entropy.toByteArray().copyOf(params.curve.field.getb() / 8) val priv = EdDSAPrivateKeySpec(bytes, params) val pub = EdDSAPublicKeySpec(priv.a, params) diff --git a/core/src/main/kotlin/net/corda/core/crypto/EdDSAKeyFactory.kt b/core/src/main/kotlin/net/corda/core/crypto/EdDSAKeyFactory.kt deleted file mode 100644 index caefb44df2..0000000000 --- a/core/src/main/kotlin/net/corda/core/crypto/EdDSAKeyFactory.kt +++ /dev/null @@ -1,10 +0,0 @@ -package net.corda.core.crypto - -import java.security.KeyFactory - -/** - * Custom [KeyFactory] for EdDSA with null security [Provider]. - * This is required as a [SignatureScheme] requires a [java.security.KeyFactory] property, but i2p has - * its own KeyFactory for EdDSA, thus this actually a Proxy Pattern over i2p's KeyFactory. - */ -object EdDSAKeyFactory : KeyFactory(net.i2p.crypto.eddsa.KeyFactory(), null, "EDDSA_ED25519_SHA512") diff --git a/core/src/test/kotlin/net/corda/core/crypto/CryptoUtilsTest.kt b/core/src/test/kotlin/net/corda/core/crypto/CryptoUtilsTest.kt index 98eaffd387..f66b0bf899 100644 --- a/core/src/test/kotlin/net/corda/core/crypto/CryptoUtilsTest.kt +++ b/core/src/test/kotlin/net/corda/core/crypto/CryptoUtilsTest.kt @@ -2,8 +2,6 @@ package net.corda.core.crypto import com.google.common.collect.Sets import net.i2p.crypto.eddsa.EdDSAKey -import net.i2p.crypto.eddsa.EdDSAPrivateKey -import net.i2p.crypto.eddsa.EdDSAPublicKey import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable import org.bouncycastle.asn1.pkcs.PrivateKeyInfo import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo @@ -413,15 +411,16 @@ class CryptoUtilsTest { fun `EdDSA encode decode keys - required for serialization`() { // Generate key pair. val keyPair = Crypto.generateKeyPair("EDDSA_ED25519_SHA512") - val privKey: EdDSAPrivateKey = keyPair.private as EdDSAPrivateKey - val pubKey: EdDSAPublicKey = keyPair.public as EdDSAPublicKey + val (privKey, pubKey) = keyPair + + val kf = KeyFactory.getInstance("EDDSA", "I2P") // Encode and decode private key. - val privKey2 = EdDSAKeyFactory.generatePrivate(PKCS8EncodedKeySpec(privKey.encoded)) + val privKey2 = kf.generatePrivate(PKCS8EncodedKeySpec(privKey.encoded)) assertEquals(privKey2, privKey) // Encode and decode public key. - val pubKey2 = EdDSAKeyFactory.generatePublic(X509EncodedKeySpec(pubKey.encoded)) + val pubKey2 = kf.generatePublic(X509EncodedKeySpec(pubKey.encoded)) assertEquals(pubKey2, pubKey) } @@ -499,9 +498,9 @@ class CryptoUtilsTest { val (privEd, pubEd) = keyPairEd assertEquals(privEd.algorithm, "EdDSA") - assertEquals((privEd as EdDSAKey).params, EdDSANamedCurveTable.getByName("ed25519-sha-512")) + assertEquals((privEd as EdDSAKey).params, EdDSANamedCurveTable.getByName("ED25519")) assertEquals(pubEd.algorithm, "EdDSA") - assertEquals((pubEd as EdDSAKey).params, EdDSANamedCurveTable.getByName("ed25519-sha-512")) + assertEquals((pubEd as EdDSAKey).params, EdDSANamedCurveTable.getByName("ED25519")) } @Test diff --git a/core/src/test/kotlin/net/corda/core/crypto/I2PProvider.kt b/core/src/test/kotlin/net/corda/core/crypto/I2PProvider.kt new file mode 100644 index 0000000000..fafc8b2c92 --- /dev/null +++ b/core/src/test/kotlin/net/corda/core/crypto/I2PProvider.kt @@ -0,0 +1,34 @@ +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") + } +}