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
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
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
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
4
gradlew
vendored
4
gradlew
vendored
@@ -114,7 +114,7 @@ case "$( uname )" in #(
|
|||||||
NONSTOP* ) nonstop=true ;;
|
NONSTOP* ) nonstop=true ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH="\\\"\\\""
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
@@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
-classpath "$CLASSPATH" \
|
-classpath "$CLASSPATH" \
|
||||||
org.gradle.wrapper.GradleWrapperMain \
|
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||||
"$@"
|
"$@"
|
||||||
|
|
||||||
# Stop when "xargs" is not available.
|
# Stop when "xargs" is not available.
|
||||||
|
|||||||
4
gradlew.bat
vendored
4
gradlew.bat
vendored
@@ -70,11 +70,11 @@ goto fail
|
|||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
set CLASSPATH=
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@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
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
|||||||
@@ -1,26 +1,30 @@
|
|||||||
package com.infendro.random
|
package com.infendro.random
|
||||||
|
|
||||||
import com.infendro.bytearray.toInt
|
import com.infendro.bytearray.addAll
|
||||||
import com.infendro.hash.SHA256
|
import com.infendro.hash.HashFunction
|
||||||
import com.infendro.mac.HMAC
|
|
||||||
import kotlin.random.Random
|
|
||||||
|
|
||||||
class HMAC internal constructor() : Random() {
|
class HMAC internal constructor(
|
||||||
|
private val function: HashFunction,
|
||||||
|
) : PRNG() {
|
||||||
private val random = Default
|
private val random = Default
|
||||||
private val hmac = HMAC(SHA256)
|
private val hmac = com.infendro.mac.HMAC(function)
|
||||||
private var K: ByteArray
|
private lateinit var K: ByteArray
|
||||||
private var V: ByteArray
|
private lateinit var V: ByteArray
|
||||||
|
|
||||||
init {
|
init {
|
||||||
K = ByteArray(32).also {
|
val bytes = random.nextBytes(function.bytes)
|
||||||
random.nextBytes(it)
|
seed(bytes)
|
||||||
}
|
|
||||||
V = ByteArray(32).also {
|
|
||||||
random.nextBytes(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reseed(
|
override fun seed(
|
||||||
|
seed: ByteArray,
|
||||||
|
) {
|
||||||
|
K = ByteArray(function.bytes) { 0x00 }
|
||||||
|
V = ByteArray(function.bytes) { 0x01 }
|
||||||
|
reseed(seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reseed(
|
||||||
entropy: ByteArray,
|
entropy: ByteArray,
|
||||||
) {
|
) {
|
||||||
K = hmac.hash(K, V + byteArrayOf(0x00) + entropy)
|
K = hmac.hash(K, V + byteArrayOf(0x00) + entropy)
|
||||||
@@ -29,18 +33,21 @@ class HMAC internal constructor() : Random() {
|
|||||||
V = hmac.hash(K, V)
|
V = hmac.hash(K, V)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun nextBits(
|
override fun generate(
|
||||||
count: Int,
|
count: Int,
|
||||||
): Int {
|
): ByteArray {
|
||||||
if (count !in 0..32) throw Exception()
|
val bytes = buildList {
|
||||||
if (count == 0) return 0
|
while (size < count) {
|
||||||
|
V = hmac.hash(K, V)
|
||||||
val bytes = hmac.hash(K, V)
|
addAll(V)
|
||||||
val bits = bytes.take(4).toInt() ushr (32 - count)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
K = hmac.hash(K, V + byteArrayOf(0x00))
|
K = hmac.hash(K, V + byteArrayOf(0x00))
|
||||||
V = hmac.hash(K, V)
|
V = hmac.hash(K, V)
|
||||||
|
|
||||||
return bits
|
return bytes
|
||||||
|
.take(count)
|
||||||
|
.toByteArray()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,36 @@
|
|||||||
package com.infendro.random
|
package com.infendro.random
|
||||||
|
|
||||||
object PRNG {
|
import com.infendro.bytearray.toInt
|
||||||
val HMAC = HMAC()
|
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