From 1db254796770c018ef1d5fd2ea9ec0973f605e60 Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Thu, 11 Jun 2020 20:29:03 +0200 Subject: [PATCH] Bump version to 0.1.0 cause a lot of things changed since 0.0.4, mac builds are working, now to get Windows to work, updated readme, copied crypto API to pure variant --- README.md | 70 +++++++++++++------ buildSrc/src/main/kotlin/Deps.kt | 2 +- multiplatform-crypto/build.gradle.kts | 7 +- .../ionspin/kotlin/crypto/CryptoProvider.kt | 59 +++++++++++++++- .../crypto/keyderivation/argon2/Argon2Pure.kt | 4 +- .../com/ionspin/kotlin/crypto/ReadmeTest.kt | 2 +- 6 files changed, 112 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 727a258..d3ef323 100644 --- a/README.md +++ b/README.md @@ -5,16 +5,34 @@ Kotlin Multiplatform Crypto is a library for various cryptographic applications. -API is very opinionated, meant to be used on both encrypting and decrypting side. The idea is that API leaves less room for -errors when using it. - The library comes in two flavors `multiplatform-crypto` and `multiplatform-crypto-delegated` * `multiplatform-crypto` contains pure kotlin implementations, is not reviewed, should be considered unsafe and only for prototyping or experimentation purposes. -* `multiplatform-crypto-delegated` relies on platform specific implementations, like libsodium, but care should still be taken that the kotlin code is not reviewed or proven safe. +* `multiplatform-crypto-delegated` relies on platform specific implementations, like libsodium, but care should still be taken that the kotlin code is not reviewed or proven safe. +APIs of both variants are identical. + +## Supported platforms by variant +|Platform|Pure variant| Delegated variant| +|--------|------------|------------------| +|Linux X86 64| :heavy_check_mark: | :heavy_check_mark: | +|Linux Arm 64| :heavy_check_mark: | :heavy_check_mark: | +|Linux Arm 32| :heavy_check_mark: | :x: | +|macOS X86 64| :heavy_check_mark: | :heavy_check_mark: | +|iOS x86 64 | :heavy_check_mark: | :heavy_check_mark: | +|iOS Arm 64 | :heavy_check_mark: | :heavy_check_mark: | +|iOS Arm 32 | :heavy_check_mark: | :heavy_check_mark: | +|watchOS X86 32 | :heavy_check_mark: | :heavy_check_mark: | +|watchOS Arm 64(_32) | :heavy_check_mark: | :heavy_check_mark: | +|watchos Arm 32 | :heavy_check_mark: | :heavy_check_mark: | +|tvOS X86 64 | :heavy_check_mark: | :heavy_check_mark: | +|tvOS Arm 64 | :heavy_check_mark: | :heavy_check_mark: | +|minGW X86 64| :heavy_check_mark: | :heavy_check_mark: | +|minGW X86 32| :x: | :x: | + + ## Notes & Roadmap @@ -29,7 +47,7 @@ No, until it is reviewed. ## Should I use this in code that is *critical* in any way, shape or form? -No, but even if after being warned you decide to, then use `multiplatform-crypto-delegated`. +No, but even if after being warned you decide to, then use `multiplatform-crypto-delegated` as it relies on reputable libraries. ## Why? @@ -61,11 +79,11 @@ The following table describes which library is used for particular cryptographic | Primitive | JVM | JS | Native | | ----------|-----|----|--------| -| Blake2b | JCE | libsodium.js | libsodium | -| SHA256 | JCE | libsodium.js | libsodium -| SHA512 | JCE | libsodium.js | libsodium -| AES-CBC | JCE | libsodium.js | libsodium -| AES-CTR | JCE | libsodium.js | libsodium +| Blake2b | LazySodium | libsodium.js | libsodium | +| SHA256 | LazySodium | libsodium.js | libsodium | +| SHA512 | LazySodium | libsodium.js | libsodium | +| AES-CBC | LazySodium | libsodium.js | libsodium | +| AES-CTR | LazySodium | libsodium.js | libsodium | ## Integration @@ -93,6 +111,13 @@ implementation("com.ionspin.kotlin:multiplatform-crypto:0.0.6-SNAPSHOT") ## Usage +### Helper functions + +All API take `UByteArray` as message/key/nonce/etc parameter. For convenience when working with strings we provide +`String.enocdeToUbyteArray()` extensions function, and `UByteArray.toHexString` extension function. + +More convenience functions will be added. + ### Hashes Hashes are provided in two versions, "stateless", usually the companion object of the hash, @@ -108,7 +133,7 @@ You need to deliver the complete data that is to be hashed in one go ```kotlin val input = "abc" -val result = Blake2b.digest(input) +val result = Crypto.Blake2b.stateless(input.encodeToUByteArray()) ``` Result is returned as a `UByteArray` @@ -122,9 +147,9 @@ If you want to use Blake2b with a key, you should supply it when creating the `B ```kotlin val test = "abc" val key = "key" -val blake2b = Blake2b(key) -blake2b.update(test) -val result = blake2b.digest() +val blake2b = Crypto.Blake2b.updateable(key.encodeToUByteArray()) +blake2b.update(test.encodeToUByteArray()) +val result = blake2b.digest().toHexString() ``` After digest is called, the instance is reset and can be reused (Keep in mind key stays the same for the particular instance). @@ -137,12 +162,12 @@ or `String`. Result is always returned as `UByteArray` (At least in verision 0.0 ```kotlin val input = "abc" -val result = Sha256.digest(input) +val result = Crypto.Sha256.stateless(input.encodeToUByteArray()) ``` ```kotlin val input ="abc" -val result = Sha512.digest(message = input.encodeToByteArray().map { it.toUByte() }.toTypedArray()) +val result = Crypto.Sha512.stateless(input.encodeToUByteArray()) ``` Result is returned as a `UByteArray` @@ -152,19 +177,20 @@ Result is returned as a `UByteArray` Or you can use the updatable instance version ```kotlin -val sha256 = Sha256() -sha256.update("abc") +val sha256 = Crypto.Sha256.updateable() +sha256.update("abc".encodeToUByteArray()) val result = sha256.digest() ``` ```kotlin -val sha512 = Sha512() -sha512.update("abc") +val sha512 = Crypto.Sha512.updateable() +sha512.update("abc".encodeToUByteArray()) val result = sha512.digest() ``` -### Symmetric encryption -#### AES +### Symmetric encryption + +#### AES Aes is available with CBC and CTR mode through `AesCbc` and `AesCtr` classes/objects. Similarly to hashes you can either use stateless or updateable version. diff --git a/buildSrc/src/main/kotlin/Deps.kt b/buildSrc/src/main/kotlin/Deps.kt index 36bf5b6..550f95b 100644 --- a/buildSrc/src/main/kotlin/Deps.kt +++ b/buildSrc/src/main/kotlin/Deps.kt @@ -33,7 +33,7 @@ object Versions { object ReleaseInfo { val group = "com.ionspin.kotlin" - val version = "0.0.5-SNAPSHOT" + val version = "0.1.0-SNAPSHOT" } object Deps { diff --git a/multiplatform-crypto/build.gradle.kts b/multiplatform-crypto/build.gradle.kts index 75c174a..cd14d94 100644 --- a/multiplatform-crypto/build.gradle.kts +++ b/multiplatform-crypto/build.gradle.kts @@ -56,11 +56,12 @@ kotlin { browser { testTask { - isRunningInTravis { - enabled = false //Until I sort out testing on travis - } +// isRunningInTravis { + enabled = false //Until I sort out testing on travis, and figure out how to increase karma timeout +// } useKarma { useChrome() + } } } diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/CryptoProvider.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/CryptoProvider.kt index 86ddfa8..526d2d4 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/CryptoProvider.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/CryptoProvider.kt @@ -1,5 +1,6 @@ package com.ionspin.kotlin.crypto +import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bProperties import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bPure import com.ionspin.kotlin.crypto.hash.sha.Sha256Pure import com.ionspin.kotlin.crypto.hash.sha.Sha512Pure @@ -9,6 +10,58 @@ import com.ionspin.kotlin.crypto.hash.sha.Sha512Pure * ugljesa.jovanovic@ionspin.com * on 24-May-2020 */ -typealias Blake2bStateless = Blake2bPure.Companion -typealias Sha256Stateless = Sha256Pure.Companion -typealias Sha512Stateless = Sha512Pure.Companion \ No newline at end of file +typealias Blake2bPureStateless = Blake2bPure.Companion +typealias Sha256PureStateless = Sha256Pure.Companion +typealias Sha512PureStateless = Sha512Pure.Companion + +object Crypto : CryptoProvider { + override suspend fun initialize() { + //Nothing to do atm. + } + + fun initializeWithCallback(done: () -> Unit) { + done() + } + + + object Blake2b { + fun updateable(key: UByteArray? = null, hashLength: Int = Blake2bProperties.MAX_HASH_BYTES): com.ionspin.kotlin.crypto.hash.blake2b.Blake2b { + checkInitialization() + return Blake2bPure(key, hashLength) + } + + fun stateless(message: UByteArray, key: UByteArray = ubyteArrayOf(), hashLength: Int = Blake2bProperties.MAX_HASH_BYTES): UByteArray { + checkInitialization() + return Blake2bPureStateless.digest(message, key, hashLength) + } + } + + object Sha256 { + fun updateable(): com.ionspin.kotlin.crypto.hash.sha.Sha256 { + checkInitialization() + return Sha256Pure() + } + + fun stateless(message: UByteArray) : UByteArray{ + checkInitialization() + return Sha256PureStateless.digest(inputMessage = message) + } + } + + object Sha512 { + fun updateable(): com.ionspin.kotlin.crypto.hash.sha.Sha512 { + checkInitialization() + return Sha512Pure() + } + + fun stateless(message: UByteArray) : UByteArray { + checkInitialization() + return Sha512PureStateless.digest(inputMessage = message) + } + } + + private fun checkInitialization() { + // Nothing to do atm + } + +} \ No newline at end of file diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2Pure.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2Pure.kt index 1d98291..c7ccc50 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2Pure.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2Pure.kt @@ -19,7 +19,7 @@ package com.ionspin.kotlin.crypto.keyderivation.argon2 import com.ionspin.kotlin.bignum.integer.toBigInteger -import com.ionspin.kotlin.crypto.Blake2bStateless +import com.ionspin.kotlin.crypto.Blake2bPureStateless import com.ionspin.kotlin.crypto.SRNG import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.argonBlake2bArbitraryLenghtHash import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.compressionFunctionG @@ -296,7 +296,7 @@ class Argon2Pure( salt.size.toUInt().toLittleEndianUByteArray() + salt + key.size.toUInt().toLittleEndianUByteArray() + key + associatedData.size.toUInt().toLittleEndianUByteArray() + associatedData - val h0 = Blake2bStateless.digest( + val h0 = Blake2bPureStateless.digest( blakeInput ) diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/ReadmeTest.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/ReadmeTest.kt index 4dd4656..8b92c99 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/ReadmeTest.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/ReadmeTest.kt @@ -159,7 +159,7 @@ class ReadmeTest { @Test fun debugTest() { - val result = Blake2bStateless.digest("test".encodeToUByteArray()) + val result = Blake2bPureStateless.digest("test".encodeToUByteArray()) println(result.toHexString()) }