Compare commits
6 Commits
a606a62eb4
...
55658f2b24
| Author | SHA1 | Date | |
|---|---|---|---|
|
55658f2b24
|
|||
|
08919cc9de
|
|||
|
150f37649d
|
|||
|
02eaa9ec59
|
|||
|
9480d02021
|
|||
|
f6f9625cf2
|
57
README.md
Normal file
57
README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Kotlin OTP
|
||||
|
||||
This library provides various [Pseudorandom Number Generator](https://en.wikipedia.org/wiki/Pseudorandom_number_generator)
|
||||
implementations in Kotlin Multiplatform.
|
||||
|
||||
## Features
|
||||
|
||||
* Generate random numbers using Kotlin's Random interface.
|
||||
* Seed the PRNGs to receive predictable results.
|
||||
* Reseed the PRNGs to add entropy to the following results.
|
||||
* [HMAC DRBG](https://en.wikipedia.org/wiki/NIST_SP_800-90A#Hash_DRBG_and_HMAC_DRBG)
|
||||
* Multiplatform support
|
||||
* JVM
|
||||
* JavaScript
|
||||
* Native (Linux)
|
||||
|
||||
## Installation
|
||||
|
||||
Add the following to your `build.gradle.kts`.
|
||||
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://git.infendro.com/api/packages/Infendro/maven")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("com.infendro:random:1.0.0")
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```kotlin
|
||||
import com.infendro.hash.SHA256
|
||||
import com.infendro.random.PRNG
|
||||
|
||||
fun main() {
|
||||
// create a PRNG instance
|
||||
val rng = PRNG.HMAC(SHA256)
|
||||
|
||||
// seed the PRNG to receive predictable results
|
||||
rng.seed(/* some seed */)
|
||||
val a = rng.nextInt()
|
||||
val b = rng.nextInt()
|
||||
val c = rng.nextInt()
|
||||
|
||||
// reseed the PRNG to add entropy to the following results
|
||||
rng.reseed(/* some random entropy */)
|
||||
val d = rng.nextInt()
|
||||
val e = rng.nextInt()
|
||||
val f = rng.nextInt()
|
||||
|
||||
// each run:
|
||||
// a, b, and c will be predictable
|
||||
// d, e, and f will be random (assuming the entropy is also random)
|
||||
}
|
||||
```
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
4
gradlew
vendored
4
gradlew
vendored
@@ -114,7 +114,7 @@ case "$( uname )" in #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
CLASSPATH="\\\"\\\""
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
||||
4
gradlew.bat
vendored
4
gradlew.bat
vendored
@@ -70,11 +70,11 @@ goto fail
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
set CLASSPATH=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
||||
@@ -1,26 +1,30 @@
|
||||
package com.infendro.random
|
||||
|
||||
import com.infendro.bytearray.toInt
|
||||
import com.infendro.hash.SHA256
|
||||
import com.infendro.mac.HMAC
|
||||
import kotlin.random.Random
|
||||
import com.infendro.bytearray.addAll
|
||||
import com.infendro.hash.HashFunction
|
||||
|
||||
class HMAC internal constructor() : Random() {
|
||||
class HMAC internal constructor(
|
||||
private val function: HashFunction,
|
||||
) : PRNG() {
|
||||
private val random = Default
|
||||
private val hmac = HMAC(SHA256)
|
||||
private var K: ByteArray
|
||||
private var V: ByteArray
|
||||
private val hmac = com.infendro.mac.HMAC(function)
|
||||
private lateinit var K: ByteArray
|
||||
private lateinit var V: ByteArray
|
||||
|
||||
init {
|
||||
K = ByteArray(32).also {
|
||||
random.nextBytes(it)
|
||||
}
|
||||
V = ByteArray(32).also {
|
||||
random.nextBytes(it)
|
||||
}
|
||||
val bytes = random.nextBytes(function.bytes)
|
||||
seed(bytes)
|
||||
}
|
||||
|
||||
fun reseed(
|
||||
override fun seed(
|
||||
seed: ByteArray,
|
||||
) {
|
||||
K = ByteArray(function.bytes) { 0x00 }
|
||||
V = ByteArray(function.bytes) { 0x01 }
|
||||
reseed(seed)
|
||||
}
|
||||
|
||||
override fun reseed(
|
||||
entropy: ByteArray,
|
||||
) {
|
||||
K = hmac.hash(K, V + byteArrayOf(0x00) + entropy)
|
||||
@@ -29,18 +33,21 @@ class HMAC internal constructor() : Random() {
|
||||
V = hmac.hash(K, V)
|
||||
}
|
||||
|
||||
override fun nextBits(
|
||||
override fun generate(
|
||||
count: Int,
|
||||
): Int {
|
||||
if (count !in 0..32) throw Exception()
|
||||
if (count == 0) return 0
|
||||
|
||||
val bytes = hmac.hash(K, V)
|
||||
val bits = bytes.take(4).toInt() ushr (32 - count)
|
||||
): ByteArray {
|
||||
val bytes = buildList {
|
||||
while (size < count) {
|
||||
V = hmac.hash(K, V)
|
||||
addAll(V)
|
||||
}
|
||||
}
|
||||
|
||||
K = hmac.hash(K, V + byteArrayOf(0x00))
|
||||
V = hmac.hash(K, V)
|
||||
|
||||
return bits
|
||||
return bytes
|
||||
.take(count)
|
||||
.toByteArray()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
package com.infendro.random
|
||||
|
||||
object PRNG {
|
||||
val HMAC = HMAC()
|
||||
import com.infendro.bytearray.toInt
|
||||
import com.infendro.hash.HashFunction
|
||||
import kotlin.random.Random
|
||||
|
||||
abstract class PRNG : Random() {
|
||||
abstract fun seed(
|
||||
seed: ByteArray,
|
||||
)
|
||||
|
||||
abstract fun reseed(
|
||||
entropy: ByteArray,
|
||||
)
|
||||
|
||||
abstract fun generate(
|
||||
count: Int,
|
||||
): ByteArray
|
||||
|
||||
override fun nextBits(
|
||||
bitCount: Int,
|
||||
): Int {
|
||||
if (bitCount !in 0..32) throw Exception()
|
||||
if (bitCount == 0) return 0
|
||||
|
||||
return generate(4).toInt() ushr (32 - bitCount)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun HMAC(
|
||||
function: HashFunction,
|
||||
): HMAC {
|
||||
return com.infendro.random.HMAC(function)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user