Add newSecureRandom() that uses a non-blocking SecureRandom provider on Linux

This commit is contained in:
Andras Slemmer 2016-06-16 17:06:01 +01:00
parent 0c325c31a2
commit a7419b116d
8 changed files with 27 additions and 12 deletions

View File

@ -3,6 +3,7 @@ package com.r3corda.contracts.cash
import com.r3corda.core.contracts.* import com.r3corda.core.contracts.*
import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.Party
import com.r3corda.core.crypto.SecureHash import com.r3corda.core.crypto.SecureHash
import com.r3corda.core.crypto.newSecureRandom
import com.r3corda.core.crypto.toStringShort import com.r3corda.core.crypto.toStringShort
import com.r3corda.core.utilities.Emoji import com.r3corda.core.utilities.Emoji
import java.security.PublicKey import java.security.PublicKey
@ -74,7 +75,7 @@ class Cash : FungibleAsset<Currency>() {
* Allows new cash states to be issued into existence: the nonce ("number used once") ensures the transaction * Allows new cash states to be issued into existence: the nonce ("number used once") ensures the transaction
* has a unique ID even when there are no inputs. * has a unique ID even when there are no inputs.
*/ */
data class Issue(override val nonce: Long = SecureRandom.getInstanceStrong().nextLong()) : FungibleAsset.Commands.Issue data class Issue(override val nonce: Long = newSecureRandom().nextLong()) : FungibleAsset.Commands.Issue
/** /**
* A command stating that money has been withdrawn from the shared ledger and is now accounted for * A command stating that money has been withdrawn from the shared ledger and is now accounted for

View File

@ -4,6 +4,7 @@ import com.google.common.io.ByteStreams
import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.ListenableFuture
import com.google.common.util.concurrent.MoreExecutors import com.google.common.util.concurrent.MoreExecutors
import com.google.common.util.concurrent.SettableFuture import com.google.common.util.concurrent.SettableFuture
import com.r3corda.core.crypto.newSecureRandom
import org.slf4j.Logger import org.slf4j.Logger
import java.io.BufferedInputStream import java.io.BufferedInputStream
import java.io.InputStream import java.io.InputStream
@ -36,7 +37,7 @@ fun String.abbreviate(maxWidth: Int): String = if (length <= maxWidth) this else
* Returns a random positive long generated using a secure RNG. This function sacrifies a bit of entropy in order to * Returns a random positive long generated using a secure RNG. This function sacrifies a bit of entropy in order to
* avoid potential bugs where the value is used in a context where negative numbers are not expected. * avoid potential bugs where the value is used in a context where negative numbers are not expected.
*/ */
fun random63BitValue(): Long = Math.abs(SecureRandom.getInstanceStrong().nextLong()) fun random63BitValue(): Long = Math.abs(newSecureRandom().nextLong())
// Some utilities for working with Guava listenable futures. // Some utilities for working with Guava listenable futures.
fun <T> ListenableFuture<T>.then(executor: Executor, body: () -> Unit) = addListener(Runnable(body), executor) fun <T> ListenableFuture<T>.then(executor: Executor, body: () -> Unit) = addListener(Runnable(body), executor)
@ -200,4 +201,4 @@ fun extractZipFile(zipPath: Path, toPath: Path) {
} }
} }
// TODO: Generic csv printing utility for clases. // TODO: Generic csv printing utility for clases.

View File

@ -10,6 +10,14 @@ import java.security.*
import java.security.interfaces.ECPublicKey import java.security.interfaces.ECPublicKey
import net.i2p.crypto.eddsa.KeyPairGenerator as EddsaKeyPairGenerator import net.i2p.crypto.eddsa.KeyPairGenerator as EddsaKeyPairGenerator
fun newSecureRandom(): SecureRandom {
if (System.getProperty("os.name") == "Linux") {
return SecureRandom.getInstance("NativePRNGNonBlocking")
} else {
return SecureRandom.getInstanceStrong()
}
}
// "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) {
class SHA256(bits: ByteArray) : SecureHash(bits) { class SHA256(bits: ByteArray) : SecureHash(bits) {
@ -38,7 +46,7 @@ sealed class SecureHash private constructor(bits: ByteArray) : OpaqueBytes(bits)
@JvmStatic fun sha256Twice(bits: ByteArray) = sha256(sha256(bits).bits) @JvmStatic fun sha256Twice(bits: ByteArray) = sha256(sha256(bits).bits)
@JvmStatic fun sha256(str: String) = sha256(str.toByteArray()) @JvmStatic fun sha256(str: String) = sha256(str.toByteArray())
@JvmStatic fun randomSHA256() = sha256(SecureRandom.getInstanceStrong().generateSeed(32)) @JvmStatic fun randomSHA256() = sha256(newSecureRandom().generateSeed(32))
} }
abstract val signatureAlgorithmName: String abstract val signatureAlgorithmName: String
@ -161,4 +169,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() = EddsaKeyPairGenerator().generateKeyPair() fun generateKeyPair() = EddsaKeyPairGenerator().generateKeyPair()

View File

@ -1,5 +1,6 @@
package com.r3corda.core.contracts package com.r3corda.core.contracts
import com.r3corda.core.crypto.newSecureRandom
import com.r3corda.core.node.services.testing.MockTransactionStorage import com.r3corda.core.node.services.testing.MockTransactionStorage
import com.r3corda.core.testing.DUMMY_NOTARY import com.r3corda.core.testing.DUMMY_NOTARY
import com.r3corda.core.testing.MEGA_CORP_KEY import com.r3corda.core.testing.MEGA_CORP_KEY
@ -16,7 +17,7 @@ class TransactionGraphSearchTests {
} }
} }
fun random31BitValue(): Int = Math.abs(SecureRandom.getInstanceStrong().nextInt()) fun random31BitValue(): Int = Math.abs(newSecureRandom().nextInt())
/** /**
* Build a pair of transactions. The first issues a dummy output state, and has a command applied, the second then * Build a pair of transactions. The first issues a dummy output state, and has a command applied, the second then
@ -70,4 +71,4 @@ class TransactionGraphSearchTests {
assertEquals(expected, actual) assertEquals(expected, actual)
} }
} }

View File

@ -2,6 +2,7 @@ package com.r3corda.core.contracts
import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.Party
import com.r3corda.core.crypto.SecureHash import com.r3corda.core.crypto.SecureHash
import com.r3corda.core.crypto.newSecureRandom
import com.r3corda.core.node.services.testing.MockStorageService import com.r3corda.core.node.services.testing.MockStorageService
import com.r3corda.core.testing.* import com.r3corda.core.testing.*
import org.junit.Test import org.junit.Test
@ -33,7 +34,7 @@ class TransactionGroupTests {
} }
interface Commands : CommandData { interface Commands : CommandData {
class Move() : TypeOnlyCommandData(), Commands class Move() : TypeOnlyCommandData(), Commands
data class Issue(val nonce: Long = SecureRandom.getInstanceStrong().nextLong()) : Commands data class Issue(val nonce: Long = newSecureRandom().nextLong()) : Commands
data class Exit(val amount: Amount<Currency>) : Commands data class Exit(val amount: Amount<Currency>) : Commands
} }
} }
@ -178,4 +179,4 @@ class TransactionGroupTests {
}.toSet() }.toSet()
TransactionGroup(ltxns, emptySet()).verify() TransactionGroup(ltxns, emptySet()).verify()
} }
} }

View File

@ -3,6 +3,7 @@ package com.r3corda.core.serialization
import com.r3corda.core.contracts.* import com.r3corda.core.contracts.*
import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.Party
import com.r3corda.core.crypto.SecureHash import com.r3corda.core.crypto.SecureHash
import com.r3corda.core.crypto.newSecureRandom
import com.r3corda.core.node.services.testing.MockStorageService import com.r3corda.core.node.services.testing.MockStorageService
import com.r3corda.core.seconds import com.r3corda.core.seconds
import com.r3corda.core.testing.* import com.r3corda.core.testing.*
@ -34,7 +35,7 @@ class TransactionSerializationTests {
} }
interface Commands : CommandData { interface Commands : CommandData {
class Move() : TypeOnlyCommandData(), Commands class Move() : TypeOnlyCommandData(), Commands
data class Issue(val nonce: Long = SecureRandom.getInstanceStrong().nextLong()) : Commands data class Issue(val nonce: Long = newSecureRandom().nextLong()) : Commands
data class Exit(val amount: Amount<Currency>) : Commands data class Exit(val amount: Amount<Currency>) : Commands
} }
} }
@ -107,4 +108,4 @@ class TransactionSerializationTests {
assertEquals(tx.outputStates(), ltx.outputs) assertEquals(tx.outputStates(), ltx.outputs)
assertEquals(TEST_TX_TIME, ltx.commands.getTimestampBy(DUMMY_NOTARY)!!.midpoint) assertEquals(TEST_TX_TIME, ltx.commands.getTimestampBy(DUMMY_NOTARY)!!.midpoint)
} }
} }

View File

@ -44,6 +44,7 @@ import java.nio.file.FileAlreadyExistsException
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
import java.security.KeyPair import java.security.KeyPair
import java.security.Security
import java.time.Clock import java.time.Clock
import java.time.Instant import java.time.Instant
import java.util.* import java.util.*

View File

@ -3,6 +3,7 @@ package com.r3corda.node.services.messaging
import com.google.common.net.HostAndPort import com.google.common.net.HostAndPort
import com.r3corda.core.RunOnCallerThread import com.r3corda.core.RunOnCallerThread
import com.r3corda.core.ThreadBox import com.r3corda.core.ThreadBox
import com.r3corda.core.crypto.newSecureRandom
import com.r3corda.core.messaging.* import com.r3corda.core.messaging.*
import com.r3corda.core.serialization.SingletonSerializeAsToken import com.r3corda.core.serialization.SingletonSerializeAsToken
import com.r3corda.core.utilities.loggerFor import com.r3corda.core.utilities.loggerFor
@ -115,7 +116,7 @@ class ArtemisMessagingService(val directory: Path, val myHostPort: HostAndPort,
val config = createArtemisConfig(directory, myHostPort) val config = createArtemisConfig(directory, myHostPort)
mq.setConfiguration(config) mq.setConfiguration(config)
val secConfig = SecurityConfiguration() val secConfig = SecurityConfiguration()
val password = BigInteger(128, SecureRandom.getInstanceStrong()).toString(16) val password = BigInteger(128, newSecureRandom()).toString(16)
secConfig.addUser("internal", password) secConfig.addUser("internal", password)
secConfig.addRole("internal", "internal") secConfig.addRole("internal", "internal")
secConfig.defaultUser = "internal" secConfig.defaultUser = "internal"