Completed blake2b, sha256 and sha512 delegated implementations

This commit is contained in:
Ugljesa Jovanovic 2020-06-09 22:13:21 +02:00 committed by Ugljesa Jovanovic
parent 6170dc0464
commit ce7b27da98
No known key found for this signature in database
GPG Key ID: 178E6DFCECCB0E0F
22 changed files with 244 additions and 181 deletions

View File

@ -23,34 +23,46 @@ object Crypto : CryptoProvider {
object Blake2b {
fun updateable(key: UByteArray? = null, hashLength: Int = Blake2bProperties.MAX_HASH_BYTES): com.ionspin.kotlin.crypto.hash.blake2b.Blake2b {
checkInitialization()
return Blake2bDelegated(key, hashLength)
}
fun stateless(message: UByteArray, key: UByteArray = ubyteArrayOf(), hashLength: Int = Blake2bProperties.MAX_HASH_BYTES): UByteArray {
checkInitialization()
return Blake2bDelegatedStateless.digest(message, key, hashLength)
}
}
object Sha256 {
fun updateable(): com.ionspin.kotlin.crypto.hash.sha.Sha256 {
checkInitialization()
return Sha256Delegated()
}
fun stateless(message: UByteArray) : UByteArray{
checkInitialization()
return Sha256StatelessDelegated.digest(inputMessage = message)
}
}
object Sha512 {
fun updateable(): com.ionspin.kotlin.crypto.hash.sha.Sha512 {
checkInitialization()
return Sha512Delegated()
}
fun stateless(message: UByteArray) : UByteArray {
checkInitialization()
return Sha512StatelessDelegated.digest(inputMessage = message)
}
}
private fun checkInitialization() {
if (!Initializer.isInitialized()) {
throw RuntimeException("Platform library not initialized, check if you called Initializer.initialize()")
}
}
}
@ -62,6 +74,8 @@ object SimpleCrypto {
}
expect object Initializer {
fun isInitialized() : Boolean
suspend fun initialize()
fun initializeWithCallback(done: () -> (Unit))

View File

@ -24,6 +24,6 @@ package com.ionspin.kotlin.crypto.hash.sha
*/
expect class Sha512Delegated(key: UByteArray? = null, hashLength: Int = Sha512Properties.MAX_HASH_BYTES) : Sha512
expect class Sha512Delegated() : Sha512
expect object Sha512StatelessDelegated : StatelessSha512

View File

@ -0,0 +1,45 @@
package com.ionspin.kotlin.crypto.hash.blake2b
import com.ionspin.kotlin.crypto.Crypto
import com.ionspin.kotlin.crypto.Initializer
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.testBlocking
import com.ionspin.kotlin.crypto.util.toHexString
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertTrue
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 09-Jun-2020
*/
class Blake2bTest {
@Test
fun statelessSimpleTest() = testBlocking {
Initializer.initialize()
val expected = "a71079d42853dea26e453004338670a53814b78137ffbed07603a41d76a483aa9bc33b582f77d30a65e6f29a89" +
"6c0411f38312e1d66e0bf16386c86a89bea572"
val result = Crypto.Blake2b.stateless("test".encodeToUByteArray()).toHexString()
// println("Result: $result")
assertTrue { result == expected }
}
//This is a bad test since it's not larger than one block
//but for now I'm testing that the platform library is being correctly called
@Test
fun updateableSimpleTest() = testBlocking {
Initializer.initialize()
val expected = "a71079d42853dea26e453004338670a53814b78137ffbed07603a41d76a483aa9bc33b582f77d30a65e6f29a89" +
"6c0411f38312e1d66e0bf16386c86a89bea572"
val blake2b = Crypto.Blake2b.updateable()
blake2b.update("t".encodeToUByteArray())
blake2b.update(("est".encodeToUByteArray()))
val result = blake2b.digest().toHexString()
// println("Result: $result")
assertTrue { result == expected }
}
}

View File

@ -1,8 +1,11 @@
package com.ionspin.kotlin.crypto.hash.sha
import com.ionspin.kotlin.crypto.Crypto
import com.ionspin.kotlin.crypto.Initializer
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.testBlocking
import com.ionspin.kotlin.crypto.util.toHexString
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertTrue
@ -12,11 +15,16 @@ import kotlin.test.assertTrue
* on 07-Jun-2020
*/
class Sha256Test {
@BeforeTest
fun beforeTest() = testBlocking {
Initializer.initialize()
}
@Test
fun statelessSimpleTest() {
val expected = "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
val result = Crypto.Sha256.stateless("test".encodeToUByteArray()).toHexString()
println("Result: $result")
// println("Result: $result")
assertTrue { result == expected }
}
@ -29,7 +37,7 @@ class Sha256Test {
sha256.update("t".encodeToUByteArray())
sha256.update(("est".encodeToUByteArray()))
val result = sha256.digest().toHexString()
println("Result: $result")
// println("Result: $result")
assertTrue { result == expected }
}
}

View File

@ -1,8 +1,11 @@
package com.ionspin.kotlin.crypto.hash.sha
import com.ionspin.kotlin.crypto.Crypto
import com.ionspin.kotlin.crypto.Initializer
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.testBlocking
import com.ionspin.kotlin.crypto.util.toHexString
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertTrue
@ -12,12 +15,17 @@ import kotlin.test.assertTrue
* on 07-Jun-2020
*/
class Sha512Test {
@BeforeTest
fun beforeTest() = testBlocking {
Initializer.initialize()
}
@Test
fun statelessSimpleTest() {
val expected = "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67" +
"b143732c304cc5fa9ad8e6f57f50028a8ff"
val result = Crypto.Sha512.stateless("test".encodeToUByteArray()).toHexString()
println("Result: $result")
// println("Result: $result")
assertTrue { result == expected }
}
@ -31,7 +39,7 @@ class Sha512Test {
sha512.update("t".encodeToUByteArray())
sha512.update(("est".encodeToUByteArray()))
val result = sha512.digest().toHexString()
println("Result: $result")
// println("Result: $result")
assertTrue { result == expected }
}
}

View File

@ -21,12 +21,22 @@ fun setSodiumLoaded(loaded: Boolean) {
}
actual object Initializer {
private var isPlatformInitialized = false
actual suspend fun initialize() {
JsSodiumLoader.load()
isPlatformInitialized = true
}
actual fun initializeWithCallback(done: () -> Unit) {
JsSodiumLoader.loadWithCallback {
isPlatformInitialized = true
done()
}
}
actual fun isInitialized(): Boolean {
return isPlatformInitialized
}

View File

@ -10,14 +10,23 @@ import org.khronos.webgl.Uint8Array
*/
interface JsSodiumInterface {
fun crypto_generichash(hashLength: Int, inputMessage: Uint8Array): Uint8Array
fun randombytes_buf(numberOfBytes: Int): Uint8Array
fun crypto_generichash(hashLength: Int, inputMessage: Uint8Array, key: Uint8Array,): Uint8Array
fun crypto_hash_sha256(message: Uint8Array): Uint8Array
fun crypto_hash_sha512(message: Uint8Array): Uint8Array
//Updateable
fun crypto_generichash_init(key : Uint8Array, hashLength: Int) : dynamic
fun crypto_generichash_update(state: dynamic, inputMessage: Uint8Array)
fun crypto_generichash_final(state: dynamic, hashLength: Int) : Uint8Array
fun crypto_hash_sha256_init() : dynamic
fun crypto_hash_sha256_update(state: dynamic, message: Uint8Array)

View File

@ -1,6 +1,7 @@
package com.ionspin.kotlin.crypto.hash.blake2b
import com.ionspin.kotlin.crypto.getSodium
import com.ionspin.kotlin.crypto.hash.sha.Sha256StatelessDelegated
import com.ionspin.kotlin.crypto.util.toHexString
import org.khronos.webgl.Uint8Array
import org.khronos.webgl.get
@ -12,18 +13,30 @@ import org.khronos.webgl.get
*/
actual class Blake2bDelegated actual constructor(key: UByteArray?, hashLength: Int) : Blake2b {
actual class Blake2bDelegated actual constructor(key: UByteArray?, val hashLength: Int) : Blake2b {
override val MAX_HASH_BYTES: Int = 64
override fun update(data: UByteArray) {
TODO("not implemented yet")
val state : dynamic
init {
state = getSodium().crypto_generichash_init(
Uint8Array(key?.toByteArray()?.toTypedArray() ?: arrayOf()),
hashLength
)
}
override fun update(data: UByteArray) {
getSodium().crypto_generichash_update(state, Uint8Array(data.toByteArray().toTypedArray()))
}
override fun digest(): UByteArray {
TODO("not implemented yet")
val hashed = getSodium().crypto_generichash_final(state, hashLength)
val hash = UByteArray(hashLength)
for (i in 0 until hashLength) {
hash[i] = hashed[i].toUByte()
}
return hash
}
}
@ -34,9 +47,12 @@ actual object Blake2bDelegatedStateless : Blake2bStateless {
override val MAX_HASH_BYTES: Int = 64
override fun digest(inputMessage: UByteArray, key: UByteArray, hashLength: Int): UByteArray {
val hashed = getSodium().crypto_generichash(64, Uint8Array(inputMessage.toByteArray().toTypedArray()))
val hash = UByteArray(MAX_HASH_BYTES)
for (i in 0 until MAX_HASH_BYTES) {
val hashed = getSodium().crypto_generichash(hashLength,
Uint8Array(inputMessage.toByteArray().toTypedArray()),
Uint8Array(key.toByteArray().toTypedArray())
)
val hash = UByteArray(hashLength)
for (i in 0 until hashLength) {
hash[i] = hashed[i].toUByte()
}
return hash

View File

@ -1,9 +1,6 @@
package com.ionspin.kotlin.crypto.hash.sha
import com.ionspin.kotlin.crypto.getSodium
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bDelegatedStateless
import ext.libsodium.crypto_hash_sha256_init
import org.khronos.webgl.Uint8Array
import org.khronos.webgl.get
@ -15,7 +12,7 @@ import org.khronos.webgl.get
*/
actual class Sha256Delegated actual constructor() : Sha256 {
actual class Sha256Delegated : Sha256 {
val state : dynamic

View File

@ -13,7 +13,7 @@ import org.khronos.webgl.get
*/
actual class Sha512Delegated actual constructor(key: UByteArray?, hashLength: Int) : Sha512 {
actual class Sha512Delegated : Sha512 {
val state : dynamic
init {

View File

@ -34,14 +34,14 @@ class SRNGJsTest {
JsSodiumLoader.load()
val bytes1 = SRNG.getRandomBytes(10)
val bytes2 = SRNG.getRandomBytes(10)
println("BYTES1\n")
bytes1.forEach {
print(it.toString(16).padStart(2, '0'))
}
println("BYTES2\n")
bytes2.forEach {
print(it.toString(16).padStart(2, '0'))
}
// println("BYTES1\n")
// bytes1.forEach {
// print(it.toString(16).padStart(2, '0'))
// }
// println("BYTES2\n")
// bytes2.forEach {
// print(it.toString(16).padStart(2, '0'))
// }
assertTrue {
!bytes1.contentEquals(bytes2) &&
bytes1.size == 10 &&

View File

@ -1,27 +0,0 @@
package com.ionspin.kotlin.crypto.hash.blake2b
import com.ionspin.kotlin.crypto.Crypto
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.testBlocking
import com.ionspin.kotlin.crypto.util.toHexString
import kotlin.test.Test
import kotlin.test.assertEquals
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 25-May-2020
*/
class Blake2bJsTest {
@Test
fun testBlake2BSodiumInterop() = testBlocking {
Crypto.initialize()
val hash = Blake2bDelegatedStateless.digest("test".encodeToUByteArray())
assertEquals(hash.toHexString(), "a71079d42853dea26e453004338670a53814b78137ffbed07603a41d76a4" +
"83aa9bc33b582f77d30a65e6f29a896c0411f38312e1d66e0bf16386c86a89bea572")
}
}

View File

@ -1,9 +1,25 @@
package com.ionspin.kotlin.crypto
import com.goterl.lazycode.lazysodium.SodiumJava
actual object Initializer {
private var isPlatformInitialized = false
lateinit var sodium : SodiumJava
actual suspend fun initialize() {
sodium = SodiumJava()
isPlatformInitialized = true
}
actual fun initializeWithCallback(done: () -> Unit) {
sodium = SodiumJava()
isPlatformInitialized = true
done()
}
actual fun isInitialized(): Boolean {
return isPlatformInitialized
}
}

View File

@ -1,5 +1,6 @@
package com.ionspin.kotlin.crypto.hash.blake2b
import com.ionspin.kotlin.crypto.Initializer.sodium
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
@ -7,14 +8,22 @@ package com.ionspin.kotlin.crypto.hash.blake2b
*/
actual class Blake2bDelegated actual constructor(key: UByteArray?, hashLength: Int) : Blake2b {
actual class Blake2bDelegated actual constructor(key: UByteArray?, val hashLength: Int) : Blake2b {
val state = ByteArray(sodium.crypto_generichash_statebytes())
init {
sodium.crypto_generichash_init(state,key?.toByteArray() ?: byteArrayOf(), key?.size ?: 0, hashLength)
}
override fun update(data: UByteArray) {
TODO("not implemented yet")
sodium.crypto_generichash_update(state, data.toByteArray(), data.size.toLong())
}
override fun digest(): UByteArray {
TODO("not implemented yet")
val hashed = ByteArray(hashLength)
sodium.crypto_generichash_final(state, hashed, hashLength)
return hashed.toUByteArray()
}
}
@ -23,7 +32,9 @@ actual object Blake2bDelegatedStateless : Blake2bStateless {
override fun digest(inputMessage: UByteArray, key: UByteArray, hashLength: Int): UByteArray {
TODO("not implemented yet")
val hashed = ByteArray(hashLength)
sodium.crypto_generichash(hashed, hashed.size, inputMessage.toByteArray(), inputMessage.size.toLong(), key.toByteArray(), key.size)
return hashed.toUByteArray()
}
}

View File

@ -0,0 +1,41 @@
package com.ionspin.kotlin.crypto.hash.sha
import com.goterl.lazycode.lazysodium.interfaces.Hash
import com.ionspin.kotlin.crypto.Initializer.sodium
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 17-Jul-2019
*/
actual class Sha256Delegated actual constructor() : Sha256 {
val state = Hash.State256()
init {
sodium.crypto_hash_sha256_init(state)
}
override fun update(data: UByteArray) {
sodium.crypto_hash_sha256_update(state, data.toByteArray(), data.size.toLong())
}
override fun digest(): UByteArray {
val hashed = ByteArray(Sha256Properties.MAX_HASH_BYTES)
sodium.crypto_hash_sha256_final(state, hashed)
return hashed.toUByteArray()
}
}
actual object Sha256StatelessDelegated : StatelessSha256 {
override fun digest(inputMessage: UByteArray): UByteArray {
val hashed = ByteArray(Sha256Properties.MAX_HASH_BYTES)
sodium.crypto_hash_sha256(hashed, inputMessage.toByteArray(), inputMessage.size.toLong())
return hashed.toUByteArray()
}
}

View File

@ -1,32 +0,0 @@
package com.ionspin.kotlin.crypto.hash.sha
import java.security.MessageDigest
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 17-Jul-2019
*/
actual class Sha256Delegated actual constructor(key: UByteArray?, hashLength: Int) : Sha256 {
override fun update(data: UByteArray) {
TODO("not implemented yet")
}
override fun digest(): UByteArray {
TODO("not implemented yet")
}
}
actual object Sha256StatelessDelegated : StatelessSha256 {
override fun digest(inputMessage: UByteArray): UByteArray {
val messageDigest = MessageDigest.getInstance("SHA-256")
messageDigest.update(inputMessage.toByteArray())
return messageDigest.digest().toUByteArray()
}
}

View File

@ -1,5 +1,8 @@
package com.ionspin.kotlin.crypto.hash.sha
import com.goterl.lazycode.lazysodium.interfaces.Hash
import com.ionspin.kotlin.crypto.Initializer
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
@ -7,13 +10,22 @@ package com.ionspin.kotlin.crypto.hash.sha
*/
actual class Sha512Delegated actual constructor(key: UByteArray?, hashLength: Int) : Sha512 {
actual class Sha512Delegated : Sha512 {
val state = Hash.State512()
init {
Initializer.sodium.crypto_hash_sha512_init(state)
}
override fun update(data: UByteArray) {
TODO("not implemented yet")
Initializer.sodium.crypto_hash_sha512_update(state, data.toByteArray(), data.size.toLong())
}
override fun digest(): UByteArray {
TODO("not implemented yet")
val hashed = ByteArray(Sha512Properties.MAX_HASH_BYTES)
Initializer.sodium.crypto_hash_sha512_final(state, hashed)
return hashed.toUByteArray()
}
}
@ -21,6 +33,8 @@ actual class Sha512Delegated actual constructor(key: UByteArray?, hashLength: In
actual object Sha512StatelessDelegated : StatelessSha512 {
override fun digest(inputMessage: UByteArray): UByteArray {
TODO("not implemented yet")
val hashed = ByteArray(Sha512Properties.MAX_HASH_BYTES)
Initializer.sodium.crypto_hash_sha512(hashed, inputMessage.toByteArray(), inputMessage.size.toLong())
return hashed.toUByteArray()
}
}

View File

@ -1,19 +1,33 @@
package com.ionspin.kotlin.crypto
import kotlinx.atomicfu.AtomicBoolean
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import libsodium.sodium_init
import kotlin.native.concurrent.AtomicInt
actual object Initializer {
private var isPlatformInitialized : AtomicInt = AtomicInt(0)
actual suspend fun initialize() {
GlobalScope.launch {
sodium_init()
GlobalScope.launch() {
if (isPlatformInitialized.compareAndSet(0, 1)) {
sodium_init()
}
}
}
actual fun initializeWithCallback(done: () -> Unit) {
sodium_init()
if (isPlatformInitialized.compareAndSet(0, 1)) {
sodium_init()
}
done()
}
actual fun isInitialized(): Boolean {
return isPlatformInitialized.value != 0
}
}

View File

@ -13,7 +13,7 @@ import platform.posix.malloc
*/
actual class Sha256Delegated actual constructor() : Sha256 {
actual class Sha256Delegated : Sha256 {
val state : crypto_hash_sha256_state

View File

@ -12,7 +12,7 @@ import platform.posix.malloc
*/
actual class Sha512Delegated actual constructor(key: UByteArray?, hashLength: Int) : Sha512 {
actual class Sha512Delegated : Sha512 {
val state : crypto_hash_sha512_state
init {

View File

@ -1,40 +0,0 @@
package com.ionspin.kotlin.crypto.hash.blake2b
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 24-May-2020
*/
import com.ionspin.kotlin.crypto.Crypto
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.testBlocking
import com.ionspin.kotlin.crypto.util.toHexString
import kotlinx.coroutines.runBlocking
import kotlin.test.Test
import kotlin.test.assertTrue
class Blake2bLinuxTest {
@Test
fun testCinterop() {
runBlocking {
Crypto.initialize()
}
}
@Test
fun testBlake2bUpdateable() = testBlocking {
val blake2b = Crypto.Blake2b.updateable()
blake2b.update("test".encodeToUByteArray())
val result = blake2b.digest().toHexString()
println(result)
assertTrue { result.length > 2 }
}
@Test
fun testBlake2BStateless() = testBlocking {
Blake2bDelegatedStateless.digest("test".encodeToUByteArray())
}
}

View File

@ -1,41 +0,0 @@
package com.ionspin.kotlin.crypto.hash.blake2b
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 24-May-2020
*/
import com.ionspin.kotlin.crypto.Crypto
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.testBlocking
import com.ionspin.kotlin.crypto.util.toHexString
import kotlinx.coroutines.runBlocking
import kotlin.test.Test
import kotlin.test.assertTrue
class Sha512DelegatedLinuxTest {
@Test
fun testCinterop() {
runBlocking {
Crypto.initialize()
}
}
@Test
fun testBlake2bUpdateable() = testBlocking {
val blake2b = Crypto.Blake2b.updateable()
blake2b.update("test".encodeToUByteArray())
val result = blake2b.digest().toHexString()
println(result)
assertTrue { result.length > 2 }
}
@Test
fun testBlake2BStateless() = testBlocking {
val result = Blake2bDelegatedStateless.digest("test".encodeToUByteArray())
println(result.toHexString())
}
}