Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 15 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# secure-random
# random
[![badge-license]][url-license]
[![badge-latest-release]][url-latest-release]

Expand All @@ -21,55 +21,21 @@
![badge-support-js-ir]
![badge-support-linux-arm]

Kotlin Multiplatform library for obtaining cryptographically
secure random data from the system.
A Kotlin Multiplatform library for obtaining cryptographically secure random data.

NOTE: For Jvm, `SecureRandom` extends `java.security.SecureRandom`
for interoperability.
The Linux/AndroidNative implementation was heavily inspired by [rust-random/getrandom][url-rust-random].

The Linux/AndroidNative implementation was heavily inspired by
[rust-random/getrandom][url-rust-random].
### Modules

### Example Usages
- [crypto-rand](library/crypto-rand/README.md)
- [sample](sample/README.md)

```kotlin
fun main() {
val sRandom = SecureRandom()

val bytes: ByteArray = try {
sRandom.nextBytesOf(count = 20)
} catch (e: SecRandomCopyException) {
e.printStackTrace()
return
}

println(bytes.toList())
}
```
### API Docs

```kotlin
fun main() {
val sRandom = SecureRandom()
val bytes = ByteArray(20)

try {
sRandom.nextBytesCopyTo(bytes)
} catch (e: SecRandomCopyException) {
e.printStackTrace()
return
}

println(bytes.toList())
}
```

### Samples

See the [sample](sample/README.md)
- [https://random.kotlincrypto.org][url-docs]

### Get Started


The best way to keep `KotlinCrypto` dependencies up to date is by using the
[version-catalog][url-version-catalog]. Alternatively, see below.

Expand All @@ -82,14 +48,14 @@ dependencies {
}
```

<!-- TAG_VERSION -->

```groovy
// build.gradle
<!-- TODO: Replace
```kotlin
// build.gradle.kts
dependencies {
implementation "org.kotlincrypto:secure-random:0.3.2"
implementation("org.kotlincrypto.random:crypto-rand:0.4.0")
}
```
-->

<!-- TAG_VERSION -->
[badge-latest-release]: https://img.shields.io/badge/latest--release-0.3.2-blue.svg?style=flat
Expand All @@ -116,9 +82,10 @@ dependencies {
[badge-support-js-ir]: https://img.shields.io/badge/support-[js--IR]-AAC4E0.svg?style=flat
[badge-support-linux-arm]: http://img.shields.io/badge/support-[LinuxArm]-2D3F6C.svg?style=flat

[url-latest-release]: https://github.com/KotlinCrypto/secure-random/releases/latest
[url-latest-release]: https://github.com/KotlinCrypto/random/releases/latest
[url-license]: https://www.apache.org/licenses/LICENSE-2.0.txt
[url-kotlin]: https://kotlinlang.org
[url-rust-random]: https://github.com/rust-random/getrandom
[url-version-catalog]: https://github.com/KotlinCrypto/version-catalog
[url-error]: https://github.com/KotlinCrypto/error
[url-docs]: https://random.kotlincrypto.org
2 changes: 1 addition & 1 deletion benchmarks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ workflow run on the [GitHub Actions][url-actions] tab of the repository.
./gradlew nativeHostBenchmark
```

[url-actions]: https://github.com/KotlinCrypto/crypto-rand/actions/
[url-actions]: https://github.com/KotlinCrypto/random/actions/
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
package org.kotlincrypto.benchmarks

import kotlinx.benchmark.*
import org.kotlincrypto.crypto.rand.CryptoRand
import org.kotlincrypto.random.CryptoRand

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
Expand Down
1 change: 1 addition & 0 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ plugins {
}

dependencies {
implementation(libs.gradle.dokka)
implementation(libs.gradle.kmp.configuration)
implementation(libs.gradle.kotlin)
implementation(libs.gradle.publish.maven)
Expand Down
45 changes: 45 additions & 0 deletions build-logic/src/main/kotlin/dokka.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2025 Matthew Nelson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
import org.jetbrains.dokka.DokkaConfiguration.Visibility
import org.jetbrains.dokka.gradle.DokkaTaskPartial
import java.net.URI

plugins {
id("org.jetbrains.dokka")
}

tasks.withType<DokkaTaskPartial>().configureEach {
suppressInheritedMembers = true

dokkaSourceSets.configureEach {
includes.from("README.md")
noStdlibLink = true

externalDocumentationLink {
url = URI("https://error.kotlincrypto.org/").toURL()
}

sourceLink {
localDirectory = rootDir
remoteUrl = URI("https://github.com/KotlinCrypto/random/tree/master").toURL()
remoteLineSuffix = "#L"
}

documentedVisibilities.set(setOf(
Visibility.PUBLIC,
))
}
}
7 changes: 2 additions & 5 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension
plugins {
alias(libs.plugins.benchmark) apply(false)
alias(libs.plugins.binary.compat)
alias(libs.plugins.dokka)
alias(libs.plugins.kotlin.multiplatform) apply(false)
}

Expand All @@ -27,18 +28,14 @@ allprojects {
findProperty("VERSION_NAME")?.let { version = it }
findProperty("POM_DESCRIPTION")?.let { description = it.toString() }

repositories {
mavenCentral()
}
repositories { mavenCentral() }
}

plugins.withType<YarnPlugin> {
the<YarnRootExtension>().lockFileDirectory = rootDir.resolve(".kotlin-js-store")
}

apiValidation {
// Only enable when selectively enabled targets are not being passed via cli.
// See https://github.com/Kotlin/binary-compatibility-validator/issues/269
@OptIn(kotlinx.validation.ExperimentalBCVApi::class)
klib.enabled = findProperty("KMP_TARGETS") == null

Expand Down
37 changes: 37 additions & 0 deletions gh-pages/publish.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env bash
# Copyright (c) 2025 Matthew Nelson
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -e

readonly DIR_SCRIPT="$( cd "$( dirname "$0" )" >/dev/null && pwd )"
readonly REPO_NAME="random"

trap 'rm -rf "$DIR_SCRIPT/$REPO_NAME"' EXIT

cd "$DIR_SCRIPT"
git clone -b gh-pages --single-branch https://github.com/KotlinCrypto/$REPO_NAME.git
rm -rf "$DIR_SCRIPT/$REPO_NAME/"*
echo "$REPO_NAME.kotlincrypto.org" > "$DIR_SCRIPT/$REPO_NAME/CNAME"

cd ..
./gradlew clean -DKMP_TARGETS_ALL
./gradlew dokkaHtmlMultiModule --no-build-cache -DKMP_TARGETS_ALL
cp -aR build/dokka/htmlMultiModule/* gh-pages/$REPO_NAME

cd "$DIR_SCRIPT/$REPO_NAME"
sed -i "s|module:|module:library/|g" "package-list"

git add --all
git commit -S --message "Update dokka docs"
git push
10 changes: 5 additions & 5 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ kotlin.native.ignoreDisabledTargets=true
SONATYPE_HOST=S01
RELEASE_SIGNING_ENABLED=true

GROUP=org.kotlincrypto
GROUP=org.kotlincrypto.random

POM_INCEPTION_YEAR=2023

POM_URL=https://github.com/KotlinCrypto/secure-random/
POM_SCM_URL=https://github.com/KotlinCrypto/secure-random/
POM_SCM_CONNECTION=scm:git:git://github.com/KotlinCrypto/secure-random.git
POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/KotlinCrypto/secure-random.git
POM_URL=https://github.com/KotlinCrypto/random/
POM_SCM_URL=https://github.com/KotlinCrypto/random/
POM_SCM_CONNECTION=scm:git:git://github.com/KotlinCrypto/random.git
POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/KotlinCrypto/random.git

POM_LICENCE_NAME=The Apache Software License, Version 2.0
POM_LICENCE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt
Expand Down
5 changes: 4 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
[versions]
gradle-benchmark = "0.4.11"
gradle-binary-compat = "0.16.3"
gradle-dokka = "1.9.20"
gradle-kmp-configuration = "0.3.2"
gradle-kotlin = "1.9.24"
gradle-publish-maven = "0.29.0"

kotlincrypto-error = "0.2.0"

[libraries]
gradle-dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "gradle-dokka" }
gradle-kmp-configuration = { module = "io.matthewnelson:gradle-kmp-configuration-plugin", version.ref = "gradle-kmp-configuration" }
gradle-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "gradle-kotlin" }
gradle-publish-maven = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "gradle-publish-maven" }

kotlincrypto-error = { module = "org.kotlincrypto:error", version.ref = "kotlincrypto-error" }

# tests
# tests & tooling
benchmark-runtime = { module = "org.jetbrains.kotlinx:kotlinx-benchmark-runtime", version.ref = "gradle-benchmark" }

[plugins]
benchmark = { id = "org.jetbrains.kotlinx.benchmark", version.ref = "gradle-benchmark" }
binary-compat = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "gradle-binary-compat" }
dokka = { id = "org.jetbrains.dokka", version.ref = "gradle-dokka" }
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "gradle-kotlin" }
19 changes: 19 additions & 0 deletions library/crypto-rand/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Module crypto-rand

Obtain cryptographically secure random bytes from system sources.

```kotlin
fun main() {
val bytes = try {
CryptoRand.Default.nextBytes(ByteArray(16))
} catch (e: RandomnessProcurementException) {
// Underlying platform APIs failed to procure data
// from system sources.
e.printStackTrace()
return
}

println(bytes.toList())
//
}
```
11 changes: 6 additions & 5 deletions library/crypto-rand/api/crypto-rand.api
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
public abstract class org/kotlincrypto/crypto/rand/CryptoRand {
public static final field Default Lorg/kotlincrypto/crypto/rand/CryptoRand$Default;
public abstract class org/kotlincrypto/random/CryptoRand {
public static final field Default Lorg/kotlincrypto/random/CryptoRand$Default;
protected fun <init> ()V
public abstract fun nextBytes ([B)[B
}

public final class org/kotlincrypto/crypto/rand/CryptoRand$Default : org/kotlincrypto/crypto/rand/CryptoRand {
public final class org/kotlincrypto/random/CryptoRand$Default : org/kotlincrypto/random/CryptoRand {
public fun nextBytes ([B)[B
public fun toString ()Ljava/lang/String;
}

public abstract interface annotation class org/kotlincrypto/crypto/rand/DelicateCryptoRandApi : java/lang/annotation/Annotation {
public abstract interface annotation class org/kotlincrypto/random/DelicateCryptoRandApi : java/lang/annotation/Annotation {
}

public final class org/kotlincrypto/crypto/rand/RNGException : java/security/GeneralSecurityException {
public final class org/kotlincrypto/random/RandomnessProcurementException : java/security/GeneralSecurityException {
public fun <init> ()V
public fun <init> (Ljava/lang/String;)V
public fun <init> (Ljava/lang/String;Ljava/lang/Throwable;)V
Expand Down
27 changes: 14 additions & 13 deletions library/crypto-rand/api/crypto-rand.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,25 @@
// - Show manifest properties: true
// - Show declarations: true

// Library unique name: <org.kotlincrypto:crypto-rand>
open annotation class org.kotlincrypto.crypto.rand/DelicateCryptoRandApi : kotlin/Annotation { // org.kotlincrypto.crypto.rand/DelicateCryptoRandApi|null[0]
constructor <init>() // org.kotlincrypto.crypto.rand/DelicateCryptoRandApi.<init>|<init>(){}[0]
// Library unique name: <org.kotlincrypto.random:crypto-rand>
open annotation class org.kotlincrypto.random/DelicateCryptoRandApi : kotlin/Annotation { // org.kotlincrypto.random/DelicateCryptoRandApi|null[0]
constructor <init>() // org.kotlincrypto.random/DelicateCryptoRandApi.<init>|<init>(){}[0]
}

abstract class org.kotlincrypto.crypto.rand/CryptoRand { // org.kotlincrypto.crypto.rand/CryptoRand|null[0]
constructor <init>() // org.kotlincrypto.crypto.rand/CryptoRand.<init>|<init>(){}[0]
abstract class org.kotlincrypto.random/CryptoRand { // org.kotlincrypto.random/CryptoRand|null[0]
constructor <init>() // org.kotlincrypto.random/CryptoRand.<init>|<init>(){}[0]

abstract fun nextBytes(kotlin/ByteArray): kotlin/ByteArray // org.kotlincrypto.crypto.rand/CryptoRand.nextBytes|nextBytes(kotlin.ByteArray){}[0]
abstract fun nextBytes(kotlin/ByteArray): kotlin/ByteArray // org.kotlincrypto.random/CryptoRand.nextBytes|nextBytes(kotlin.ByteArray){}[0]

final object Default : org.kotlincrypto.crypto.rand/CryptoRand { // org.kotlincrypto.crypto.rand/CryptoRand.Default|null[0]
final fun nextBytes(kotlin/ByteArray): kotlin/ByteArray // org.kotlincrypto.crypto.rand/CryptoRand.Default.nextBytes|nextBytes(kotlin.ByteArray){}[0]
final object Default : org.kotlincrypto.random/CryptoRand { // org.kotlincrypto.random/CryptoRand.Default|null[0]
final fun nextBytes(kotlin/ByteArray): kotlin/ByteArray // org.kotlincrypto.random/CryptoRand.Default.nextBytes|nextBytes(kotlin.ByteArray){}[0]
final fun toString(): kotlin/String // org.kotlincrypto.random/CryptoRand.Default.toString|toString(){}[0]
}
}

final class org.kotlincrypto.crypto.rand/RNGException : org.kotlincrypto.error/GeneralSecurityException { // org.kotlincrypto.crypto.rand/RNGException|null[0]
constructor <init>() // org.kotlincrypto.crypto.rand/RNGException.<init>|<init>(){}[0]
constructor <init>(kotlin/String?) // org.kotlincrypto.crypto.rand/RNGException.<init>|<init>(kotlin.String?){}[0]
constructor <init>(kotlin/String?, kotlin/Throwable?) // org.kotlincrypto.crypto.rand/RNGException.<init>|<init>(kotlin.String?;kotlin.Throwable?){}[0]
constructor <init>(kotlin/Throwable?) // org.kotlincrypto.crypto.rand/RNGException.<init>|<init>(kotlin.Throwable?){}[0]
final class org.kotlincrypto.random/RandomnessProcurementException : org.kotlincrypto.error/GeneralSecurityException { // org.kotlincrypto.random/RandomnessProcurementException|null[0]
constructor <init>() // org.kotlincrypto.random/RandomnessProcurementException.<init>|<init>(){}[0]
constructor <init>(kotlin/String?) // org.kotlincrypto.random/RandomnessProcurementException.<init>|<init>(kotlin.String?){}[0]
constructor <init>(kotlin/String?, kotlin/Throwable?) // org.kotlincrypto.random/RandomnessProcurementException.<init>|<init>(kotlin.String?;kotlin.Throwable?){}[0]
constructor <init>(kotlin/Throwable?) // org.kotlincrypto.random/RandomnessProcurementException.<init>|<init>(kotlin.Throwable?){}[0]
}
Loading