Skip to content
This repository has been archived by the owner on Nov 29, 2021. It is now read-only.

Commit

Permalink
add OS agnostic secure random
Browse files Browse the repository at this point in the history
  • Loading branch information
jmcardon committed Jul 30, 2018
1 parent a4f784e commit f611ef6
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 35 deletions.
41 changes: 11 additions & 30 deletions common/src/main/scala/tsec/common/ManagedRandom.scala
@@ -1,46 +1,27 @@
package tsec.common

import java.security.SecureRandom
import java.util.concurrent.atomic.LongAdder

/** A trait that manages a secureRandom instance.
*/
trait ManagedRandom {

private val SecureRandomAlgorithm = "NativePRNGNonBlocking"

/** Cache our random, and seed it properly as per
* [[https://tersesystems.com/2015/12/17/the-right-way-to-use-securerandom/]]
*/
private[tsec] var cachedRand: SecureRandom = {
val r = SecureRandom.getInstance(SecureRandomAlgorithm)
r.nextBytes(new Array[Byte](20))
private[tsec] val cachedRand: SecureRandom = {
val r = {
if (OSUtil.isWindows) new SecureRandom()
else SecureRandom.getInstance(ManagedRandom.UnixURandom)
}
r.nextBytes(new Array[Byte](20)) //Force reseed
r
}

/** We will keep a reference to how many times our random is utilized
* After a sensible Integer.MaxValue/5 times, we should reseed
*/
private val adder: LongAdder = new LongAdder
private val MaxBeforeReseed = (Integer.MAX_VALUE / 5).toLong

private def reSeed(): Unit = {
adder.reset()
val tmpRand = SecureRandom.getInstance(SecureRandomAlgorithm)
tmpRand.nextBytes(new Array[Byte](20))
cachedRand = tmpRand
}

private[tsec] def forceIncrement: Unit = {
adder.increment()
if (adder.sum() == MaxBeforeReseed)
reSeed()
}

def nextBytes(bytes: Array[Byte]): Unit = {
adder.increment()
if (adder.sum() == MaxBeforeReseed)
reSeed()
def nextBytes(bytes: Array[Byte]): Unit =
cachedRand.nextBytes(bytes)
}
}

object ManagedRandom {
private[ManagedRandom] val UnixURandom = "NativePRNGNonBlocking"
}
35 changes: 35 additions & 0 deletions common/src/main/scala/tsec/common/OSUtil.scala
@@ -0,0 +1,35 @@
package tsec.common

import java.security.{AccessController, PrivilegedAction}
import java.util.Locale

object OSUtil {

lazy val isWindows: Boolean = {
OSUtil.getSystemProperty("os.name", "").toLowerCase(Locale.US).contains("win")
}

lazy val isOsx: Boolean = {
val osName = OSUtil
.getSystemProperty("os.name", "")
.toLowerCase(Locale.US)
.replaceAll("[^a-z0-9]+", "")

osName.startsWith("macosx") || osName.startsWith("osx")
}

def getSystemProperty(key: String, default: String): String = {
if (key == null) throw new NullPointerException("key")
if (key.isEmpty) throw new IllegalArgumentException("key must not be empty.")
try if (System.getSecurityManager == null) System.getProperty(key)
else
AccessController.doPrivileged(new PrivilegedAction[String]() {
override def run: String = System.getProperty(key)
})
catch {
case e: SecurityException =>
default
}
}

}
Expand Up @@ -9,10 +9,7 @@ private[tsec] object JBCryptUtil extends ManagedRandom {
* but make sure we increment the adder
* to reseed eventually if necessary
*/
def genSalt(logRounds: Int): String = {
val salt = JBCrypt.gensalt(logRounds, cachedRand)
forceIncrement
salt
}
def genSalt(logRounds: Int): String =
JBCrypt.gensalt(logRounds, cachedRand)

}

0 comments on commit f611ef6

Please sign in to comment.