From 15be7071145b5cf15d38f6c476d0503d9c9df7a3 Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Mon, 31 Aug 2020 20:44:37 +0200 Subject: [PATCH] Added sha2 hashes in common and native and test --- .../generichash/GenericHash.kt | 19 +++- .../com.ionspin.kotlin.crypto/hash/Hash.kt | 31 ++++++ .../ionspin/kotlin/crypto/hash/HashTest.kt | 77 +++++++++++++++ .../kotlin/crypto/JsSodiumInterface.kt | 22 ++++- .../kotlin/crypto/generichash/GenericHash.kt | 31 ++++++ .../com/ionspin/kotlin/crypto/hash/Hash.kt | 39 ++++++++ .../com/ionspin/kotlin/crypto/hash/Hash.kt | 98 +++++++++++++++++++ 7 files changed, 313 insertions(+), 4 deletions(-) create mode 100644 multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/hash/Hash.kt create mode 100644 multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/HashTest.kt create mode 100644 multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt create mode 100644 multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt diff --git a/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/generichash/GenericHash.kt b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/generichash/GenericHash.kt index cddacce..c778647 100644 --- a/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/generichash/GenericHash.kt +++ b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/generichash/GenericHash.kt @@ -7,10 +7,18 @@ package com.ionspin.kotlin.crypto.generichash */ val crypto_generichash_BYTES = 32 +val crypto_generichash_blake2b_BYTES_MIN = 16 +val crypto_generichash_blake2b_BYTES_MAX = 64 +val crypto_generichash_blake2b_BYTES = 32 +val crypto_generichash_blake2b_KEYBYTES_MIN = 16 +val crypto_generichash_blake2b_KEYBYTES_MAX = 64 +val crypto_generichash_blake2b_KEYBYTES = 32 +val crypto_generichash_blake2b_SALTBYTES = 16 + +expect class GenericHashStateInternal data class GenericHashState(val hashLength: Int, val internalState: GenericHashStateInternal) -expect class GenericHashStateInternal expect object GenericHash { @@ -21,6 +29,15 @@ expect object GenericHash { fun genericHashFinal(state : GenericHashState) : UByteArray fun genericHashKeygen() : UByteArray +// ---- Not present in LazySodium nor libsodium.js +// fun blake2b(message : UByteArray, requestedHashLength: Int, key : UByteArray? = null) : UByteArray +// +// fun blake2bInit(requestedHashLength: Int, key : UByteArray? = null) : Blake2bState +// fun blake2bUpdate(state: GenericHashState, messagePart : UByteArray) +// fun blake2bFinal(state : GenericHashState) : UByteArray +// +// fun blake2bKeygen() : UByteArray + } diff --git a/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/hash/Hash.kt b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/hash/Hash.kt new file mode 100644 index 0000000..77a787c --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/hash/Hash.kt @@ -0,0 +1,31 @@ +package com.ionspin.kotlin.crypto.hash + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 31-Aug-2020 + */ + +val crypto_hash_BYTES = 64 +val crypto_hash_sha256_BYTES = 32 +val crypto_hash_sha512_BYTES = 64 + +expect class Sha256State +expect class Sha512State + +expect object Hash { + + fun hash(data: UByteArray) : UByteArray + + fun sha256(data: UByteArray) : UByteArray + fun sha256Init() : Sha256State + fun sha256Update(state: Sha256State, data : UByteArray) + fun sha256Final(state : Sha256State) : UByteArray + + fun sha512(data: UByteArray) : UByteArray + fun sha512Init() : Sha512State + fun sha512Update(state: Sha512State, data : UByteArray) + fun sha512Final(state : Sha512State) : UByteArray + + +} diff --git a/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/HashTest.kt b/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/HashTest.kt new file mode 100644 index 0000000..b88df15 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/HashTest.kt @@ -0,0 +1,77 @@ +package com.ionspin.kotlin.crypto.hash + +import com.ionspin.kotlin.crypto.LibsodiumInitializer +import com.ionspin.kotlin.crypto.util.encodeToUByteArray +import com.ionspin.kotlin.crypto.util.hexStringToUByteArray +import com.ionspin.kotlin.crypto.util.toHexString +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 31-Aug-2020 + */ +class HashTest { + @Test + fun hashTest() { + LibsodiumInitializer.initializeWithCallback { + val input = ("Input for various hash functions").encodeToUByteArray() + val expected = ("34fcbcdcfe9e6aa3e6d5a64649afcfafb449c4b8435a65e5e7b7c2b6af3b04da350acee" + + "838246d7c2637021def0c844fcb79ac42d6a50279f1078e535997b6e6").hexStringToUByteArray() + + val result = Hash.hash(input) + assertTrue { + result.contentEquals(expected) + } + } + + } + + + @Test + fun hashTestSha256() { + LibsodiumInitializer.initializeWithCallback { + val input = ("Input for various hash functions").encodeToUByteArray() + val expected = ("2bb078ec5993b5428355ba49bf030b1ac7" + + "1519e635aebc2f28124fac2aef9264").hexStringToUByteArray() + + val result = Hash.sha256(input) + assertTrue { + result.contentEquals(expected) + } + + val sha256State = Hash.sha256Init() + Hash.sha256Update(sha256State, input) + val multipartResult = Hash.sha256Final(sha256State) + assertTrue { + multipartResult.contentEquals(expected) + } + } + + } + + @Test + fun hashTestSha512() { + LibsodiumInitializer.initializeWithCallback { + val input = ("Input for various hash functions").encodeToUByteArray() + val expected = ("34fcbcdcfe9e6aa3e6d5a64649afcfafb449c4b8435a65e5e7b7c2b6af3b04da350acee" + + "838246d7c2637021def0c844fcb79ac42d6a50279f1078e535997b6e6").hexStringToUByteArray() + + val result = Hash.sha512(input) + assertTrue { + result.contentEquals(expected) + } + + val sha512State = Hash.sha512Init() + Hash.sha512Update(sha512State, input) + val multipartResult = Hash.sha512Final(sha512State) + assertTrue { + multipartResult.contentEquals(expected) + } + } + + } + + +} diff --git a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt index 2bc4158..37880e3 100644 --- a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt +++ b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt @@ -18,7 +18,7 @@ interface JsSodiumInterface { fun crypto_hash_sha512(message: Uint8Array): Uint8Array - //Updateable + // ---- Generic hash ---- // Updateable fun crypto_generichash_init(key : Uint8Array, hashLength: Int) : dynamic @@ -28,11 +28,27 @@ interface JsSodiumInterface { fun crypto_generichash_keygen() : Uint8Array - //Short hash + // ---- Generic hash end ---- // Updateable + + // ---- Blake2b ---- + + fun crypto_generichash_blake2b(hashLength: Int, inputMessage: Uint8Array, key: Uint8Array): Uint8Array + + fun crypto_generichash_blake2b_init(key : Uint8Array, hashLength: Int) : dynamic + + fun crypto_generichash_blake2b_update(state: dynamic, inputMessage: Uint8Array) + + fun crypto_generichash_blake2b_final(state: dynamic, hashLength: Int) : Uint8Array + + fun crypto_generichash_blake2b_keygen() : Uint8Array + + // ---- Blake2b end ---- + + // ---- Short hash ---- fun crypto_shorthash(data : Uint8Array, key: Uint8Array) : Uint8Array fun crypto_shorthash_keygen() : Uint8Array - + // ---- Short hash end ---- fun crypto_hash_sha256_init() : dynamic diff --git a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/generichash/GenericHash.kt b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/generichash/GenericHash.kt index bcd6d3c..3ea5001 100644 --- a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/generichash/GenericHash.kt +++ b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/generichash/GenericHash.kt @@ -48,4 +48,35 @@ actual object GenericHash { actual fun genericHashKeygen(): UByteArray { return getSodium().crypto_generichash_keygen().toUByteArray() } +// -- Not present in LazySodium nor libsodium.js +// actual fun blake2b(message: UByteArray, requestedHashLength: Int, key: UByteArray?) : UByteArray { +// return getSodium().crypto_generichash_blake2b( +// requestedHashLength, +// message.toUInt8Array(), +// key?.toUInt8Array() ?: Uint8Array(0) +// ).toUByteArray() +// } +// +// actual fun blake2bInit( +// requestedHashLength: Int, +// key: UByteArray? +// ): Blake2bState { +// val state = getSodium().crypto_generichash_blake2b_init(key?.toUInt8Array() ?: Uint8Array(0), requestedHashLength) +// return Blake2bState(requestedHashLength, state) +// } +// +// actual fun blake2bUpdate( +// state: GenericHashState, +// messagePart: UByteArray +// ) { +// getSodium().crypto_generichash_blake2b_update(state.internalState, messagePart.toUInt8Array()) +// } +// +// actual fun blake2bFinal(state: GenericHashState): UByteArray { +// return getSodium().crypto_generichash_blake2b_final(state.internalState, state.hashLength).toUByteArray() +// } +// +// actual fun blake2bKeygen(): UByteArray { +// return getSodium().crypto_generichash_blake2b_keygen().toUByteArray() +// } } diff --git a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt new file mode 100644 index 0000000..9746dd6 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt @@ -0,0 +1,39 @@ +package com.ionspin.kotlin.crypto.hash + +actual object Hash { + actual fun hash(data: UByteArray): UByteArray { + TODO("not implemented yet") + } + + actual fun sha256(data: UByteArray): UByteArray { + TODO("not implemented yet") + } + + actual fun sha256Init(): Sha256State { + TODO("not implemented yet") + } + + actual fun sha256Update(state: Sha256State, data: UByteArray) { + } + + actual fun sha256Final(state: Sha256State): UByteArray { + TODO("not implemented yet") + } + + actual fun sha512(data: UByteArray): UByteArray { + TODO("not implemented yet") + } + + actual fun sha512Init(): Sha512State { + TODO("not implemented yet") + } + + actual fun sha512Update(state: Sha512State, data: UByteArray) { + } + + actual fun sha512Final(state: Sha512State): UByteArray { + TODO("not implemented yet") + } + + +} diff --git a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt new file mode 100644 index 0000000..5b76344 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt @@ -0,0 +1,98 @@ +package com.ionspin.kotlin.crypto.hash + +import com.ionspin.kotlin.crypto.util.toPtr +import kotlinx.cinterop.convert +import kotlinx.cinterop.pin +import kotlinx.cinterop.pointed +import kotlinx.cinterop.ptr +import kotlinx.cinterop.reinterpret +import libsodium.crypto_hash +import libsodium.crypto_hash_sha256 +import libsodium.crypto_hash_sha256_final +import libsodium.crypto_hash_sha256_init +import libsodium.crypto_hash_sha256_state +import libsodium.crypto_hash_sha256_update +import libsodium.crypto_hash_sha512 +import libsodium.crypto_hash_sha512_final +import libsodium.crypto_hash_sha512_init +import libsodium.crypto_hash_sha512_state +import libsodium.crypto_hash_sha512_update +import platform.posix.malloc + +actual typealias Sha256State = crypto_hash_sha256_state +actual typealias Sha512State = crypto_hash_sha512_state + +actual object Hash { + actual fun hash(data: UByteArray): UByteArray { + val hashResult = UByteArray(crypto_hash_BYTES) + val hashResultPinned = hashResult.pin() + val dataPinned = data.pin() + crypto_hash(hashResultPinned.toPtr(), dataPinned.toPtr(), data.size.convert()) + hashResultPinned.unpin() + dataPinned.unpin() + + return hashResult + } + + actual fun sha256(data: UByteArray): UByteArray { + val hashResult = UByteArray(crypto_hash_sha256_BYTES) + val hashResultPinned = hashResult.pin() + val dataPinned = data.pin() + crypto_hash_sha256(hashResultPinned.toPtr(), dataPinned.toPtr(), data.size.convert()) + hashResultPinned.unpin() + dataPinned.unpin() + + return hashResult + } + + actual fun sha256Init(): Sha256State { + val stateAllocated = malloc(Sha256State.size.convert()) + val statePointed = stateAllocated!!.reinterpret().pointed + crypto_hash_sha256_init(statePointed.ptr) + return statePointed + } + + actual fun sha256Update(state: Sha256State, data: UByteArray) { + val dataPinned = data.pin() + crypto_hash_sha256_update(state.ptr, dataPinned.toPtr(), data.size.convert()) + } + + actual fun sha256Final(state: Sha256State): UByteArray { + val hashResult = UByteArray(crypto_hash_sha256_BYTES) + val hashResultPinned = hashResult.pin() + crypto_hash_sha256_final(state.ptr, hashResultPinned.toPtr()) + return hashResult + } + + actual fun sha512(data: UByteArray): UByteArray { + val hashResult = UByteArray(crypto_hash_sha512_BYTES) + val hashResultPinned = hashResult.pin() + val dataPinned = data.pin() + crypto_hash_sha512(hashResultPinned.toPtr(), dataPinned.toPtr(), data.size.convert()) + hashResultPinned.unpin() + dataPinned.unpin() + + return hashResult + } + + actual fun sha512Init(): Sha512State { + val stateAllocated = malloc(Sha512State.size.convert()) + val statePointed = stateAllocated!!.reinterpret().pointed + crypto_hash_sha512_init(statePointed.ptr) + return statePointed + } + + actual fun sha512Update(state: Sha512State, data: UByteArray) { + val dataPinned = data.pin() + crypto_hash_sha512_update(state.ptr, dataPinned.toPtr(), data.size.convert()) + } + + actual fun sha512Final(state: Sha512State): UByteArray { + val hashResult = UByteArray(crypto_hash_sha512_BYTES) + val hashResultPinned = hashResult.pin() + crypto_hash_sha512_final(state.ptr, hashResultPinned.toPtr()) + return hashResult + } + + +}