Merge pull request #8 from ionspin/jna-android-and-java

Jna android and java
This commit is contained in:
Ugljesa Jovanovic 2021-02-24 08:56:12 +00:00 committed by GitHub
commit 6db7a828ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 1899 additions and 342 deletions

View File

@ -5,12 +5,26 @@
# Libsodium bindings for Kotiln Multiplatform
Libsodium bindings project uses libsodium c sources, libsodium.js as well as LazySodium Java and Android to provide a kotlin multiplatform wrapper library for libsodium.
Libsodium bindings project uses libsodium c sources and libsodium.js to provide a kotlin multiplatform wrapper library for libsodium.
## Installation
The libsodium binding library is not published yet, once the sample showing the basic usage is ready, the library will be published. You can track the implementation
[progress here](https://github.com/ionspin/kotlin-multiplatform-crypto/blob/master/supported_bindings_list.md)
#### Gradle
```kotlin
implementation("com.ionspin.kotlin:multiplatform-crypto-lisodium-bindings:0.8.0")
```
#### Snapshot builds
```kotlin
repositories {
maven {
url = uri("https://oss.sonatype.org/content/repositories/snapshots")
}
}
implementation("com.ionspin.kotlin:multiplatform-crypto-lisodium-bindings:0.8.1-SNAPSHOT ")
```
## Usage
@ -18,8 +32,7 @@ The libsodium binding library is not published yet, once the sample showing the
Before using the wrapper you need to initialize the underlying libsodium library. You can use either a callback or coroutines approach
```
= runTest {
LibsodiumInitializer.initializeWithCallback {
LibsodiumInitializer.initializeWithCallback {
// Libsodium initialized
}
```
@ -125,31 +138,20 @@ Currently supported native platforms:
|minGW X86 64| :heavy_check_mark: |
|minGW X86 32| :x: |
[List of supported bindings](https://github.com/ionspin/kotlin-multiplatform-crypto/blob/master/supported_bindings_list.md)
### Where do the compiled libraries used by JVM and Android come from
Android .so files come from running dist-build scripts in libsodium which you can find in the libsodium submodule
Java Linux Arm/X86_64 and Mac so and dylib are the same as produced by multiplatform builds, also based on the same submodule commit
Java Windows dll is from https://download.libsodium.org/libsodium/releases/libsodium-1.0.18-stable-msvc.zip
### TODO:
- Copy/adapt code documentation, currently only some functions have documentation that is a copy-paste from libsodium website
- Replace LazySodium with direct JNA calls, and add build scripts for required libraries if missing
- Android testing
- Fix browser testing, both locally and in CI/CD
- LobsodiumUtil `unpad` and `fromBase64` native implementations use a nasty hack to support shared native sourceset. The hack either needs to be removed and replaced with another solution or additional safeguards need to be added.
- Complete exposing libsodium constants
### Known issues:
- Using LazySodium self built variant to fix some of the bugs present in LazySodium, but **Android** is using directly
LazySodium release which has not been updated (latest version is 4.2.0), this means that randombytes_random, basetobin and
base64tohex functions are not working on Android, as well as problems with sodium_pad:
https://github.com/terl/lazysodium-java/issues/83
https://github.com/terl/lazysodium-java/issues/85
https://github.com/terl/lazysodium-java/issues/86
Also it is not clear where are the precompiled libraries in LazySodium coming from
This will be handled by providing a new JNA libsodium wrapper library
#### Notes for Gitlab runners:
- At the moment all runners need to have android sdk

View File

@ -24,14 +24,16 @@ object Versions {
val dokkaPlugin = "1.4.20"
val taskTreePlugin = "1.5"
val kotlinBigNumVersion = "0.2.8-SNAPSHOT"
val lazySodium = "4.3.1-SNAPSHOT"
val jna = "5.5.0"
val jna = "5.7.0"
val kotlinPoet = "1.6.0"
val libsodiumBindings = "0.1.1-SNAPSHOT"
val ktor = "1.3.2"
val timber = "4.7.1"
val kodeinVersion = "7.1.0"
val resourceLoader = "1.3.10"
}
@ -39,7 +41,7 @@ object Versions {
object ReleaseInfo {
val group = "com.ionspin.kotlin"
val version = "0.1.0-SNAPSHOT"
val bindingsVersion = "0.1.1-SNAPSHOT"
val bindingsVersion = "0.8.0-SNAPSHOT"
}
object Deps {
@ -112,11 +114,9 @@ object Deps {
val kotlinPoet = "com.squareup:kotlinpoet:${Versions.kotlinPoet}"
val resourceLoader = "co.libly:resource-loader:${Versions.resourceLoader}"
object Delegated {
// Temporary until reported lazysodium issues are fixed. My snapshot build with
// And cause I registered com.ionspin.kotlin as maven central package root now I have to use
// that even though this is pure java library. :)
val lazysodium = "com.ionspin.kotlin:lazysodium-java:${Versions.lazySodium}"
val jna = "net.java.dev.jna:jna:${Versions.jna}"
}
}
@ -139,6 +139,7 @@ object Deps {
val ktorClientSerialization = "io.ktor:ktor-client-serialization-jvm:${Versions.ktor}"
val serialization = "org.jetbrains.kotlinx:kotlinx-serialization-runtime:${Versions.kotlinSerialization}"
val timber = "com.jakewharton.timber:timber:${Versions.timber}"
val jna = "net.java.dev.jna:jna:${Versions.jna}@aar"
}
object Desktop {

View File

@ -48,7 +48,6 @@ val sonatypeUsernameEnv: String? = System.getenv()["SONATYPE_USERNAME"]
repositories {
mavenCentral()
jcenter()
maven("https://dl.bintray.com/terl/lazysodium-maven")
maven {
url = uri("https://oss.sonatype.org/content/repositories/snapshots")
}
@ -73,6 +72,9 @@ android {
isMinifyEnabled = false
}
}
sourceSets.getByName("main") {
// jniLibs.srcDir("src/androidMain/libs")
}
}
@ -80,9 +82,10 @@ android {
kotlin {
val hostOsName = getHostOsName()
android()
jvm()
runningOnLinuxx86_64 {
println("Configuring Linux X86-64 targets")
jvm()
js(IR) {
browser {
testTask {
@ -438,14 +441,16 @@ kotlin {
val androidMain by getting {
isNotRunningInIdea {
kotlin.srcDirs("src/androidSpecific", "src/jvmMain/kotlin")
kotlin.srcDirs("src/androidMain", "src/androidSpecific", "src/jvmMain/kotlin")
}
isRunningInIdea {
kotlin.srcDirs("src/androidSpecific")
kotlin.srcDirs("src/androidSpecific", "src/jvmMain/kotlin")
}
dependencies {
implementation("com.goterl.lazycode:lazysodium-android:4.2.0@aar")
implementation("net.java.dev.jna:jna:5.5.0@aar")
implementation(Deps.Jvm.resourceLoader) {
exclude("net.java.dev.jna", "jna")
}
}
}
@ -458,28 +463,30 @@ kotlin {
}
}
val jvmMain by getting {
kotlin.srcDirs("src/jvmSpecific", "src/jvmMain/kotlin")
dependencies {
implementation(kotlin(Deps.Jvm.stdLib))
implementation(kotlin(Deps.Jvm.test))
implementation(kotlin(Deps.Jvm.testJUnit))
implementation(Deps.Jvm.resourceLoader)
implementation(Deps.Jvm.Delegated.jna)
implementation("org.slf4j:slf4j-api:1.7.30")
}
}
val jvmTest by getting {
dependencies {
implementation(kotlin(Deps.Jvm.test))
implementation(kotlin(Deps.Jvm.testJUnit))
implementation(kotlin(Deps.Jvm.reflection))
}
}
runningOnLinuxx86_64 {
println("Configuring Linux 64 Bit source sets")
val jvmMain by getting {
kotlin.srcDirs("src/jvmSpecific", "src/jvmMain/kotlin")
dependencies {
implementation(kotlin(Deps.Jvm.stdLib))
implementation(kotlin(Deps.Jvm.test))
implementation(kotlin(Deps.Jvm.testJUnit))
//lazysodium
implementation(Deps.Jvm.Delegated.lazysodium)
implementation(Deps.Jvm.Delegated.jna)
}
}
val jvmTest by getting {
dependencies {
implementation(kotlin(Deps.Jvm.test))
implementation(kotlin(Deps.Jvm.testJUnit))
implementation(kotlin(Deps.Jvm.reflection))
}
}
val jsMain by getting {
@ -678,6 +685,13 @@ tasks {
}
allprojects {
tasks.withType(JavaCompile::class) {
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
}
}
signing {

View File

@ -1,12 +1,2 @@
package com.ionspin.kotlin.crypto
import com.goterl.lazycode.lazysodium.LazySodiumAndroid
import com.goterl.lazycode.lazysodium.SodiumAndroid
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 22-Aug-2020
*/
typealias SodiumWrapper = SodiumAndroid

View File

@ -9,13 +9,22 @@ const val crypto_stream_chacha20_KEYBYTES = 32
const val crypto_stream_chacha20_NONCEBYTES = 8
const val crypto_stream_chacha20_ietf_KEYBYTES = 32
const val crypto_stream_chacha20_ietf_NONCEBYTES = 12
const val crypto_stream_xchacha20_NONCEBYTES = 24
const val crypto_stream_xchacha20_KEYBYTES = 32
expect object Stream {
fun chacha20(clen: Int, nonce: UByteArray, key: UByteArray) : UByteArray
fun chacha20IetfXor(message : UByteArray, nonce: UByteArray, key: UByteArray) : UByteArray
fun chacha20IetfXorIc(message : UByteArray, nonce: UByteArray, initialCounter: ULong, key: UByteArray) : UByteArray
fun chacha20Keygen() : UByteArray
fun chacha20(clen: Int, nonce: UByteArray, key: UByteArray) : UByteArray
fun chacha20Xor(message : UByteArray, nonce: UByteArray, key: UByteArray) : UByteArray
fun chacha20XorIc(message : UByteArray, nonce: UByteArray, initialCounter: ULong, key: UByteArray) : UByteArray
fun chacha20IetfXor(message : UByteArray, nonce: UByteArray, key: UByteArray) : UByteArray
fun chacha20IetfXorIc(message : UByteArray, nonce: UByteArray, initialCounter: ULong, key: UByteArray) : UByteArray
// fun xChacha20Keygen() : UByteArray
//
// fun xChacha20Xor(message : UByteArray, nonce: UByteArray, key: UByteArray) : UByteArray
// fun xChacha20XorIc(message : UByteArray, nonce: UByteArray, initialCounter: ULong, key: UByteArray) : UByteArray
}

View File

@ -10,6 +10,9 @@ enum class Base64Variants(val value: Int) {
ORIGINAL(1), ORIGINAL_NO_PADDING(3), URLSAFE(5), URLSAFE_NO_PADDING(7)
}
class ConversionException() : RuntimeException("Conversion failed")
class PaddingException() : RuntimeException("Padding failed")
expect object LibsodiumUtil {
fun memcmp(first: UByteArray, second: UByteArray) : Boolean

View File

@ -68,4 +68,26 @@ class StreamTest {
}
}
}
// @Test
// fun testXChaCha20IetfStream() = runTest {
// LibsodiumInitializer.initializeWithCallback {
// val message = "This is a cha cha message".encodeToUByteArray()
// val nonce = LibsodiumRandom.bufDeterministic(crypto_stream_xchacha20_NONCEBYTES, seed)
// val key = Stream.xChacha20Keygen()
// val encryptedUsingLibsodium = Stream.xChacha20Xor(message, nonce, key)
// val encryptedUsingLibsodiumWithInitialCounter = Stream.xChacha20XorIc(message, nonce, 0U, key)
// println(encryptedUsingLibsodium.toHexString())
// println(encryptedUsingLibsodiumWithInitialCounter.toHexString())
// assertTrue {
// encryptedUsingLibsodium.contentEquals(encryptedUsingLibsodiumWithInitialCounter)
// }
// val decryptedUsingLibsodium = Stream.xChacha20Xor(encryptedUsingLibsodium, nonce, key)
// println(message.toHexString())
// println(decryptedUsingLibsodium.toHexString())
// assertTrue {
// decryptedUsingLibsodium.contentEquals(message)
// }
// }
// }
}

View File

@ -232,6 +232,10 @@ interface JsSodiumInterface {
fun crypto_stream_chacha20_xor(message : Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array
fun crypto_stream_chacha20_xor_ic(message : Uint8Array, nonce: Uint8Array, initialCounter: UInt, key: Uint8Array) : Uint8Array
fun crypto_stream_xchacha20_keygen() : Uint8Array
fun crypto_stream_xchacha20_xor(message : Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array
fun crypto_stream_xchacha20_xor_ic(message : Uint8Array, nonce: Uint8Array, initialCounter: UInt, key: Uint8Array) : Uint8Array
// ---- Stream end ----
// ---- Scalar multiplication ----

View File

@ -79,4 +79,42 @@ actual object Stream {
return result.toUByteArray()
}
// actual fun xChacha20Keygen(): UByteArray {
// val result = getSodium().crypto_stream_xchacha20_keygen()
//
// return result.toUByteArray()
// }
//
// actual fun xChacha20Xor(
// message: UByteArray,
// nonce: UByteArray,
// key: UByteArray
// ): UByteArray {
// val result = getSodium().crypto_stream_xchacha20_xor(
// message.toUInt8Array(),
// nonce.toUInt8Array(),
// key.toUInt8Array()
// )
//
// return result.toUByteArray()
// }
//
// actual fun xChacha20XorIc(
// message: UByteArray,
// nonce: UByteArray,
// initialCounter: ULong,
// key: UByteArray
// ): UByteArray {
// val result = getSodium().crypto_stream_xchacha20_xor_ic(
// message.toUInt8Array(),
// nonce.toUInt8Array(),
// initialCounter.toUInt(),
// key.toUInt8Array()
// )
//
// return result.toUByteArray()
// }
}

View File

@ -1,19 +1,59 @@
package com.ionspin.kotlin.crypto
import co.libly.resourceloader.FileLoader
import com.sun.jna.Native
import com.sun.jna.Platform
import java.io.File
import java.lang.RuntimeException
/**
* Created by Ugljesa Jovanovic (jovanovic.ugljesa@gmail.com) on 02/Aug/2020
*/
actual object LibsodiumInitializer {
private var isPlatformInitialized = false
lateinit var sodium : SodiumWrapper
private fun loadLibrary() : JnaLibsodiumInterface {
val libraryFile = when {
Platform.isMac() -> {
FileLoader.get().load("dynamic-macos-x86-64.dylib", Any::class.java)
}
Platform.isLinux() -> {
FileLoader.get().load("dynamic-linux-x86-64-libsodium.so", Any::class.java)
}
Platform.isWindows() -> {
FileLoader.get().load("dynamic-msvc-x86-64-libsodium.dll", Any::class.java)
}
Platform.isAndroid() -> {
when {
Platform.is64Bit() -> {
File("irrelevant")
}
else -> throw RuntimeException("Unsupported platform")
}
}
else -> throw RuntimeException("Unknown platform")
}
val library = if (Platform.isAndroid()) {
Native.load("sodium", JnaLibsodiumInterface::class.java) as JnaLibsodiumInterface
} else {
Native.load(libraryFile.absolutePath, JnaLibsodiumInterface::class.java) as JnaLibsodiumInterface
}
return library
}
lateinit var sodiumJna : JnaLibsodiumInterface
actual suspend fun initialize() {
sodium = SodiumWrapper()
sodiumJna = loadLibrary()
isPlatformInitialized = true
}
actual fun initializeWithCallback(done: () -> Unit) {
sodium = SodiumWrapper()
sodiumJna = loadLibrary()
isPlatformInitialized = true
done()
}

View File

@ -0,0 +1,10 @@
package com.ionspin.kotlin.crypto
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 21-Feb-2021
*/
object TmpAccessor {
fun getVersion() : String = LibsodiumInitializer.sodiumJna.sodium_version_string()
}

View File

@ -1,6 +1,6 @@
package com.ionspin.kotlin.crypto.aead
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
actual object AuthenticatedEncryptionWithAssociatedData {
@ -14,7 +14,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
key: UByteArray
): UByteArray {
val ciphertext = UByteArray(message.size + crypto_aead_xchacha20poly1305_ietf_ABYTES)
sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(
sodiumJna.crypto_aead_xchacha20poly1305_ietf_encrypt(
ciphertext.asByteArray(),
null,
message.asByteArray(),
@ -35,7 +35,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
key: UByteArray
): UByteArray {
val message = UByteArray(ciphertextAndTag.size - crypto_aead_xchacha20poly1305_ietf_ABYTES)
val validationResult = sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
val validationResult = sodiumJna.crypto_aead_xchacha20poly1305_ietf_decrypt(
message.asByteArray(),
null,
null,
@ -60,7 +60,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
): AeadEncryptedDataAndTag {
val ciphertext = UByteArray(message.size)
val authenticationTag = UByteArray(crypto_aead_xchacha20poly1305_ietf_ABYTES)
sodium.crypto_aead_xchacha20poly1305_ietf_encrypt_detached(
sodiumJna.crypto_aead_xchacha20poly1305_ietf_encrypt_detached(
ciphertext.asByteArray(),
authenticationTag.asByteArray(),
null,
@ -83,7 +83,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
key: UByteArray
): UByteArray {
val message = UByteArray(ciphertext.size)
val validationResult = sodium.crypto_aead_xchacha20poly1305_ietf_decrypt_detached(
val validationResult = sodiumJna.crypto_aead_xchacha20poly1305_ietf_decrypt_detached(
message.asByteArray(),
null,
ciphertext.asByteArray(),
@ -107,7 +107,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
key: UByteArray
): UByteArray {
val ciphertext = UByteArray(message.size + crypto_aead_chacha20poly1305_ietf_ABYTES)
sodium.crypto_aead_chacha20poly1305_ietf_encrypt(
sodiumJna.crypto_aead_chacha20poly1305_ietf_encrypt(
ciphertext.asByteArray(),
null,
message.asByteArray(),
@ -128,7 +128,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
key: UByteArray
): UByteArray {
val message = UByteArray(ciphertextAndTag.size - crypto_aead_chacha20poly1305_ietf_ABYTES)
val validationResult = sodium.crypto_aead_chacha20poly1305_ietf_decrypt(
val validationResult = sodiumJna.crypto_aead_chacha20poly1305_ietf_decrypt(
message.asByteArray(),
null,
null,
@ -153,7 +153,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
): AeadEncryptedDataAndTag {
val ciphertext = UByteArray(message.size)
val authenticationTag = UByteArray(crypto_aead_chacha20poly1305_ietf_ABYTES)
sodium.crypto_aead_chacha20poly1305_ietf_encrypt_detached(
sodiumJna.crypto_aead_chacha20poly1305_ietf_encrypt_detached(
ciphertext.asByteArray(),
authenticationTag.asByteArray(),
null,
@ -176,7 +176,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
key: UByteArray
): UByteArray {
val message = UByteArray(ciphertext.size)
val validationResult = sodium.crypto_aead_chacha20poly1305_ietf_decrypt_detached(
val validationResult = sodiumJna.crypto_aead_chacha20poly1305_ietf_decrypt_detached(
message.asByteArray(),
null,
ciphertext.asByteArray(),
@ -200,7 +200,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
key: UByteArray
): UByteArray {
val ciphertext = UByteArray(message.size + crypto_aead_chacha20poly1305_ABYTES)
sodium.crypto_aead_chacha20poly1305_encrypt(
sodiumJna.crypto_aead_chacha20poly1305_encrypt(
ciphertext.asByteArray(),
null,
message.asByteArray(),
@ -221,7 +221,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
key: UByteArray
): UByteArray {
val message = UByteArray(ciphertextAndTag.size - crypto_aead_chacha20poly1305_ABYTES)
val validationResult = sodium.crypto_aead_chacha20poly1305_decrypt(
val validationResult = sodiumJna.crypto_aead_chacha20poly1305_decrypt(
message.asByteArray(),
null,
null,
@ -246,7 +246,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
): AeadEncryptedDataAndTag {
val ciphertext = UByteArray(message.size)
val authenticationTag = UByteArray(crypto_aead_chacha20poly1305_ABYTES)
sodium.crypto_aead_chacha20poly1305_encrypt_detached(
sodiumJna.crypto_aead_chacha20poly1305_encrypt_detached(
ciphertext.asByteArray(),
authenticationTag.asByteArray(),
null,
@ -269,7 +269,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
key: UByteArray
): UByteArray {
val message = UByteArray(ciphertext.size)
val validationResult = sodium.crypto_aead_chacha20poly1305_decrypt_detached(
val validationResult = sodiumJna.crypto_aead_chacha20poly1305_decrypt_detached(
message.asByteArray(),
null,
ciphertext.asByteArray(),
@ -288,19 +288,19 @@ actual object AuthenticatedEncryptionWithAssociatedData {
actual fun xChaCha20Poly1305IetfKeygen(): UByteArray {
val generatedKey = UByteArray(crypto_aead_xchacha20poly1305_ietf_KEYBYTES)
sodium.crypto_aead_xchacha20poly1305_ietf_keygen(generatedKey.asByteArray())
sodiumJna.crypto_aead_xchacha20poly1305_ietf_keygen(generatedKey.asByteArray())
return generatedKey
}
actual fun chaCha20Poly1305IetfKeygen(): UByteArray {
val generatedKey = UByteArray(crypto_aead_chacha20poly1305_ietf_KEYBYTES)
sodium.crypto_aead_chacha20poly1305_ietf_keygen(generatedKey.asByteArray())
sodiumJna.crypto_aead_chacha20poly1305_ietf_keygen(generatedKey.asByteArray())
return generatedKey
}
actual fun chaCha20Poly1305Keygen(): UByteArray {
val generatedKey = UByteArray(crypto_aead_chacha20poly1305_KEYBYTES)
sodium.crypto_aead_chacha20poly1305_keygen(generatedKey.asByteArray())
sodiumJna.crypto_aead_chacha20poly1305_keygen(generatedKey.asByteArray())
return generatedKey
}

View File

@ -1,17 +1,17 @@
package com.ionspin.kotlin.crypto.auth
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
actual object Auth {
actual fun authKeygen(): UByteArray {
val generatedKey = UByteArray(crypto_auth_KEYBYTES)
sodium.crypto_auth_keygen(generatedKey.asByteArray())
sodiumJna.crypto_auth_keygen(generatedKey.asByteArray())
return generatedKey
}
actual fun auth(message: UByteArray, key: UByteArray): UByteArray {
val mac = UByteArray(crypto_auth_BYTES)
sodium.crypto_auth(
sodiumJna.crypto_auth(
mac.asByteArray(),
message.asByteArray(),
message.size.toLong(),
@ -21,7 +21,7 @@ actual object Auth {
}
actual fun authVerify(tag: UByteArray, message: UByteArray, key: UByteArray): Boolean {
return sodium.crypto_auth_verify(
return sodiumJna.crypto_auth_verify(
tag.asByteArray(),
message.asByteArray(),
message.size.toLong(),
@ -31,13 +31,13 @@ actual object Auth {
actual fun authHmacSha256Keygen(): UByteArray {
val generatedKey = UByteArray(crypto_auth_hmacsha256_KEYBYTES)
sodium.crypto_auth_hmacsha256_keygen(generatedKey.asByteArray())
sodiumJna.crypto_auth_hmacsha256_keygen(generatedKey.asByteArray())
return generatedKey
}
actual fun authHmacSha256(message: UByteArray, key: UByteArray): UByteArray {
val mac = UByteArray(crypto_auth_hmacsha256_BYTES)
sodium.crypto_auth_hmacsha256(
sodiumJna.crypto_auth_hmacsha256(
mac.asByteArray(),
message.asByteArray(),
message.size.toLong(),
@ -51,7 +51,7 @@ actual object Auth {
message: UByteArray,
key: UByteArray
): Boolean {
return sodium.crypto_auth_hmacsha256_verify(
return sodiumJna.crypto_auth_hmacsha256_verify(
tag.asByteArray(),
message.asByteArray(),
message.size.toLong(),
@ -61,13 +61,13 @@ actual object Auth {
actual fun authHmacSha512Keygen(): UByteArray {
val generatedKey = UByteArray(crypto_auth_hmacsha512_KEYBYTES)
sodium.crypto_auth_hmacsha512_keygen(generatedKey.asByteArray())
sodiumJna.crypto_auth_hmacsha512_keygen(generatedKey.asByteArray())
return generatedKey
}
actual fun authHmacSha512(message: UByteArray, key: UByteArray): UByteArray {
val mac = UByteArray(crypto_auth_hmacsha512_BYTES)
sodium.crypto_auth_hmacsha512(
sodiumJna.crypto_auth_hmacsha512(
mac.asByteArray(),
message.asByteArray(),
message.size.toLong(),
@ -81,7 +81,7 @@ actual object Auth {
message: UByteArray,
key: UByteArray
): Boolean {
return sodium.crypto_auth_hmacsha512_verify(
return sodiumJna.crypto_auth_hmacsha512_verify(
tag.asByteArray(),
message.asByteArray(),
message.size.toLong(),

View File

@ -1,6 +1,6 @@
package com.ionspin.kotlin.crypto.box
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
actual object Box {
/**
@ -11,7 +11,7 @@ actual object Box {
actual fun keypair(): BoxKeyPair {
val publicKey = UByteArray(crypto_box_PUBLICKEYBYTES)
val secretKey = UByteArray(crypto_box_SECRETKEYBYTES)
sodium.crypto_box_keypair(publicKey.asByteArray(), secretKey.asByteArray())
sodiumJna.crypto_box_keypair(publicKey.asByteArray(), secretKey.asByteArray())
return BoxKeyPair(publicKey, secretKey)
}
@ -21,7 +21,7 @@ actual object Box {
actual fun seedKeypair(seed: UByteArray): BoxKeyPair {
val publicKey = UByteArray(crypto_box_PUBLICKEYBYTES)
val secretKey = UByteArray(crypto_box_SECRETKEYBYTES)
sodium.crypto_box_seed_keypair(publicKey.asByteArray(), secretKey.asByteArray(), seed.asByteArray())
sodiumJna.crypto_box_seed_keypair(publicKey.asByteArray(), secretKey.asByteArray(), seed.asByteArray())
return BoxKeyPair(publicKey, secretKey)
}
@ -39,7 +39,7 @@ actual object Box {
sendersSecretKey: UByteArray
): UByteArray {
val ciphertext = UByteArray(message.size + crypto_box_MACBYTES)
sodium.crypto_box_easy(
sodiumJna.crypto_box_easy(
ciphertext.asByteArray(),
message.asByteArray(),
message.size.toLong(),
@ -64,7 +64,7 @@ actual object Box {
recipientsSecretKey: UByteArray
): UByteArray {
val message = UByteArray(ciphertext.size - crypto_box_MACBYTES)
val validationResult = sodium.crypto_box_open_easy(
val validationResult = sodiumJna.crypto_box_open_easy(
message.asByteArray(),
ciphertext.asByteArray(),
ciphertext.size.toLong(),
@ -85,7 +85,7 @@ actual object Box {
*/
actual fun beforeNM(publicKey: UByteArray, secretKey: UByteArray): UByteArray {
val sessionKey = UByteArray(crypto_box_BEFORENMBYTES)
sodium.crypto_box_beforenm(sessionKey.asByteArray(), publicKey.asByteArray(), secretKey.asByteArray())
sodiumJna.crypto_box_beforenm(sessionKey.asByteArray(), publicKey.asByteArray(), secretKey.asByteArray())
return sessionKey
}
@ -99,7 +99,7 @@ actual object Box {
): UByteArray {
val ciphertext = UByteArray(message.size + crypto_box_MACBYTES)
sodium.crypto_box_easy_afternm(
sodiumJna.crypto_box_easy_afternm(
ciphertext.asByteArray(),
message.asByteArray(),
message.size.toLong(),
@ -119,7 +119,7 @@ actual object Box {
precomputedKey: UByteArray
): UByteArray {
val message = UByteArray(ciphertext.size - crypto_box_MACBYTES)
val validationResult = sodium.crypto_box_open_easy_afternm(
val validationResult = sodiumJna.crypto_box_open_easy_afternm(
message.asByteArray(),
ciphertext.asByteArray(),
ciphertext.size.toLong(),
@ -149,7 +149,7 @@ actual object Box {
val ciphertext = UByteArray(message.size)
val tag = UByteArray(crypto_box_MACBYTES)
sodium.crypto_box_detached(
sodiumJna.crypto_box_detached(
ciphertext.asByteArray(),
tag.asByteArray(),
message.asByteArray(),
@ -177,7 +177,7 @@ actual object Box {
): UByteArray {
val message = UByteArray(ciphertext.size)
val validationResult = sodium.crypto_box_open_detached(
val validationResult = sodiumJna.crypto_box_open_detached(
message.asByteArray(),
ciphertext.asByteArray(),
tag.asByteArray(),
@ -196,7 +196,7 @@ actual object Box {
actual fun seal(message: UByteArray, recipientsPublicKey: UByteArray): UByteArray {
val ciphertextWithPublicKey = UByteArray(message.size + crypto_box_SEALBYTES)
sodium.crypto_box_seal(
sodiumJna.crypto_box_seal(
ciphertextWithPublicKey.asByteArray(),
message.asByteArray(),
message.size.toLong(),
@ -207,7 +207,7 @@ actual object Box {
actual fun sealOpen(ciphertext: UByteArray, recipientsPublicKey: UByteArray, recipientsSecretKey: UByteArray): UByteArray {
val message = UByteArray(ciphertext.size - crypto_box_SEALBYTES)
val validationResult = sodium.crypto_box_seal_open(
val validationResult = sodiumJna.crypto_box_seal_open(
message.asByteArray(),
ciphertext.asByteArray(),
ciphertext.size.toLong(),
@ -223,4 +223,4 @@ actual object Box {
}
}
}

View File

@ -1,13 +1,14 @@
package com.ionspin.kotlin.crypto.generichash
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
import com.ionspin.kotlin.crypto.Blake2bState
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 21-Aug-2020
*/
actual class GenericHashStateInternal(internal val data: ByteArray)
actual typealias GenericHashStateInternal = Blake2bState
actual object GenericHash {
actual fun genericHash(
@ -16,12 +17,12 @@ actual object GenericHash {
key: UByteArray?
): UByteArray {
val hash = UByteArray(requestedHashLength)
sodium.crypto_generichash(
sodiumJna.crypto_generichash(
hash.asByteArray(),
requestedHashLength,
message.asByteArray(),
message.size.toLong(),
key?.asByteArray(),
key?.asByteArray() ?: ByteArray(0),
(key?.size ?: 0)
)
return hash
@ -31,8 +32,8 @@ actual object GenericHash {
requestedHashLength: Int,
key: UByteArray?
): GenericHashState {
val state = GenericHashStateInternal(ByteArray(sodium.crypto_generichash_statebytes()))
sodium.crypto_generichash_init(state.data, key?.asByteArray(), key?.size ?: 0, requestedHashLength)
val state = GenericHashStateInternal()
sodiumJna.crypto_generichash_init(state, key?.asByteArray() ?: ByteArray(0), key?.size ?: 0, requestedHashLength)
return GenericHashState(requestedHashLength, state)
}
@ -40,18 +41,18 @@ actual object GenericHash {
state: GenericHashState,
messagePart: UByteArray
) {
sodium.crypto_generichash_update(state.internalState.data, messagePart.asByteArray(), messagePart.size.toLong())
sodiumJna.crypto_generichash_update(state.internalState, messagePart.asByteArray(), messagePart.size.toLong())
}
actual fun genericHashFinal(state: GenericHashState): UByteArray {
val hashResult = ByteArray(state.hashLength)
sodium.crypto_generichash_final(state.internalState.data, hashResult, state.hashLength)
sodiumJna.crypto_generichash_final(state.internalState, hashResult, state.hashLength)
return hashResult.asUByteArray()
}
actual fun genericHashKeygen(): UByteArray {
val generatedKey = UByteArray(crypto_generichash_BYTES)
sodium.crypto_generichash_keygen(generatedKey.asByteArray())
sodiumJna.crypto_generichash_keygen(generatedKey.asByteArray())
return generatedKey
}

View File

@ -1,54 +1,55 @@
package com.ionspin.kotlin.crypto.hash
import com.goterl.lazycode.lazysodium.interfaces.Hash
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
import com.ionspin.kotlin.crypto.Hash256State
import com.ionspin.kotlin.crypto.Hash512State
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
actual typealias Sha256State = Hash.State256
actual typealias Sha512State = Hash.State512
actual typealias Sha256State = Hash256State
actual typealias Sha512State = Hash512State
actual object Hash {
actual fun sha256(data: UByteArray): UByteArray {
val resultHash = UByteArray(crypto_hash_sha256_BYTES)
sodium.crypto_hash_sha256(resultHash.asByteArray(), data.asByteArray(), data.size.toLong())
sodiumJna.crypto_hash_sha256(resultHash.asByteArray(), data.asByteArray(), data.size.toLong())
return resultHash
}
actual fun sha256Init(): Sha256State {
val state = Hash.State256()
sodium.crypto_hash_sha256_init(state)
val state = Hash256State()
sodiumJna.crypto_hash_sha256_init(state)
return state
}
actual fun sha256Update(state: Sha256State, data: UByteArray) {
sodium.crypto_hash_sha256_update(state, data.asByteArray(), data.size.toLong())
sodiumJna.crypto_hash_sha256_update(state, data.asByteArray(), data.size.toLong())
}
actual fun sha256Final(state: Sha256State): UByteArray {
val resultHash = UByteArray(crypto_hash_sha256_BYTES)
sodium.crypto_hash_sha256_final(state, resultHash.asByteArray())
sodiumJna.crypto_hash_sha256_final(state, resultHash.asByteArray())
return resultHash
}
actual fun sha512(data: UByteArray): UByteArray {
val resultHash = UByteArray(crypto_hash_sha512_BYTES)
sodium.crypto_hash_sha512(resultHash.asByteArray(), data.asByteArray(), data.size.toLong())
sodiumJna.crypto_hash_sha512(resultHash.asByteArray(), data.asByteArray(), data.size.toLong())
return resultHash
}
actual fun sha512Init(): Sha512State {
val state = Hash.State512()
sodium.crypto_hash_sha512_init(state)
val state = Hash512State()
sodiumJna.crypto_hash_sha512_init(state)
return state
}
actual fun sha512Update(state: Sha512State, data: UByteArray) {
sodium.crypto_hash_sha512_update(state, data.asByteArray(), data.size.toLong())
sodiumJna.crypto_hash_sha512_update(state, data.asByteArray(), data.size.toLong())
}
actual fun sha512Final(state: Sha512State): UByteArray {
val resultHash = UByteArray(crypto_hash_sha512_BYTES)
sodium.crypto_hash_sha512_final(state, resultHash.asByteArray())
sodiumJna.crypto_hash_sha512_final(state, resultHash.asByteArray())
return resultHash
}

View File

@ -1,6 +1,6 @@
package com.ionspin.kotlin.crypto.kdf
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
actual object Kdf {
/**
@ -26,7 +26,7 @@ actual object Kdf {
val subkey = UByteArray(subkeyLength)
val contextEncoded = context.encodeToByteArray()
sodium.crypto_kdf_derive_from_key(
sodiumJna.crypto_kdf_derive_from_key(
subkey.asByteArray(),
subkeyLength,
subkeyId.toLong(),
@ -42,8 +42,8 @@ actual object Kdf {
*/
actual fun keygen(): UByteArray {
val masterKey = UByteArray(crypto_kdf_KEYBYTES)
sodium.crypto_kdf_keygen(masterKey.asByteArray())
sodiumJna.crypto_kdf_keygen(masterKey.asByteArray())
return masterKey
}
}
}

View File

@ -1,13 +1,13 @@
package com.ionspin.kotlin.crypto.keyexchange
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
actual object KeyExchange {
actual fun clientSessionKeys(clientPublicKey: UByteArray, clientSecretKey: UByteArray, serverPublicKey: UByteArray) : KeyExchangeSessionKeyPair {
val receiveKey = UByteArray(crypto_kx_SESSIONKEYBYTES)
val sendKey = UByteArray(crypto_kx_SESSIONKEYBYTES)
sodium.crypto_kx_client_session_keys(
sodiumJna.crypto_kx_client_session_keys(
receiveKey.asByteArray(),
sendKey.asByteArray(),
clientPublicKey.asByteArray(),
@ -25,7 +25,7 @@ actual object KeyExchange {
val secretKey = UByteArray(crypto_kx_SECRETKEYBYTES)
sodium.crypto_kx_keypair(publicKey.asByteArray(), secretKey.asByteArray())
sodiumJna.crypto_kx_keypair(publicKey.asByteArray(), secretKey.asByteArray())
return KeyExchangeKeyPair(publicKey, secretKey)
@ -35,7 +35,7 @@ actual object KeyExchange {
val publicKey = UByteArray(crypto_kx_PUBLICKEYBYTES)
val secretKey = UByteArray(crypto_kx_SECRETKEYBYTES)
sodium.crypto_kx_seed_keypair(publicKey.asByteArray(), secretKey.asByteArray(), seed.asByteArray())
sodiumJna.crypto_kx_seed_keypair(publicKey.asByteArray(), secretKey.asByteArray(), seed.asByteArray())
return KeyExchangeKeyPair(publicKey, secretKey)
}
@ -44,7 +44,7 @@ actual object KeyExchange {
val receiveKey = UByteArray(crypto_kx_SESSIONKEYBYTES)
val sendKey = UByteArray(crypto_kx_SESSIONKEYBYTES)
sodium.crypto_kx_server_session_keys(
sodiumJna.crypto_kx_server_session_keys(
receiveKey.asByteArray(),
sendKey.asByteArray(),
serverPublicKey.asByteArray(),

View File

@ -1,6 +1,6 @@
package com.ionspin.kotlin.crypto.pwhash
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
import com.sun.jna.NativeLong
actual object PasswordHash {
@ -10,7 +10,7 @@ actual object PasswordHash {
* PASSWD_MIN and crypto_pwhash_PASSWD_MAX. outlen should be at least crypto_pwhash_BYTES_MIN = 16 (128 bits) and
* at most crypto_pwhash_BYTES_MAX.
*
* See https://libsodium.gitbook.io/doc/password_hashing/default_phf for more details
* See https://libsodiumJna.gitbook.io/doc/password_hashing/default_phf for more details
*/
actual fun pwhash(
outputLength: Int,
@ -22,14 +22,14 @@ actual object PasswordHash {
): UByteArray {
val hashedPassword = UByteArray(outputLength)
sodium.crypto_pwhash(
sodiumJna.crypto_pwhash(
hashedPassword.asByteArray(),
outputLength.toLong(),
password.encodeToByteArray(),
password,
password.length.toLong(),
salt.asByteArray(),
opsLimit.toLong(),
NativeLong(memLimit.toLong()),
memLimit.toLong(),
algorithm
)
@ -48,12 +48,12 @@ actual object PasswordHash {
*/
actual fun str(password: String, opslimit: ULong, memlimit: Int): UByteArray {
val output = ByteArray(crypto_pwhash_STRBYTES)
sodium.crypto_pwhash_str(
sodiumJna.crypto_pwhash_str(
output,
password.encodeToByteArray(),
password,
password.length.toLong(),
opslimit.toLong(),
NativeLong(memlimit.toLong())
memlimit.toLong()
)
return output.asUByteArray()
}
@ -69,10 +69,10 @@ actual object PasswordHash {
opslimit: ULong,
memlimit: Int
): Int {
return sodium.crypto_pwhash_str_needs_rehash(
return sodiumJna.crypto_pwhash_str_needs_rehash(
passwordHash.asByteArray(),
opslimit.toLong(),
NativeLong(memlimit.toLong())
memlimit.toLong()
)
}
@ -82,9 +82,9 @@ actual object PasswordHash {
* It returns 0 if the verification succeeds, and -1 on error.
*/
actual fun strVerify(passwordHash: UByteArray, password: String): Boolean {
val result = sodium.crypto_pwhash_str_verify(
val result = sodiumJna.crypto_pwhash_str_verify(
passwordHash.asByteArray(),
password.encodeToByteArray(),
password,
password.length.toLong()
)

View File

@ -1,6 +1,6 @@
package com.ionspin.kotlin.crypto.scalarmult
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
actual object ScalarMultiplication {
/**
@ -18,7 +18,7 @@ actual object ScalarMultiplication {
actual fun scalarMultiplication(secretKeyN: UByteArray, publicKeyP: UByteArray): UByteArray {
val result = UByteArray(crypto_scalarmult_BYTES)
sodium.crypto_scalarmult(result.asByteArray(), secretKeyN.asByteArray(), publicKeyP.asByteArray())
sodiumJna.crypto_scalarmult(result.asByteArray(), secretKeyN.asByteArray(), publicKeyP.asByteArray())
return result
@ -35,7 +35,7 @@ actual object ScalarMultiplication {
): UByteArray {
val result = UByteArray(crypto_scalarmult_BYTES)
sodium.crypto_scalarmult_base(result.asByteArray(), secretKeyN.asByteArray())
sodiumJna.crypto_scalarmult_base(result.asByteArray(), secretKeyN.asByteArray())
return result
}

View File

@ -1,11 +1,11 @@
package com.ionspin.kotlin.crypto.secretbox
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
actual object SecretBox {
actual fun easy(message: UByteArray, nonce: UByteArray, key: UByteArray): UByteArray {
val ciphertext = UByteArray(message.size + crypto_secretbox_MACBYTES)
sodium.crypto_secretbox_easy(
sodiumJna.crypto_secretbox_easy(
ciphertext.asByteArray(),
message.asByteArray(),
message.size.toLong(),
@ -21,7 +21,7 @@ actual object SecretBox {
key: UByteArray
): UByteArray {
val decrypted = UByteArray(ciphertext.size - crypto_secretbox_MACBYTES)
val validationResult = sodium.crypto_secretbox_open_easy(
val validationResult = sodiumJna.crypto_secretbox_open_easy(
decrypted.asByteArray(),
ciphertext.asByteArray(),
ciphertext.size.toLong(),
@ -41,7 +41,7 @@ actual object SecretBox {
): SecretBoxEncryptedDataAndTag {
val ciphertext = UByteArray(message.size)
val authenticationTag = UByteArray(crypto_secretbox_MACBYTES)
sodium.crypto_secretbox_detached(
sodiumJna.crypto_secretbox_detached(
ciphertext.asByteArray(),
authenticationTag.asByteArray(),
message.asByteArray(),
@ -59,7 +59,7 @@ actual object SecretBox {
key: UByteArray
): UByteArray {
val message = UByteArray(ciphertext.size)
val validationResult = sodium.crypto_secretbox_open_detached(
val validationResult = sodiumJna.crypto_secretbox_open_detached(
message.asByteArray(),
ciphertext.asByteArray(),
tag.asByteArray(),
@ -75,7 +75,7 @@ actual object SecretBox {
actual fun keygen() : UByteArray {
val generatedKey = UByteArray(crypto_secretbox_KEYBYTES)
sodium.crypto_secretbox_keygen(generatedKey.asByteArray())
sodiumJna.crypto_secretbox_keygen(generatedKey.asByteArray())
return generatedKey
}

View File

@ -1,15 +1,15 @@
package com.ionspin.kotlin.crypto.secretstream
import com.goterl.lazycode.lazysodium.interfaces.SecretStream
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
import com.ionspin.kotlin.crypto.SecretStreamXChaCha20Poly1305State
actual typealias SecretStreamState = SecretStream.State
actual typealias SecretStreamState = SecretStreamXChaCha20Poly1305State
actual object SecretStream {
actual fun xChaCha20Poly1305InitPush(key: UByteArray): SecretStreamStateAndHeader {
val state = SecretStreamState()
val header = UByteArray(sodium.crypto_secretstream_xchacha20poly1305_headerbytes())
sodium.crypto_secretstream_xchacha20poly1305_init_push(state, header.asByteArray(), key.asByteArray())
val header = UByteArray(sodiumJna.crypto_secretstream_xchacha20poly1305_headerbytes())
sodiumJna.crypto_secretstream_xchacha20poly1305_init_push(state, header.asByteArray(), key.asByteArray())
return SecretStreamStateAndHeader(state, header)
}
@ -20,7 +20,7 @@ actual object SecretStream {
tag: UByte
): UByteArray {
val ciphertext = UByteArray(message.size + crypto_secretstream_xchacha20poly1305_ABYTES)
sodium.crypto_secretstream_xchacha20poly1305_push(
sodiumJna.crypto_secretstream_xchacha20poly1305_push(
state,
ciphertext.asByteArray(),
null,
@ -38,7 +38,7 @@ actual object SecretStream {
header: UByteArray
): SecretStreamStateAndHeader {
val state = SecretStreamState()
sodium.crypto_secretstream_xchacha20poly1305_init_pull(state, header.asByteArray(), key.asByteArray())
sodiumJna.crypto_secretstream_xchacha20poly1305_init_pull(state, header.asByteArray(), key.asByteArray())
return SecretStreamStateAndHeader(state, header)
}
@ -49,7 +49,7 @@ actual object SecretStream {
): DecryptedDataAndTag {
val result = UByteArray(ciphertext.size - crypto_secretstream_xchacha20poly1305_ABYTES)
val tagArray = UByteArray(1) { 0U }
val validationResult = sodium.crypto_secretstream_xchacha20poly1305_pull(
val validationResult = sodiumJna.crypto_secretstream_xchacha20poly1305_pull(
state,
result.asByteArray(),
null,
@ -67,12 +67,12 @@ actual object SecretStream {
actual fun xChaCha20Poly1305Keygen(): UByteArray {
val generatedKey = UByteArray(crypto_secretstream_xchacha20poly1305_KEYBYTES)
sodium.crypto_secretstream_xchacha20poly1305_keygen(generatedKey.asByteArray())
sodiumJna.crypto_secretstream_xchacha20poly1305_keygen(generatedKey.asByteArray())
return generatedKey
}
actual fun xChaCha20Poly1305Rekey(state: SecretStreamState) {
sodium.crypto_secretstream_xchacha20poly1305_rekey(state)
sodiumJna.crypto_secretstream_xchacha20poly1305_rekey(state)
}
}

View File

@ -1,6 +1,7 @@
package com.ionspin.kotlin.crypto.shortinputhash
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
import com.sun.jna.NativeLong
/**
* Created by Ugljesa Jovanovic
@ -12,13 +13,13 @@ import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
actual object ShortHash {
actual fun shortHash(data: UByteArray, key: UByteArray): UByteArray {
val hashResult = UByteArray(crypto_shorthash_BYTES)
sodium.crypto_shorthash(hashResult.asByteArray(), data.asByteArray(), data.size.toLong(), key.asByteArray())
sodiumJna.crypto_shorthash(hashResult.asByteArray(), data.asByteArray(), data.size.toLong(), key.asByteArray())
return hashResult
}
actual fun shortHashKeygen(): UByteArray {
val key = UByteArray(crypto_shorthash_KEYBYTES)
sodium.crypto_shorthash_keygen(key.asByteArray())
sodiumJna.crypto_shorthash_keygen(key.asByteArray())
return key
}

View File

@ -1,9 +1,9 @@
package com.ionspin.kotlin.crypto.signature
import com.goterl.lazycode.lazysodium.interfaces.Sign
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
import com.ionspin.kotlin.crypto.Ed25519SignatureState
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
actual typealias SignatureState = Sign.StateCryptoSign
actual typealias SignatureState = Ed25519SignatureState
actual object Signature {
actual fun init(): SignatureState {
@ -11,7 +11,7 @@ actual object Signature {
}
actual fun update(state: SignatureState, data: UByteArray) {
sodium.crypto_sign_update(state, data.asByteArray(), data.size.toLong())
sodiumJna.crypto_sign_update(state, data.asByteArray(), data.size.toLong())
}
actual fun finalCreate(
@ -19,7 +19,7 @@ actual object Signature {
secretKey: UByteArray
): UByteArray {
val signature = UByteArray(crypto_sign_BYTES)
sodium.crypto_sign_final_create(
sodiumJna.crypto_sign_final_create(
state,
signature.asByteArray(),
null,
@ -33,7 +33,7 @@ actual object Signature {
signature: UByteArray,
publicKey: UByteArray
) {
val verificationResult = sodium.crypto_sign_final_verify(
val verificationResult = sodiumJna.crypto_sign_final_verify(
state,
signature.asByteArray(),
publicKey.asByteArray()
@ -50,7 +50,7 @@ actual object Signature {
actual fun keypair(): SignatureKeyPair {
val publicKey = UByteArray(crypto_sign_PUBLICKEYBYTES)
val secretKey = UByteArray(crypto_sign_SECRETKEYBYTES)
sodium.crypto_sign_keypair(
sodiumJna.crypto_sign_keypair(
publicKey.asByteArray(),
secretKey.asByteArray(),
)
@ -65,9 +65,9 @@ actual object Signature {
actual fun seedKeypair(seed: UByteArray): SignatureKeyPair {
val publicKey = UByteArray(crypto_sign_PUBLICKEYBYTES)
val secretKey = UByteArray(crypto_sign_SECRETKEYBYTES)
sodium.crypto_sign_seed_keypair(
sodiumJna.crypto_sign_seed_keypair(
publicKey.asByteArray(),
secretKey.asByteArray(),
seed.asByteArray()
@ -76,13 +76,13 @@ actual object Signature {
}
/**
* The sodium.crypto_sign() function prepends a signature to a message m whose length is mlen bytes, using the secret key sk.
* The signed message, which includes the signature + a plain copy of the message, is put into sm, and is sodium.crypto_sign_BYTES + mlen bytes long.
* The sodiumJna.crypto_sign() function prepends a signature to a message m whose length is mlen bytes, using the secret key sk.
* The signed message, which includes the signature + a plain copy of the message, is put into sm, and is sodiumJna.crypto_sign_BYTES + mlen bytes long.
*/
actual fun sign(message: UByteArray, secretKey: UByteArray): UByteArray {
val signedMessage = UByteArray(message.size + crypto_sign_BYTES)
sodium.crypto_sign(
sodiumJna.crypto_sign(
signedMessage.asByteArray(),
null,
message.asByteArray(),
@ -94,13 +94,13 @@ actual object Signature {
}
/**
* The sodium.crypto_sign_open() function checks that the signed message sm whose length is smlen bytes has a valid signature for the public key pk.
* The sodiumJna.crypto_sign_open() function checks that the signed message sm whose length is smlen bytes has a valid signature for the public key pk.
* If the signature is doesn't appear to be valid, the function throws an exception
*/
actual fun open(signedMessage: UByteArray, publicKey: UByteArray): UByteArray {
val message = UByteArray(signedMessage.size - crypto_sign_BYTES)
val verificationResult = sodium.crypto_sign_open(
val verificationResult = sodiumJna.crypto_sign_open(
message.asByteArray(),
null,
signedMessage.asByteArray(),
@ -115,13 +115,13 @@ actual object Signature {
/**
* In detached mode, the signature is stored without attaching a copy of the original message to it.
* The sodium.crypto_sign_detached() function signs the message m whose length is mlen bytes, using the secret key sk,
* and puts the signature into sig, which can be up to sodium.crypto_sign_BYTES bytes long.
* The sodiumJna.crypto_sign_detached() function signs the message m whose length is mlen bytes, using the secret key sk,
* and puts the signature into sig, which can be up to sodiumJna.crypto_sign_BYTES bytes long.
*/
actual fun detached(message: UByteArray, secretKey: UByteArray): UByteArray {
val signature = UByteArray(crypto_sign_BYTES)
sodium.crypto_sign_detached(
sodiumJna.crypto_sign_detached(
signature.asByteArray(),
null,
message.asByteArray(),
@ -133,7 +133,7 @@ actual object Signature {
}
/**
* The sodium.crypto_sign_verify_detached() function verifies that sig is a valid signature for the message m whose length
* The sodiumJna.crypto_sign_verify_detached() function verifies that sig is a valid signature for the message m whose length
* is mlen bytes, using the signer's public key pk.
*/
actual fun verifyDetached(
@ -142,7 +142,7 @@ actual object Signature {
publicKey: UByteArray
) {
val verificationResult = sodium.crypto_sign_verify_detached(
val verificationResult = sodiumJna.crypto_sign_verify_detached(
signature.asByteArray(),
message.asByteArray(),
message.size.toLong(),
@ -155,11 +155,11 @@ actual object Signature {
}
/**
* The sodium.crypto_sign_ed25519_pk_to_curve25519() function converts an Ed25519 public key ed25519_pk to an X25519 public key and stores it into x25519_pk.
* The sodiumJna.crypto_sign_ed25519_pk_to_curve25519() function converts an Ed25519 public key ed25519_pk to an X25519 public key and stores it into x25519_pk.
*/
actual fun ed25519PkToCurve25519(ed25519PublicKey: UByteArray) : UByteArray {
val x25519PublicKey = UByteArray(crypto_scalarmult_curve25519_BYTES)
sodium.crypto_sign_ed25519_sk_to_curve25519(
sodiumJna.crypto_sign_ed25519_sk_to_curve25519(
x25519PublicKey.asByteArray(),
ed25519PublicKey.asByteArray()
)
@ -168,7 +168,7 @@ actual object Signature {
actual fun ed25519SkToCurve25519(ed25519SecretKey: UByteArray) : UByteArray {
val x25519SecretKey = UByteArray(crypto_scalarmult_curve25519_BYTES)
sodium.crypto_sign_ed25519_sk_to_curve25519(
sodiumJna.crypto_sign_ed25519_sk_to_curve25519(
x25519SecretKey.asByteArray(),
ed25519SecretKey.asByteArray()
)
@ -176,13 +176,13 @@ actual object Signature {
}
/**
* The secret key actually includes the seed (either a random seed or the one given to sodium.crypto_sign_seed_keypair()) as well as the public key.
* The secret key actually includes the seed (either a random seed or the one given to sodiumJna.crypto_sign_seed_keypair()) as well as the public key.
* While the public key can always be derived from the seed, the precomputation saves a significant amount of CPU cycles when signing.
*/
actual fun ed25519SkToSeed(secretKey: UByteArray): UByteArray {
val seed = UByteArray(crypto_sign_SEEDBYTES)
sodium.crypto_sign_ed25519_sk_to_seed(
sodiumJna.crypto_sign_ed25519_sk_to_seed(
seed.asByteArray(),
secretKey.asByteArray()
)
@ -192,13 +192,13 @@ actual object Signature {
}
/**
* The secret key actually includes the seed (either a random seed or the one given to sodium.crypto_sign_seed_keypair()) as well as the public key.
* The secret key actually includes the seed (either a random seed or the one given to sodiumJna.crypto_sign_seed_keypair()) as well as the public key.
* While the public key can always be derived from the seed, the precomputation saves a significant amount of CPU cycles when signing.
*/
actual fun ed25519SkToPk(secretKey: UByteArray): UByteArray {
val publicKey = UByteArray(crypto_sign_PUBLICKEYBYTES)
sodium.crypto_sign_ed25519_sk_to_pk(
sodiumJna.crypto_sign_ed25519_sk_to_pk(
publicKey.asByteArray(),
secretKey.asByteArray()
)
@ -206,4 +206,4 @@ actual object Signature {
return publicKey
}
}
}

View File

@ -1,12 +1,12 @@
package com.ionspin.kotlin.crypto.stream
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
actual object Stream {
actual fun chacha20(clen: Int, nonce: UByteArray, key: UByteArray): UByteArray {
val result = UByteArray(clen)
sodium.crypto_stream_chacha20(result.asByteArray(), clen.toLong(), nonce.asByteArray(), key.asByteArray())
sodiumJna.crypto_stream_chacha20(result.asByteArray(), clen.toLong(), nonce.asByteArray(), key.asByteArray())
return result
}
@ -18,7 +18,7 @@ actual object Stream {
): UByteArray {
val result = UByteArray(message.size)
sodium.crypto_stream_chacha20_ietf_xor(
sodiumJna.crypto_stream_chacha20_ietf_xor(
result.asByteArray(),
message.asByteArray(),
message.size.toLong(),
@ -37,7 +37,7 @@ actual object Stream {
): UByteArray {
val result = UByteArray(message.size)
sodium.crypto_stream_chacha20_ietf_xor_ic(
sodiumJna.crypto_stream_chacha20_ietf_xor_ic(
result.asByteArray(),
message.asByteArray(),
message.size.toLong(),
@ -52,7 +52,7 @@ actual object Stream {
actual fun chacha20Keygen(): UByteArray {
val result = UByteArray(crypto_stream_chacha20_KEYBYTES)
sodium.crypto_stream_chacha20_keygen(result.asByteArray())
sodiumJna.crypto_stream_chacha20_keygen(result.asByteArray())
return result
}
@ -64,7 +64,7 @@ actual object Stream {
): UByteArray {
val result = UByteArray(message.size)
sodium.crypto_stream_chacha20_xor(
sodiumJna.crypto_stream_chacha20_xor(
result.asByteArray(),
message.asByteArray(),
message.size.toLong(),
@ -83,7 +83,7 @@ actual object Stream {
): UByteArray {
val result = UByteArray(message.size)
sodium.crypto_stream_chacha20_xor_ic(
sodiumJna.crypto_stream_chacha20_xor_ic(
result.asByteArray(),
message.asByteArray(),
message.size.toLong(),
@ -95,4 +95,50 @@ actual object Stream {
return result
}
// actual fun xChacha20Keygen(): UByteArray {
// val result = UByteArray(crypto_stream_chacha20_KEYBYTES)
//
// sodiumJna.crypto_stream_xchacha20_keygen(result.asByteArray())
//
// return result
// }
//
// actual fun xChacha20Xor(
// message: UByteArray,
// nonce: UByteArray,
// key: UByteArray
// ): UByteArray {
// val result = UByteArray(message.size)
//
// sodiumJna.crypto_stream_xchacha20_xor(
// result.asByteArray(),
// message.asByteArray(),
// message.size.toLong(),
// nonce.asByteArray(),
// key.asByteArray()
// )
//
// return result
// }
//
// actual fun xChacha20XorIc(
// message: UByteArray,
// nonce: UByteArray,
// initialCounter: ULong,
// key: UByteArray
// ): UByteArray {
// val result = UByteArray(message.size)
//
// sodiumJna.crypto_stream_xchacha20_xor_ic(
// result.asByteArray(),
// message.asByteArray(),
// message.size.toLong(),
// nonce.asByteArray(),
// initialCounter.toLong(),
// key.asByteArray()
// )
//
// return result
// }
}

View File

@ -1,6 +1,6 @@
package com.ionspin.kotlin.crypto.util
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
/**
* Created by Ugljesa Jovanovic
@ -13,7 +13,7 @@ actual object LibsodiumRandom {
*/
actual fun buf(size: Int): UByteArray {
val result = ByteArray(size)
sodium.randombytes_buf(result, size)
sodiumJna.randombytes_buf(result, size)
return result.asUByteArray()
}
@ -27,7 +27,7 @@ actual object LibsodiumRandom {
*/
actual fun bufDeterministic(size: Int, seed: UByteArray): UByteArray {
val result = ByteArray(size)
sodium.randombytes_buf_deterministic(result, size, seed.asByteArray())
sodiumJna.randombytes_buf_deterministic(result, size, seed.asByteArray())
return result.asUByteArray()
}
@ -35,9 +35,7 @@ actual object LibsodiumRandom {
* The randombytes_random() function returns an unpredictable value between 0 and 0xffffffff (included).
*/
actual fun random(): UInt {
//Broken in lazysodium-java https://github.com/terl/lazysodium-java/issues/86
//Using temporary forked and fixed build until pull request is accepted in original repo
return sodium.randombytes_random().toUInt()
return sodiumJna.randombytes_random().toUInt()
}
@ -48,9 +46,7 @@ actual object LibsodiumRandom {
* upper_bound is not a power of 2. Note that an upper_bound < 2 leaves only a single element to be chosen, namely 0
*/
actual fun uniform(upperBound: UInt): UInt {
//Broken in lazysodium-java https://github.com/terl/lazysodium-java/issues/86
//Using temporary fixed build until pull request is accepted
return sodium.randombytes_uniform(upperBound.toInt()).toUInt()
return sodiumJna.randombytes_uniform(upperBound.toLong()).toUInt()
}
}

View File

@ -1,6 +1,7 @@
package com.ionspin.kotlin.crypto.util
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
import com.sun.jna.ptr.IntByReference
import java.lang.RuntimeException
import java.util.*
@ -9,100 +10,63 @@ actual object LibsodiumUtil {
if (first.size != second.size) {
throw RuntimeException("Sodium memcmp() only supports comparing same length arrays")
}
return sodium.sodium_memcmp(first.asByteArray(), second.asByteArray(), first.size) == 0
return sodiumJna.sodium_memcmp(first.asByteArray(), second.asByteArray(), first.size) == 0
}
actual fun memzero(target: UByteArray) {
sodium.sodium_memzero(target.asByteArray(), target.size)
sodiumJna.sodium_memzero(target.asByteArray(), target.size)
}
actual fun pad(unpaddedData: UByteArray, blocksize: Int): UByteArray {
// Pad is invalid in lazysodium-java because it uses char arrays, which are 2 bytes in java
// while libsodium expects 1 byte char array
// See https://github.com/terl/lazysodium-java/issues/85
//This is temporary solution until lazysodium is fixed
if (blocksize == 0) {
throw RuntimeException("Invalid block size: $blocksize")
}
val padAmount = blocksize - (unpaddedData.size % blocksize)
val result = if (padAmount == blocksize) {
unpaddedData + UByteArray(blocksize) {
when (it) {
0 -> 0x80U
else -> 0x00U
}
}
} else {
unpaddedData + UByteArray(padAmount) {
when (it) {
0 -> 0x80U
else -> 0x00U
}
val newPadSizeReference = IntByReference(0)
val newSize = ((unpaddedData.size / blocksize) + 1) * blocksize
val paddedArray = UByteArray(newSize) {
if (it < unpaddedData.size) {
unpaddedData[it]
} else {
0U
}
}
val resultCode = sodiumJna.sodium_pad(
newPadSizeReference.pointer,
paddedArray.asByteArray(),
unpaddedData.size,
blocksize,
newSize
)
if (resultCode != 0) {
throw RuntimeException("Padding failed")
}
return result
// val newPadSizeReference = IntByReference(0)
// val newSize = ((unpaddedData.size / blocksize) + 1) * blocksize
// val charArray = CharArray(newSize) {
// if (it < unpaddedData.size) {
// unpaddedData[it].toByte().toChar()
// } else {
// '\u0000'
// }
// }
// sodium.sodium_pad(
// newPadSizeReference.pointer,
// charArray,
// unpaddedData.size + 1,
// blocksize,
// newSize
// )
//
// return charArray.slice(0 until newPadSizeReference.value).map { it.toByte().toUByte()}.toUByteArray()
return paddedArray.slice(0 until newPadSizeReference.value).map { it.toByte().toUByte()}.toUByteArray()
}
actual fun unpad(paddedData: UByteArray, blocksize: Int): UByteArray {
// Pad is invalid in lazysodium-java because it uses char arrays, which are 2 bytes in java
// while libsodium expects 1 byte char array
// See https://github.com/terl/lazysodium-java/issues/85
val paddedDataCopy = paddedData.copyOf().asByteArray()
var unpaddedSize = IntByReference(0)
//This is temporary solution until lazysodium is fixed
sodiumJna.sodium_unpad(
unpaddedSize.pointer,
paddedDataCopy,
paddedData.size,
blocksize
)
val unpaddedData = paddedData.dropLastWhile { it == 0U.toUByte() }
if (unpaddedData.last() != 0x80U.toUByte()) {
throw RuntimeException("Invalid padding!")
}
return unpaddedData.dropLast(1).toUByteArray()
val unpadded = paddedDataCopy.sliceArray(0 until unpaddedSize.value).asUByteArray()
// val paddedDataCopy = paddedData.copyOf().asByteArray().map { it.toChar() }.toCharArray()
// var unpaddedSize = IntByReference(0)
//
// sodium.sodium_unpad(
// unpaddedSize.pointer,
// paddedDataCopy,
// paddedData.size,
// blocksize
// )
//
// val unpadded = paddedDataCopy.sliceArray(0 until unpaddedSize.value).map { it.toByte().toUByte() }.toUByteArray()
//
// return unpadded
return unpadded
}
actual fun toBase64(
data: UByteArray,
variant: Base64Variants
): String {
val maxlen = sodium.sodium_base64_encoded_len(data.size, variant.value)
val maxlen = sodiumJna.sodium_base64_encoded_len(data.size, variant.value)
val result = ByteArray(maxlen) { 0 }
sodium.sodium_bin2base64(
sodiumJna.sodium_bin2base64(
result,
maxlen,
data.asByteArray(),
@ -116,49 +80,66 @@ actual object LibsodiumUtil {
actual fun toHex(data: UByteArray): String {
val hexLen = (data.size * 2) + 1 // +1 for terminator char
val result = ByteArray(hexLen)
sodium.sodium_bin2hex(
sodiumJna.sodium_bin2hex(
result,
hexLen,
data.asByteArray(),
data.size
)
//Drop terminating char \0
return String(result.sliceArray(0 until result.size - 1))
}
actual fun fromHex(data: String): UByteArray {
val binLenReference = IntByReference(0)
val binSize = (data.length + 1) / 2 // -1 for terminator char
val hex = data.toCharArray().map { it.toByte() }.toByteArray()
val result = ByteArray(binSize)
val resultCode = sodiumJna.sodium_hex2bin(
result,
binSize,
hex,
hex.size,
null,
binLenReference.pointer,
null
)
if (resultCode != 0) {
throw ConversionException()
}
return result.slice(0 until binLenReference.value).toByteArray().asUByteArray()
}
actual fun fromBase64(
data: String,
variant: Base64Variants
): UByteArray {
// from base64 is currently broken in lazysodium-java
// see https://github.com/terl/lazysodium-java/issues/83
// val maxLength = (data.length * 3) / 4
// val intermediaryResult = UByteArray(maxLength) { 0U }
//
// sodium.sodium_base642bin(
// intermediaryResult.asByteArray(),
// maxLength,
// data.encodeToByteArray(),
// data.length,
// null,
// binLenPinned.addressOf(0),
// null,
// variant.value
//
// )
val decoder = when(variant) {
Base64Variants.ORIGINAL -> Base64.getDecoder()
Base64Variants.ORIGINAL_NO_PADDING -> Base64.getDecoder()
Base64Variants.URLSAFE -> Base64.getUrlDecoder()
Base64Variants.URLSAFE_NO_PADDING -> Base64.getUrlDecoder()
val binLengthReference = IntByReference(0)
val maxLength = (data.length * 3) / 4
val intermediaryResult = UByteArray(maxLength) { 0U }
val resultCode = sodiumJna.sodium_base642bin(
intermediaryResult.asByteArray(),
maxLength,
data.encodeToByteArray(),
data.length,
null,
binLengthReference.pointer,
null,
variant.value
)
if (resultCode != 0) {
throw ConversionException()
}
return decoder.decode(data).asUByteArray()
return intermediaryResult.sliceArray(0 until binLengthReference.value)
}
actual fun fromHex(data: String): UByteArray {
// from hex is currently broken in lazysodium-java
// see https://github.com/terl/lazysodium-java/issues/83
return data.hexStringToUByteArray()
}
}

View File

@ -1,11 +1,2 @@
package com.ionspin.kotlin.crypto
import com.goterl.lazycode.lazysodium.LazySodiumJava
import com.goterl.lazycode.lazysodium.SodiumJava
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 22-Aug-2020
*/
typealias SodiumWrapper = SodiumJava

View File

@ -0,0 +1,23 @@
package com.ionspin.kotlin.crypto.jnitest
import com.ionspin.kotlin.crypto.LibsodiumInitializer
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
import com.ionspin.kotlin.crypto.util.runTest
import org.junit.Test
import kotlin.test.assertEquals
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 20-Feb-2021
*/
class JnaLibraryLoaderTest {
@Test
fun testIfLibraryIsLoaded() = runTest {
LibsodiumInitializer.initialize()
val version = sodiumJna.sodium_version_string()
println("Got loaded sodium version: $version")
assertEquals("1.0.18", version)
}
}

View File

@ -1,6 +1,6 @@
package com.ionspin.kotlin.crypto.secretstream
actual fun modifyState(state: SecretStreamState, forceNonce: UByteArray) {
state.nonce = forceNonce.sliceArray(12 until 24).asByteArray()
forceNonce.sliceArray(12 until 24).asByteArray().copyInto(state.nonce)
println("Nonce modified ${state.nonce}")
}

View File

@ -3,7 +3,6 @@ package com.ionspin.kotlin.crypto.stream
import com.ionspin.kotlin.crypto.util.toPtr
import kotlinx.cinterop.convert
import kotlinx.cinterop.pin
import libsodium.crypto_stream_KEYBYTES
import libsodium.crypto_stream_chacha20
import libsodium.crypto_stream_chacha20_ietf_xor
import libsodium.crypto_stream_chacha20_ietf_xor_ic
@ -11,6 +10,10 @@ import libsodium.crypto_stream_chacha20_keygen
import libsodium.crypto_stream_chacha20_xor
import libsodium.crypto_stream_chacha20_xor_ic
//import libsodium.crypto_stream_xchacha20_keygen
//import libsodium.crypto_stream_xchacha20_xor
//import libsodium.crypto_stream_xchacha20_xor_ic
actual object Stream {
actual fun chacha20(clen: Int, nonce: UByteArray, key: UByteArray): UByteArray {
val result = UByteArray(clen)
@ -149,4 +152,71 @@ actual object Stream {
return result
}
// actual fun xChacha20Keygen(): UByteArray {
// val result = UByteArray(crypto_stream_xchacha20_KEYBYTES)
// val resultPinned = result.pin()
//
// crypto_stream_xchacha20_keygen(resultPinned.toPtr())
//
// resultPinned.unpin()
//
// return result
// }
//
// actual fun xChacha20Xor(
// message: UByteArray,
// nonce: UByteArray,
// key: UByteArray
// ): UByteArray {
// val result = UByteArray(message.size)
// val messagePinned = message.pin()
// val resultPinned = result.pin()
// val noncePinned = nonce.pin()
// val keyPinned = key.pin()
//
// crypto_stream_xchacha20_xor(
// resultPinned.toPtr(),
// messagePinned.toPtr(),
// message.size.convert(),
// noncePinned.toPtr(),
// keyPinned.toPtr()
// )
//
// messagePinned.unpin()
// resultPinned.unpin()
// noncePinned.unpin()
// keyPinned.unpin()
//
// return result
// }
//
// actual fun xChacha20XorIc(
// message: UByteArray,
// nonce: UByteArray,
// initialCounter: ULong,
// key: UByteArray
// ): UByteArray {
// val result = UByteArray(message.size)
// val messagePinned = message.pin()
// val resultPinned = result.pin()
// val noncePinned = nonce.pin()
// val keyPinned = key.pin()
//
// crypto_stream_xchacha20_xor_ic(
// resultPinned.toPtr(),
// messagePinned.toPtr(),
// message.size.convert(),
// noncePinned.toPtr(),
// initialCounter.convert(),
// keyPinned.toPtr()
// )
//
// messagePinned.unpin()
// resultPinned.unpin()
// noncePinned.unpin()
// keyPinned.unpin()
//
// return result
// }
}

View File

@ -63,7 +63,7 @@ kotlin {
android()
runningOnLinuxx86_64 {
jvm()
js {
js(IR) {
browser {
webpackTask {
@ -188,7 +188,7 @@ kotlin {
implementation(kotlin(Deps.Common.test))
implementation(Deps.Common.kotlinBigNum)
implementation(Deps.Common.serialization)
api(Deps.Common.libsodiumBindings)
api(project(":multiplatform-crypto-libsodium-bindings"))
}
}
val commonTest by getting {

View File

@ -6,10 +6,19 @@ package com.ionspin.kotlin.crypto.sample
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodiumJna
import com.ionspin.kotlin.crypto.TmpAccessor
import com.ionspin.kotlin.crypto.box.Box
import com.ionspin.kotlin.crypto.box.BoxCorruptedOrTamperedDataException
import com.ionspin.kotlin.crypto.box.crypto_box_NONCEBYTES
import com.ionspin.kotlin.crypto.hash.Hash
import com.ionspin.kotlin.crypto.util.decodeFromUByteArray
import com.ionspin.kotlin.crypto.util.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.toHexString
import kotlinx.android.synthetic.main.activity_main.*
import java.lang.StringBuilder
import kotlin.random.Random
import kotlin.random.nextUBytes
class MainActivity : AppCompatActivity() {
@ -18,9 +27,25 @@ class MainActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val hash = Hash.sha512("123".encodeToUByteArray())
helloWorldTextView.setText("Hash (SHA512) of 123: ${hash.toHexString()}")
val message = "Message message message".encodeToUByteArray()
val senderKeypair = Box.keypair()
val recipientKeypair = Box.keypair()
val messageNonce = Random(0).nextUBytes(crypto_box_NONCEBYTES)
val builder = StringBuilder()
val encrypted = Box.easy(message, messageNonce, recipientKeypair.publicKey, senderKeypair.secretKey)
builder.appendLine("Encrypted: ${encrypted.toHexString()}")
val decrypted = Box.openEasy(encrypted, messageNonce, senderKeypair.publicKey, recipientKeypair.secretKey)
builder.appendLine("Decrypted: ${decrypted.decodeFromUByteArray()}")
try {
val tampered = encrypted.copyOf()
tampered[1] = 0U
Box.openEasy(tampered, messageNonce, senderKeypair.publicKey, recipientKeypair.secretKey)
} catch (exception : Exception) {
builder.appendLine("And caught tamper")
}
helloWorldTextView.setText(builder.toString())
}
}

View File

@ -7,11 +7,12 @@ import com.ionspin.kotlin.crypto.util.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.toHexString
import react.dom.render
import kotlinx.browser.document
import kotlin.browser.window
import kotlinx.browser.window
fun main() {
val runningOnNode = jsTypeOf(window) == "undefined"
if (!runningOnNode) = runTest {
// if (!runningOnNode) = runTest {
LibsodiumInitializer.initializeWithCallback {
render(document.getElementById("root")) {
app {
@ -19,10 +20,10 @@ fun main() {
}
}
}
} else = runTest {
LibsodiumInitializer.initializeWithCallback {
val hash = Hash.sha512("123".encodeToUByteArray())
println("Hash (SHA512) of 123: ${hash.toHexString()}")
}
}
// } else = runTest {
// LibsodiumInitializer.initializeWithCallback {
// val hash = Hash.sha512("123".encodeToUByteArray())
// println("Hash (SHA512) of 123: ${hash.toHexString()}")
// }
// }
}

View File

@ -37,5 +37,5 @@ enableFeaturePreview("GRADLE_METADATA")
rootProject.name = "KotlinMultiplatformLibsodium"
include("multiplatform-crypto-api")
include("multiplatform-crypto-libsodium-bindings")
//include("sample")
include("sample")

View File

@ -143,9 +143,9 @@ native libsodium library.
| crypto_stream_chacha20_xor | :heavy_check_mark: |
| crypto_stream_chacha20_xor_ic | :heavy_check_mark: |
| crypto_stream_keygen | Other XSalsa20 primitives are not available, so I'm leaving this out as well|
| crypto_stream_xchacha20_keygen | not present in LazySodium Android |
| crypto_stream_xchacha20_xor | not present in LazySodium Android|
| crypto_stream_xchacha20_xor_ic | not present in LazySodium Android |
| crypto_stream_xchacha20_keygen | Not at the moment |
| crypto_stream_xchacha20_xor | Not at the moment |
| crypto_stream_xchacha20_xor_ic | Not at the moment |
| randombytes_buf | :heavy_check_mark: |
| randombytes_buf_deterministic | :heavy_check_mark: |
| randombytes_close | not present in LazySodium |