Merged andrius-crypto-refactor into master

This commit is contained in:
Andrius Dagys 2016-09-22 18:07:31 +01:00
commit ac57c5cf86
3 changed files with 84 additions and 76 deletions

View File

@ -1,9 +1,6 @@
package com.r3corda.core.crypto package com.r3corda.core.crypto
import com.google.common.io.BaseEncoding
import com.r3corda.core.serialization.OpaqueBytes import com.r3corda.core.serialization.OpaqueBytes
import com.r3corda.core.serialization.SerializedBytes
import com.r3corda.core.serialization.deserialize
import net.i2p.crypto.eddsa.EdDSAEngine import net.i2p.crypto.eddsa.EdDSAEngine
import net.i2p.crypto.eddsa.EdDSAPrivateKey import net.i2p.crypto.eddsa.EdDSAPrivateKey
import net.i2p.crypto.eddsa.EdDSAPublicKey import net.i2p.crypto.eddsa.EdDSAPublicKey
@ -22,45 +19,6 @@ fun newSecureRandom(): SecureRandom {
} }
} }
// "sealed" here means there can't be any subclasses other than the ones defined here.
sealed class SecureHash(bits: ByteArray) : OpaqueBytes(bits) {
class SHA256(bits: ByteArray) : SecureHash(bits) {
init {
require(bits.size == 32)
}
override val signatureAlgorithmName: String get() = "SHA256withECDSA"
}
override fun toString() = BaseEncoding.base16().encode(bits)
fun prefixChars(prefixLen: Int = 6) = toString().substring(0, prefixLen)
// Like static methods in Java, except the 'companion' is a singleton that can have state.
companion object {
@JvmStatic
fun parse(str: String) = BaseEncoding.base16().decode(str.toUpperCase()).let {
when (it.size) {
32 -> SHA256(it)
else -> throw IllegalArgumentException("Provided string is ${it.size} bytes not 32 bytes in hex: $str")
}
}
@JvmStatic fun sha256(bits: ByteArray) = SHA256(MessageDigest.getInstance("SHA-256").digest(bits))
@JvmStatic fun sha256Twice(bits: ByteArray) = sha256(sha256(bits).bits)
@JvmStatic fun sha256(str: String) = sha256(str.toByteArray())
@JvmStatic fun randomSHA256() = sha256(newSecureRandom().generateSeed(32))
}
abstract val signatureAlgorithmName: String
// In future, maybe SHA3, truncated hashes etc.
}
fun ByteArray.sha256(): SecureHash.SHA256 = SecureHash.sha256(this)
fun OpaqueBytes.sha256(): SecureHash.SHA256 = SecureHash.sha256(this.bits)
/** /**
* A wrapper around a digital signature. The covering field is a generic tag usable by whatever is interpreting the * A wrapper around a digital signature. The covering field is a generic tag usable by whatever is interpreting the
* signature. It isn't used currently, but experience from Bitcoin suggests such a feature is useful, especially when * signature. It isn't used currently, but experience from Bitcoin suggests such a feature is useful, especially when
@ -76,40 +34,6 @@ open class DigitalSignature(bits: ByteArray) : OpaqueBytes(bits) {
class LegallyIdentifiable(val signer: Party, bits: ByteArray) : WithKey(signer.owningKey, bits) class LegallyIdentifiable(val signer: Party, bits: ByteArray) : WithKey(signer.owningKey, bits)
} }
/**
* A serialized piece of data and its signature. Enforces signature validity in order to deserialize the data
* contained within.
*
* @param raw the raw serialized data.
* @param sig the (unverified) signature for the data.
*/
open class SignedData<T : Any>(val raw: SerializedBytes<T>, val sig: DigitalSignature.WithKey) {
/**
* Return the deserialized data if the signature can be verified.
*
* @throws IllegalArgumentException if the data is invalid (only used if verifyData() is overloaded).
* @throws SignatureException if the signature is invalid.
*/
@Throws(SignatureException::class)
fun verified(): T {
sig.by.verifyWithECDSA(raw.bits, sig)
val data = raw.deserialize()
verifyData(data)
return data
}
/**
* Verify the wrapped data after the signature has been verified and the data deserialised. Provided as an extension
* point for subclasses.
*
* @throws IllegalArgumentException if the data is invalid.
*/
@Throws(IllegalArgumentException::class)
open protected fun verifyData(data: T) {
// By default we accept anything
}
}
object NullPublicKey : PublicKey, Comparable<PublicKey> { object NullPublicKey : PublicKey, Comparable<PublicKey> {
override fun getAlgorithm() = "NULL" override fun getAlgorithm() = "NULL"
override fun getEncoded() = byteArrayOf(0) override fun getEncoded() = byteArrayOf(0)
@ -179,6 +103,7 @@ fun Iterable<PublicKey>.toStringsShort(): String = map { it.toStringShort() }.to
// Allow Kotlin destructuring: val (private, public) = keyPair // Allow Kotlin destructuring: val (private, public) = keyPair
operator fun KeyPair.component1() = this.private 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 */

View File

@ -0,0 +1,44 @@
package com.r3corda.core.crypto
import com.google.common.io.BaseEncoding
import com.r3corda.core.serialization.OpaqueBytes
import java.security.MessageDigest
/**
* Container for a cryptographically secure hash value.
* Provides utilities for generating a cryptographic hash using different algorithms (currently only SHA-256 supported).
*/
sealed class SecureHash(bits: ByteArray) : OpaqueBytes(bits) {
/** SHA-256 is part of the SHA-2 hash function family. Generated hash is fixed size, 256-bits (32-bytes) */
class SHA256(bits: ByteArray) : SecureHash(bits) {
init {
require(bits.size == 32)
}
}
override fun toString() = BaseEncoding.base16().encode(bits)
fun prefixChars(prefixLen: Int = 6) = toString().substring(0, prefixLen)
// Like static methods in Java, except the 'companion' is a singleton that can have state.
companion object {
@JvmStatic
fun parse(str: String) = BaseEncoding.base16().decode(str.toUpperCase()).let {
when (it.size) {
32 -> SHA256(it)
else -> throw IllegalArgumentException("Provided string is ${it.size} bytes not 32 bytes in hex: $str")
}
}
@JvmStatic fun sha256(bits: ByteArray) = SHA256(MessageDigest.getInstance("SHA-256").digest(bits))
@JvmStatic fun sha256Twice(bits: ByteArray) = sha256(sha256(bits).bits)
@JvmStatic fun sha256(str: String) = sha256(str.toByteArray())
@JvmStatic fun randomSHA256() = sha256(newSecureRandom().generateSeed(32))
}
// In future, maybe SHA3, truncated hashes etc.
}
fun ByteArray.sha256(): SecureHash.SHA256 = SecureHash.sha256(this)
fun OpaqueBytes.sha256(): SecureHash.SHA256 = SecureHash.sha256(this.bits)

View File

@ -0,0 +1,39 @@
package com.r3corda.core.crypto
import com.r3corda.core.serialization.SerializedBytes
import com.r3corda.core.serialization.deserialize
import java.security.SignatureException
/**
* A serialized piece of data and its signature. Enforces signature validity in order to deserialize the data
* contained within.
*
* @param raw the raw serialized data.
* @param sig the (unverified) signature for the data.
*/
open class SignedData<T : Any>(val raw: SerializedBytes<T>, val sig: DigitalSignature.WithKey) {
/**
* Return the deserialized data if the signature can be verified.
*
* @throws IllegalArgumentException if the data is invalid (only used if verifyData() is overloaded).
* @throws SignatureException if the signature is invalid.
*/
@Throws(SignatureException::class)
fun verified(): T {
sig.by.verifyWithECDSA(raw.bits, sig)
val data = raw.deserialize()
verifyData(data)
return data
}
/**
* Verify the wrapped data after the signature has been verified and the data deserialised. Provided as an extension
* point for subclasses.
*
* @throws IllegalArgumentException if the data is invalid.
*/
@Throws(IllegalArgumentException::class)
open protected fun verifyData(data: T) {
// By default we accept anything
}
}