mirror of
https://github.com/corda/corda.git
synced 2025-01-17 18:29:49 +00:00
commit
cb1b274d5c
@ -67,6 +67,9 @@ dependencies {
|
|||||||
// For JSON
|
// For JSON
|
||||||
compile "com.fasterxml.jackson.core:jackson-databind:2.5.5"
|
compile "com.fasterxml.jackson.core:jackson-databind:2.5.5"
|
||||||
|
|
||||||
|
// Java ed25519 implementation. See https://github.com/str4d/ed25519-java/
|
||||||
|
compile 'net.i2p.crypto:eddsa:0.1.0'
|
||||||
|
|
||||||
// Quasar: for the bytecode rewriting for state machines.
|
// Quasar: for the bytecode rewriting for state machines.
|
||||||
quasar "co.paralleluniverse:quasar-core:${quasar_version}:jdk8@jar"
|
quasar "co.paralleluniverse:quasar-core:${quasar_version}:jdk8@jar"
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package com.r3corda.core.crypto
|
package com.r3corda.core.crypto
|
||||||
|
|
||||||
import com.google.common.io.BaseEncoding
|
import com.google.common.io.BaseEncoding
|
||||||
import com.r3corda.core.crypto.Party
|
|
||||||
import com.r3corda.core.serialization.OpaqueBytes
|
import com.r3corda.core.serialization.OpaqueBytes
|
||||||
import com.r3corda.core.serialization.SerializedBytes
|
import com.r3corda.core.serialization.SerializedBytes
|
||||||
import com.r3corda.core.serialization.deserialize
|
import com.r3corda.core.serialization.deserialize
|
||||||
|
import net.i2p.crypto.eddsa.EdDSAEngine
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
import java.security.*
|
import java.security.*
|
||||||
import java.security.interfaces.ECPublicKey
|
import java.security.interfaces.ECPublicKey
|
||||||
|
import net.i2p.crypto.eddsa.KeyPairGenerator as EddsaKeyPairGenerator
|
||||||
|
|
||||||
// "sealed" here means there can't be any subclasses other than the ones defined here.
|
// "sealed" here means there can't be any subclasses other than the ones defined here.
|
||||||
sealed class SecureHash private constructor(bits: ByteArray) : OpaqueBytes(bits) {
|
sealed class SecureHash private constructor(bits: ByteArray) : OpaqueBytes(bits) {
|
||||||
@ -118,7 +119,7 @@ class DummyPublicKey(val s: String) : PublicKey, Comparable<PublicKey> {
|
|||||||
|
|
||||||
/** Utility to simplify the act of signing a byte array */
|
/** Utility to simplify the act of signing a byte array */
|
||||||
fun PrivateKey.signWithECDSA(bits: ByteArray): DigitalSignature {
|
fun PrivateKey.signWithECDSA(bits: ByteArray): DigitalSignature {
|
||||||
val signer = Signature.getInstance("SHA256withECDSA")
|
val signer = EdDSAEngine()
|
||||||
signer.initSign(this)
|
signer.initSign(this)
|
||||||
signer.update(bits)
|
signer.update(bits)
|
||||||
val sig = signer.sign()
|
val sig = signer.sign()
|
||||||
@ -140,7 +141,7 @@ fun KeyPair.signWithECDSA(bitsToSign: ByteArray, party: Party): DigitalSignature
|
|||||||
|
|
||||||
/** Utility to simplify the act of verifying a signature */
|
/** Utility to simplify the act of verifying a signature */
|
||||||
fun PublicKey.verifyWithECDSA(content: ByteArray, signature: DigitalSignature) {
|
fun PublicKey.verifyWithECDSA(content: ByteArray, signature: DigitalSignature) {
|
||||||
val verifier = Signature.getInstance("SHA256withECDSA")
|
val verifier = EdDSAEngine()
|
||||||
verifier.initVerify(this)
|
verifier.initVerify(this)
|
||||||
verifier.update(content)
|
verifier.update(content)
|
||||||
if (verifier.verify(signature.bits) == false)
|
if (verifier.verify(signature.bits) == false)
|
||||||
@ -160,4 +161,4 @@ operator fun KeyPair.component1() = this.private
|
|||||||
operator fun KeyPair.component2() = this.public
|
operator fun KeyPair.component2() = this.public
|
||||||
|
|
||||||
/** A simple wrapper that will make it easier to swap out the EC algorithm we use in future */
|
/** A simple wrapper that will make it easier to swap out the EC algorithm we use in future */
|
||||||
fun generateKeyPair() = KeyPairGenerator.getInstance("EC").genKeyPair()
|
fun generateKeyPair() = EddsaKeyPairGenerator().generateKeyPair()
|
@ -17,6 +17,11 @@ import com.r3corda.core.crypto.sha256
|
|||||||
import com.r3corda.core.node.AttachmentsClassLoader
|
import com.r3corda.core.node.AttachmentsClassLoader
|
||||||
import com.r3corda.core.node.services.AttachmentStorage
|
import com.r3corda.core.node.services.AttachmentStorage
|
||||||
import de.javakaffee.kryoserializers.ArraysAsListSerializer
|
import de.javakaffee.kryoserializers.ArraysAsListSerializer
|
||||||
|
import net.i2p.crypto.eddsa.EdDSAPrivateKey
|
||||||
|
import net.i2p.crypto.eddsa.EdDSAPublicKey
|
||||||
|
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable
|
||||||
|
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec
|
||||||
|
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec
|
||||||
import org.objenesis.strategy.StdInstantiatorStrategy
|
import org.objenesis.strategy.StdInstantiatorStrategy
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.ObjectInputStream
|
import java.io.ObjectInputStream
|
||||||
@ -29,6 +34,7 @@ import java.util.*
|
|||||||
import javax.annotation.concurrent.ThreadSafe
|
import javax.annotation.concurrent.ThreadSafe
|
||||||
import kotlin.reflect.*
|
import kotlin.reflect.*
|
||||||
import kotlin.reflect.jvm.javaType
|
import kotlin.reflect.jvm.javaType
|
||||||
|
import java.security.PrivateKey
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialization utilities, using the Kryo framework with a custom serialiser for immutable data classes and a dead
|
* Serialization utilities, using the Kryo framework with a custom serialiser for immutable data classes and a dead
|
||||||
@ -205,6 +211,16 @@ inline fun <T> Kryo.useClassLoader(cl: ClassLoader, body: () -> T) : T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun Output.writeBytesWithLength(byteArray: ByteArray) {
|
||||||
|
this.writeInt(byteArray.size, true)
|
||||||
|
this.writeBytes(byteArray)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun Input.readBytesWithLength(): ByteArray {
|
||||||
|
val size = this.readInt(true)
|
||||||
|
return this.readBytes(size)
|
||||||
|
}
|
||||||
|
|
||||||
/** Thrown during deserialisation to indicate that an attachment needed to construct the [WireTransaction] is not found */
|
/** Thrown during deserialisation to indicate that an attachment needed to construct the [WireTransaction] is not found */
|
||||||
class MissingAttachmentsException(val ids: List<SecureHash>) : Exception()
|
class MissingAttachmentsException(val ids: List<SecureHash>) : Exception()
|
||||||
|
|
||||||
@ -250,6 +266,39 @@ object WireTransactionSerializer : Serializer<WireTransaction>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** For serialising an ed25519 private key */
|
||||||
|
@ThreadSafe
|
||||||
|
object Ed25519PrivateKeySerializer : Serializer<EdDSAPrivateKey>() {
|
||||||
|
val ed25519Curve = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512)
|
||||||
|
|
||||||
|
override fun write(kryo: Kryo, output: Output, obj: EdDSAPrivateKey) {
|
||||||
|
check(obj.params == ed25519Curve)
|
||||||
|
output.writeBytesWithLength(obj.seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(kryo: Kryo, input: Input, type: Class<EdDSAPrivateKey>): EdDSAPrivateKey {
|
||||||
|
val seed = input.readBytesWithLength()
|
||||||
|
return EdDSAPrivateKey(EdDSAPrivateKeySpec(seed, ed25519Curve))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** For serialising an ed25519 public key */
|
||||||
|
@ThreadSafe
|
||||||
|
object Ed25519PublicKeySerializer : Serializer<EdDSAPublicKey>() {
|
||||||
|
val ed25519Curve = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512)
|
||||||
|
|
||||||
|
override fun write(kryo: Kryo, output: Output, obj: EdDSAPublicKey) {
|
||||||
|
check(obj.params == ed25519Curve)
|
||||||
|
output.writeBytesWithLength(obj.abyte)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(kryo: Kryo, input: Input, type: Class<EdDSAPublicKey>): EdDSAPublicKey {
|
||||||
|
val A = input.readBytesWithLength()
|
||||||
|
return EdDSAPublicKey(EdDSAPublicKeySpec(A, ed25519Curve))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun createKryo(k: Kryo = Kryo()): Kryo {
|
fun createKryo(k: Kryo = Kryo()): Kryo {
|
||||||
return k.apply {
|
return k.apply {
|
||||||
// Allow any class to be deserialized (this is insecure but for prototyping we don't care)
|
// Allow any class to be deserialized (this is insecure but for prototyping we don't care)
|
||||||
@ -273,8 +322,8 @@ fun createKryo(k: Kryo = Kryo()): Kryo {
|
|||||||
|
|
||||||
// Some things where the JRE provides an efficient custom serialisation.
|
// Some things where the JRE provides an efficient custom serialisation.
|
||||||
val keyPair = generateKeyPair()
|
val keyPair = generateKeyPair()
|
||||||
register(keyPair.public.javaClass, ReferencesAwareJavaSerializer)
|
register(keyPair.public.javaClass, Ed25519PublicKeySerializer)
|
||||||
register(keyPair.private.javaClass, ReferencesAwareJavaSerializer)
|
register(keyPair.private.javaClass, Ed25519PrivateKeySerializer)
|
||||||
register(Instant::class.java, ReferencesAwareJavaSerializer)
|
register(Instant::class.java, ReferencesAwareJavaSerializer)
|
||||||
|
|
||||||
// Some classes have to be handled with the ImmutableClassSerializer because they need to have their
|
// Some classes have to be handled with the ImmutableClassSerializer because they need to have their
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
package com.r3corda.core.serialization
|
package com.r3corda.core.serialization
|
||||||
|
|
||||||
import com.google.common.primitives.Ints
|
import com.google.common.primitives.Ints
|
||||||
|
import com.r3corda.core.crypto.generateKeyPair
|
||||||
|
import com.r3corda.core.crypto.signWithECDSA
|
||||||
|
import com.r3corda.core.crypto.verifyWithECDSA
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -54,6 +58,21 @@ class KryoTests {
|
|||||||
assertThat(bits.deserialize(kryo)).isEqualTo(cyclic)
|
assertThat(bits.deserialize(kryo)).isEqualTo(cyclic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `deserialised keypair functions the same as serialised one`() {
|
||||||
|
val keyPair = generateKeyPair()
|
||||||
|
val bitsToSign: ByteArray = Ints.toByteArray(0x01234567)
|
||||||
|
val wrongBits: ByteArray = Ints.toByteArray(0x76543210)
|
||||||
|
val signature = keyPair.signWithECDSA(bitsToSign)
|
||||||
|
signature.verifyWithECDSA(bitsToSign)
|
||||||
|
assertThatThrownBy { signature.verifyWithECDSA(wrongBits) }
|
||||||
|
|
||||||
|
val deserialisedKeyPair = keyPair.serialize(kryo).deserialize(kryo)
|
||||||
|
val deserialisedSignature = deserialisedKeyPair.signWithECDSA(bitsToSign)
|
||||||
|
assertThat(deserialisedSignature).isEqualTo(signature)
|
||||||
|
deserialisedSignature.verifyWithECDSA(bitsToSign)
|
||||||
|
assertThatThrownBy { deserialisedSignature.verifyWithECDSA(wrongBits) }
|
||||||
|
}
|
||||||
|
|
||||||
private data class Person(val name: String, val birthday: Instant?)
|
private data class Person(val name: String, val birthday: Instant?)
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ Here are changes in git master that haven't yet made it to a snapshot release:
|
|||||||
* Amount class is now generic, to support non-currency types (such as assets, or currency with additional information).
|
* Amount class is now generic, to support non-currency types (such as assets, or currency with additional information).
|
||||||
* Refactored the Cash contract to have a new FungibleAsset superclass, to model all countable assets that can be merged
|
* Refactored the Cash contract to have a new FungibleAsset superclass, to model all countable assets that can be merged
|
||||||
and split (currency, barrels of oil, etc.)
|
and split (currency, barrels of oil, etc.)
|
||||||
|
* Switched to the ed25519 elliptic curve from secp256r1. Note that this introduces a new external lib dependency.
|
||||||
|
|
||||||
Milestone 0
|
Milestone 0
|
||||||
-----------
|
-----------
|
||||||
|
Loading…
Reference in New Issue
Block a user