diff options
Diffstat (limited to 'wallet/src/jsMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt')
-rw-r--r-- | wallet/src/jsMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/wallet/src/jsMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt b/wallet/src/jsMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt new file mode 100644 index 0000000..e428f6a --- /dev/null +++ b/wallet/src/jsMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt @@ -0,0 +1,185 @@ +/* + * This file is part of GNU Taler + * (C) 2020 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +package net.taler.wallet.kotlin.crypto + +import org.khronos.webgl.Uint8Array +import org.khronos.webgl.get + +internal actual object CryptoFactory { + internal actual fun getCrypto(): Crypto = CryptoJsImpl +} + +internal object CryptoJsImpl : CryptoImpl() { + + override fun sha256(input: ByteArray): ByteArray { + 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() + } + + override fun eddsaGetPublic(eddsaPrivateKey: ByteArray): ByteArray { + val pair = nacl.sign.keyPair.fromSeed(eddsaPrivateKey.toUint8Array()) + return pair.publicKey.toByteArray() + } + + override fun ecdheGetPublic(ecdhePrivateKey: ByteArray): ByteArray { + return nacl.scalarMult.base(ecdhePrivateKey.toUint8Array()).toByteArray() + } + + override fun createEddsaKeyPair(): EddsaKeyPair { + val privateKey = nacl.randomBytes(32).toByteArray() + val publicKey = eddsaGetPublic(privateKey) + return EddsaKeyPair(privateKey, publicKey) + } + + override fun createEcdheKeyPair(): EcdheKeyPair { + val privateKey = nacl.randomBytes(32).toByteArray() + val publicKey = ecdheGetPublic(privateKey) + return EcdheKeyPair(privateKey, publicKey) + } + + override fun eddsaSign(msg: ByteArray, eddsaPrivateKey: ByteArray): ByteArray { + val privateKey = nacl.sign.keyPair.fromSeed(eddsaPrivateKey.toUint8Array()).secretKey + return nacl.sign.detached(msg.toUint8Array(), privateKey).toByteArray() + } + + override fun eddsaVerify(msg: ByteArray, sig: ByteArray, eddsaPub: ByteArray): Boolean { + return nacl.sign.detached.verify(msg.toUint8Array(), sig.toUint8Array(), eddsaPub.toUint8Array()) + } + + override fun keyExchangeEddsaEcdhe(eddsaPrivateKey: ByteArray, ecdhePublicKey: ByteArray): ByteArray { + val ph = sha512(eddsaPrivateKey) + val a = ph.copyOfRange(0, 32) + val x = nacl.scalarMult(a.toUint8Array(), ecdhePublicKey.toUint8Array()).toByteArray() + return sha512(x) + } + + override fun keyExchangeEcdheEddsa(ecdhePrivateKey: ByteArray, eddsaPublicKey: ByteArray): ByteArray { + val curve25519Pub = + ed2curve.convertPublicKey(eddsaPublicKey.toUint8Array()) ?: throw Error("invalid public key") + val x = nacl.scalarMult(ecdhePrivateKey.toUint8Array(), curve25519Pub).toByteArray() + return sha512(x) + } + + override fun rsaBlind(hm: ByteArray, bks: ByteArray, rsaPubEnc: ByteArray): ByteArray { + TODO("Not yet implemented") + } + + override fun rsaUnblind(sig: ByteArray, rsaPubEnc: ByteArray, bks: ByteArray): ByteArray { + TODO("Not yet implemented") + } + + override fun rsaVerify(hm: ByteArray, rsaSig: ByteArray, rsaPubEnc: ByteArray): Boolean { + 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] + return result + } + + private fun ByteArray.toUint8Array(): Uint8Array { + return Uint8Array(this.toTypedArray()) + } + +} + +@Suppress("ClassName") +@JsModule("tweetnacl") +@JsNonModule +private external class nacl { + + companion object { + fun hash(input: Uint8Array): Uint8Array + fun scalarMult(n: Uint8Array, p: Uint8Array): Uint8Array + fun randomBytes(n: Int): Uint8Array + } + + class scalarMult { + companion object { + fun base(n: Uint8Array): Uint8Array + } + } + + class sign { + 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 + } + } + } +} + +private class KeyPair(val publicKey: Uint8Array, @Suppress("unused") val secretKey: Uint8Array) + +@Suppress("ClassName") +@JsModule("ed2curve") +@JsNonModule +private external class ed2curve { + companion object { + fun convertPublicKey(pk: Uint8Array): Uint8Array? + } +} + +@Suppress("ClassName") +@JsModule("hash.js") +@JsNonModule +private external class hash { + class sha256 { + fun update(message: Uint8Array): sha256 + fun digest(): Uint8Array + } + + class sha512 { + fun update(message: Uint8Array): sha512 + fun digest(): Uint8Array + } +} |