summaryrefslogtreecommitdiff
path: root/wallet/src/jsMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
diff options
context:
space:
mode:
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.kt185
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
+ }
+}