[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-wallet-kotlin] 02/02: Add incremental hashing (needed for creatin
From: |
gnunet |
Subject: |
[taler-wallet-kotlin] 02/02: Add incremental hashing (needed for creating refresh sessions) |
Date: |
Tue, 30 Jun 2020 21:04:28 +0200 |
This is an automated email from the git hooks/post-receive script.
torsten-grote pushed a commit to branch master
in repository wallet-kotlin.
commit 08f5f3618b5a9d9f38f7da0dbff39164c8b5f77b
Author: Torsten Grote <t@grobox.de>
AuthorDate: Tue Jun 30 16:04:04 2020 -0300
Add incremental hashing (needed for creating refresh sessions)
---
build.gradle | 2 +-
.../taler/wallet/kotlin/crypto/CryptoFactory.kt | 25 +++++++++++
.../net/taler/wallet/kotlin/crypto/Crypto.kt | 5 +++
.../net/taler/wallet/kotlin/crypto/Sha512Test.kt | 40 ++++++++++++++++-
.../taler/wallet/kotlin/crypto/CryptoFactory.kt | 36 ++++++++++++++--
.../taler/wallet/kotlin/crypto/CryptoFactory.kt | 50 +++++++++++++++++++++-
6 files changed, 151 insertions(+), 7 deletions(-)
diff --git a/build.gradle b/build.gradle
index 727b42c..8ae318e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -67,7 +67,7 @@ kotlin {
implementation kotlin('stdlib-js')
implementation npm('tweetnacl', '1.0.3')
implementation npm('ed2curve', '0.3.0')
- implementation npm('fast-sha256', '1.3.0')
+ implementation npm('hash.js', '1.1.7')
}
}
jsTest {
diff --git
a/src/androidMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
b/src/androidMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
index 7435c3f..b54d93e 100644
--- a/src/androidMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
+++ b/src/androidMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
@@ -3,6 +3,7 @@ package net.taler.wallet.kotlin.crypto
import com.goterl.lazycode.lazysodium.LazySodiumJava
import com.goterl.lazycode.lazysodium.SodiumJava
import com.goterl.lazycode.lazysodium.interfaces.Hash
+import com.goterl.lazycode.lazysodium.interfaces.Hash.State512
import com.goterl.lazycode.lazysodium.interfaces.KeyExchange
import com.goterl.lazycode.lazysodium.interfaces.Sign
import com.goterl.lazycode.lazysodium.utils.Key
@@ -27,6 +28,10 @@ internal object CryptoJvmImpl : CryptoImpl() {
return output
}
+ override fun getHashSha512State(): HashSha512State {
+ return JvmHashSha512State()
+ }
+
override fun getRandomBytes(num: Int): ByteArray {
return sodium.randomBytesBuf(num)
}
@@ -88,4 +93,24 @@ internal object CryptoJvmImpl : CryptoImpl() {
return RsaBlinding.rsaVerify(hm, rsaSig, rsaPubEnc)
}
+ private class JvmHashSha512State : HashSha512State {
+ private val state = State512()
+
+ init {
+ check(sodium.cryptoHashSha512Init(state)) { "Error doing
cryptoHashSha512Init" }
+ }
+
+ override fun update(data: ByteArray): HashSha512State {
+ sodium.cryptoHashSha512Update(state, data, data.size.toLong())
+ return this
+ }
+
+ override fun final(): ByteArray {
+ val output = ByteArray(Hash.SHA512_BYTES)
+ sodium.cryptoHashSha512Final(state, output)
+ return output
+ }
+
+ }
+
}
diff --git a/src/commonMain/kotlin/net/taler/wallet/kotlin/crypto/Crypto.kt
b/src/commonMain/kotlin/net/taler/wallet/kotlin/crypto/Crypto.kt
index 7019310..7c5fa29 100644
--- a/src/commonMain/kotlin/net/taler/wallet/kotlin/crypto/Crypto.kt
+++ b/src/commonMain/kotlin/net/taler/wallet/kotlin/crypto/Crypto.kt
@@ -3,6 +3,7 @@ package net.taler.wallet.kotlin.crypto
internal interface Crypto {
fun sha256(input: ByteArray): ByteArray
fun sha512(input: ByteArray): ByteArray
+ fun getHashSha512State(): HashSha512State
fun getRandomBytes(num: Int): ByteArray
fun eddsaGetPublic(eddsaPrivateKey: ByteArray): ByteArray
fun ecdheGetPublic(ecdhePrivateKey: ByteArray): ByteArray
@@ -19,6 +20,10 @@ internal interface Crypto {
fun setupRefreshPlanchet(secretSeed: ByteArray, coinNumber: Int): FreshCoin
}
+interface HashSha512State {
+ fun update(data: ByteArray): HashSha512State
+ fun final(): ByteArray
+}
class EddsaKeyPair(val privateKey: ByteArray, val publicKey: ByteArray)
class EcdheKeyPair(val privateKey: ByteArray, val publicKey: ByteArray)
data class FreshCoin(val coinPublicKey: ByteArray, val coinPrivateKey:
ByteArray, val bks: ByteArray) {
diff --git a/src/commonTest/kotlin/net/taler/wallet/kotlin/crypto/Sha512Test.kt
b/src/commonTest/kotlin/net/taler/wallet/kotlin/crypto/Sha512Test.kt
index c401b73..309e053 100644
--- a/src/commonTest/kotlin/net/taler/wallet/kotlin/crypto/Sha512Test.kt
+++ b/src/commonTest/kotlin/net/taler/wallet/kotlin/crypto/Sha512Test.kt
@@ -1,10 +1,10 @@
package net.taler.wallet.kotlin.crypto
import net.taler.wallet.kotlin.Base32Crockford
+import kotlin.random.Random
import kotlin.test.Test
import kotlin.test.assertEquals
-@kotlin.ExperimentalStdlibApi
class Sha512Test {
private val crypto = CryptoFactory.getCrypto()
@@ -59,4 +59,42 @@ class Sha512Test {
assertEquals(output,
Base32Crockford.encode(crypto.sha512(Base32Crockford.decode(input))))
}
+ @Test
+ fun testIncrementalHashing() {
+ val n = 1024
+ val d = Random.nextBytes(n)
+
+ val h1 = crypto.sha512(d)
+ val h2 = crypto.getHashSha512State().update(d).final()
+ assertEquals(Base32Crockford.encode(h1), Base32Crockford.encode(h2))
+
+ val s = crypto.getHashSha512State()
+ for (i in 0 until n) {
+ val b = ByteArray(1)
+ b[0] = d[i]
+ s.update(b)
+ }
+ val h3 = s.final()
+ assertEquals(Base32Crockford.encode(h1), Base32Crockford.encode(h3))
+ }
+
+ @Test
+ fun testIncrementalHashing2() {
+ val n = 10
+ val d = Random.nextBytes(n)
+
+ val h1 = crypto.sha512(d)
+ val h2 = crypto.getHashSha512State().update(d).final()
+ assertEquals(Base32Crockford.encode(h1), Base32Crockford.encode(h2))
+
+ val s = crypto.getHashSha512State()
+ for (i in 0 until n) {
+ val b = ByteArray(1)
+ b[0] = d[i]
+ s.update(b)
+ }
+ val h3 = s.final()
+ assertEquals(Base32Crockford.encode(h1), Base32Crockford.encode(h3))
+ }
+
}
diff --git a/src/jsMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
b/src/jsMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
index 7cf210a..dab9ecc 100644
--- a/src/jsMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
+++ b/src/jsMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
@@ -10,13 +10,17 @@ internal actual object CryptoFactory {
internal object CryptoJsImpl : CryptoImpl() {
override fun sha256(input: ByteArray): ByteArray {
- return sha256(input.toUint8Array()).toByteArray()
+ return
hash.sha256().update(input.toUint8Array()).digest().toByteArray()
}
override fun sha512(input: ByteArray): ByteArray {
return nacl.hash(input.toUint8Array()).toByteArray()
}
+ override fun getHashSha512State(): HashSha512State {
+ return JsHashSha512State()
+ }
+
override fun getRandomBytes(num: Int): ByteArray {
return nacl.randomBytes(num).toByteArray()
}
@@ -77,6 +81,19 @@ internal object CryptoJsImpl : CryptoImpl() {
TODO("Not yet implemented")
}
+ private class JsHashSha512State : HashSha512State {
+ private val state = hash.sha512()
+
+ override fun update(data: ByteArray): HashSha512State {
+ state.update(data.toUint8Array())
+ return this
+ }
+
+ override fun final(): ByteArray {
+ return state.digest().toByteArray()
+ }
+ }
+
private fun Uint8Array.toByteArray(): ByteArray {
val result = ByteArray(this.length)
for (i in 0 until this.length) result[i] = this[i]
@@ -110,11 +127,13 @@ private external class nacl {
companion object {
fun detached(msg: Uint8Array, secretKey: Uint8Array): Uint8Array
}
+
class detached {
companion object {
fun verify(msg: Uint8Array, sig: Uint8Array, publicKey:
Uint8Array): Boolean
}
}
+
class keyPair {
companion object {
fun fromSeed(seed: Uint8Array): KeyPair
@@ -134,6 +153,17 @@ private external class ed2curve {
}
}
-@JsModule("fast-sha256")
+@Suppress("ClassName")
+@JsModule("hash.js")
@JsNonModule
-private external fun sha256(message: Uint8Array): Uint8Array
+private external class hash {
+ class sha256 {
+ fun update(message: Uint8Array): sha256
+ fun digest(): Uint8Array
+ }
+
+ class sha512 {
+ fun update(message: Uint8Array): sha512
+ fun digest(): Uint8Array
+ }
+}
diff --git
a/src/linuxMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
b/src/linuxMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
index a44bc46..b0bb5b2 100644
--- a/src/linuxMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
+++ b/src/linuxMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
@@ -2,11 +2,19 @@ package net.taler.wallet.kotlin.crypto
import kotlinx.cinterop.CValuesRef
import kotlinx.cinterop.UByteVar
+import kotlinx.cinterop.alloc
+import kotlinx.cinterop.free
+import kotlinx.cinterop.nativeHeap
+import kotlinx.cinterop.ptr
import kotlinx.cinterop.refTo
import org.libsodium.crypto_hash_sha256
import org.libsodium.crypto_hash_sha256_bytes
import org.libsodium.crypto_hash_sha512
import org.libsodium.crypto_hash_sha512_bytes
+import org.libsodium.crypto_hash_sha512_final
+import org.libsodium.crypto_hash_sha512_init
+import org.libsodium.crypto_hash_sha512_state
+import org.libsodium.crypto_hash_sha512_update
import org.libsodium.crypto_scalarmult
import org.libsodium.crypto_scalarmult_BYTES
import org.libsodium.crypto_scalarmult_base
@@ -41,6 +49,10 @@ internal object CryptoNativeImpl : CryptoImpl() {
return output
}
+ override fun getHashSha512State(): HashSha512State {
+ return NativeHashSha512State()
+ }
+
override fun getRandomBytes(num: Int): ByteArray {
val bytes = ByteArray(num)
randombytes(bytes.toCValuesRef(), num.toULong())
@@ -80,12 +92,23 @@ internal object CryptoNativeImpl : CryptoImpl() {
crypto_sign_seed_keypair(publicKey.toCValuesRef(),
privateKey.toCValuesRef(), eddsaPrivateKey.toCValuesRef())
val signatureBytes = ByteArray(crypto_sign_BYTES.toInt())
- crypto_sign_detached(signatureBytes.toCValuesRef(), null,
msg.toCValuesRef(), msg.size.toULong(), privateKey.toCValuesRef())
+ crypto_sign_detached(
+ signatureBytes.toCValuesRef(),
+ null,
+ msg.toCValuesRef(),
+ msg.size.toULong(),
+ privateKey.toCValuesRef()
+ )
return signatureBytes
}
override fun eddsaVerify(msg: ByteArray, sig: ByteArray, eddsaPub:
ByteArray): Boolean {
- return crypto_sign_verify_detached(sig.toCValuesRef(),
msg.toCValuesRef(), msg.size.toULong(), eddsaPub.toCValuesRef()) == 0
+ return crypto_sign_verify_detached(
+ sig.toCValuesRef(),
+ msg.toCValuesRef(),
+ msg.size.toULong(),
+ eddsaPub.toCValuesRef()
+ ) == 0
}
override fun keyExchangeEddsaEcdhe(eddsaPrivateKey: ByteArray,
ecdhePublicKey: ByteArray): ByteArray {
@@ -117,6 +140,29 @@ internal object CryptoNativeImpl : CryptoImpl() {
TODO("Not yet implemented")
}
+ private class NativeHashSha512State : HashSha512State {
+ private val state = nativeHeap.alloc<crypto_hash_sha512_state>()
+ private val statePointer = state.ptr
+
+ init {
+ check(crypto_hash_sha512_init(statePointer) == 0) { "Error doing
crypto_hash_sha512_init" }
+ }
+
+ override fun update(data: ByteArray): HashSha512State {
+ val cInput = if (data.isEmpty()) null else data.toCValuesRef()
+ crypto_hash_sha512_update(statePointer, cInput,
data.size.toULong())
+ return this
+ }
+
+ override fun final(): ByteArray {
+ val output = ByteArray(crypto_hash_sha512_bytes().toInt())
+ crypto_hash_sha512_final(statePointer, output.toCValuesRef())
+ nativeHeap.free(statePointer)
+ return output
+ }
+
+ }
+
private fun ByteArray.toCValuesRef(): CValuesRef<UByteVar> {
@Suppress("UNCHECKED_CAST")
return this.refTo(0) as CValuesRef<UByteVar>
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.