gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-kotlin] branch master updated: Add elliptic curve crypto t


From: gnunet
Subject: [taler-wallet-kotlin] branch master updated: Add elliptic curve crypto to all platforms
Date: Wed, 03 Jun 2020 22:27:23 +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.

The following commit(s) were added to refs/heads/master by this push:
     new bb61128  Add elliptic curve crypto to all platforms
bb61128 is described below

commit bb611284c1d9f0204ad0f5ae08cb03cc0294ec7c
Author: Torsten Grote <t@grobox.de>
AuthorDate: Wed Jun 3 14:40:35 2020 -0300

    Add elliptic curve crypto to all platforms
---
 .idea/dictionaries/user.xml                        |   2 +
 .idea/jarRepositories.xml                          |   5 +
 build.gradle                                       |   7 +-
 .../taler/wallet/kotlin/crypto/CryptoFactory.kt    |  69 +++++++++++---
 .../net/taler/wallet/kotlin/crypto/Crypto.kt       |  17 +++-
 .../net/taler/wallet/kotlin/Base32CrockfordTest.kt |  10 ++
 .../wallet/kotlin/crypto/EllipticCurveTest.kt      |  96 +++++++++++++++++++
 .../net/taler/wallet/kotlin/crypto/Sha512Test.kt   |  12 ++-
 .../taler/wallet/kotlin/crypto/CryptoFactory.kt    | 104 ++++++++++++++++++---
 .../taler/wallet/kotlin/crypto/CryptoFactory.kt    |  82 +++++++++++++---
 10 files changed, 364 insertions(+), 40 deletions(-)

diff --git a/.idea/dictionaries/user.xml b/.idea/dictionaries/user.xml
index 55989af..75c46ba 100644
--- a/.idea/dictionaries/user.xml
+++ b/.idea/dictionaries/user.xml
@@ -1,6 +1,8 @@
 <component name="ProjectDictionaryState">
   <dictionary name="user">
     <words>
+      <w>ecdhe</w>
+      <w>eddsa</w>
       <w>nacl</w>
     </words>
   </dictionary>
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index fdc392f..b3e9cbd 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -16,5 +16,10 @@
       <option name="name" value="MavenRepo" />
       <option name="url" value="https://repo.maven.apache.org/maven2/"; />
     </remote-repository>
+    <remote-repository>
+      <option name="id" value="BintrayJCenter" />
+      <option name="name" value="BintrayJCenter" />
+      <option name="url" value="https://jcenter.bintray.com/"; />
+    </remote-repository>
   </component>
 </project>
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 7e06be1..b87f250 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,6 +3,7 @@ plugins {
 }
 repositories {
     mavenCentral()
+    jcenter()
 }
 group 'net.taler'
 version '0.0.1'
@@ -44,7 +45,10 @@ kotlin {
         androidMain {
             dependencies {
                 implementation kotlin('stdlib-jdk8')
-                implementation 'org.bouncycastle:bcprov-jdk15on:1.65.01'
+                // TODO Android
+//                implementation 
"com.goterl.lazycode:lazysodium-android:4.1.1@aar"
+                implementation "com.goterl.lazycode:lazysodium-java:4.2.6"
+                implementation 'net.java.dev.jna:jna:5.5.0@aar'
             }
         }
         androidTest {
@@ -57,6 +61,7 @@ kotlin {
             dependencies {
                 implementation kotlin('stdlib-js')
                 implementation npm('tweetnacl', '1.0.3')
+                implementation npm('ed2curve', '0.3.0')
             }
         }
         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 509fabb..0bc933a 100644
--- a/src/androidMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
+++ b/src/androidMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
@@ -1,22 +1,69 @@
 package net.taler.wallet.kotlin.crypto
 
-import org.bouncycastle.jce.provider.BouncyCastleProvider
-import java.security.MessageDigest
-import java.security.Security
+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.KeyExchange
+import com.goterl.lazycode.lazysodium.interfaces.Sign
+import com.goterl.lazycode.lazysodium.utils.Key
 
-actual object CryptoFactory {
-    actual fun getCrypto(): Crypto = CryptoJvmImpl
+internal actual object CryptoFactory {
+    internal actual fun getCrypto(): Crypto = CryptoJvmImpl
 }
 
-object CryptoJvmImpl : Crypto {
+internal object CryptoJvmImpl : Crypto {
 
-    init {
-        Security.addProvider(BouncyCastleProvider())
-    }
+    private val sodium = LazySodiumJava(SodiumJava())
 
     override fun sha512(input: ByteArray): ByteArray {
-        val digest = MessageDigest.getInstance("SHA-512", "BC")
-        return digest.digest(input)
+        val output = ByteArray(Hash.SHA512_BYTES)
+        sodium.cryptoHashSha512(output, input, input.size.toLong())
+        return output
+    }
+
+    override fun eddsaGetPublic(eddsaPrivateKey: ByteArray): ByteArray {
+        return sodium.cryptoSignSeedKeypair(eddsaPrivateKey).publicKey.asBytes
+    }
+
+    override fun ecdheGetPublic(ecdhePrivateKey: ByteArray): ByteArray {
+        return 
sodium.cryptoScalarMultBase(Key.fromBytes(ecdhePrivateKey)).asBytes
+    }
+
+    override fun createEddsaKeyPair(): EddsaKeyPair {
+        val privateKey = sodium.randomBytesBuf(KeyExchange.SEEDBYTES)
+        val publicKey = eddsaGetPublic(privateKey)
+        return EddsaKeyPair(privateKey, publicKey)
+    }
+
+    override fun createEcdheKeyPair(): EcdheKeyPair {
+        val privateKey = sodium.randomBytesBuf(KeyExchange.SEEDBYTES)
+        val publicKey = ecdheGetPublic(privateKey)
+        return EcdheKeyPair(privateKey, publicKey)
+    }
+
+    override fun eddsaSign(msg: ByteArray, eddsaPrivateKey: ByteArray): 
ByteArray {
+        val privateKey = 
sodium.cryptoSignSeedKeypair(eddsaPrivateKey).secretKey.asBytes
+        val signatureBytes = ByteArray(Sign.BYTES)
+        sodium.cryptoSignDetached(signatureBytes, msg, msg.size.toLong(), 
privateKey)
+        return signatureBytes
+    }
+
+    override fun eddsaVerify(msg: ByteArray, sig: ByteArray, eddsaPub: 
ByteArray): Boolean {
+        return sodium.cryptoSignVerifyDetached(sig, msg, msg.size, eddsaPub)
+    }
+
+    override fun keyExchangeEddsaEcdhe(eddsaPrivateKey: ByteArray, 
ecdhePublicKey: ByteArray): ByteArray {
+        val ph = sha512(eddsaPrivateKey)
+        val a = ph.copyOfRange(0, 32)
+        val x = sodium.cryptoScalarMult(Key.fromBytes(a), 
Key.fromBytes(ecdhePublicKey)).asBytes
+        return sha512(x)
+    }
+
+    override fun keyExchangeEcdheEddsa(ecdhePrivateKey: ByteArray, 
eddsaPublicKey: ByteArray): ByteArray {
+        val curve25519Pub = ByteArray(KeyExchange.PUBLICKEYBYTES)
+        sodium.convertPublicKeyEd25519ToCurve25519(curve25519Pub, 
eddsaPublicKey)
+        val x = sodium.cryptoScalarMult(Key.fromBytes(ecdhePrivateKey), 
Key.fromBytes(curve25519Pub)).asBytes
+        return sha512(x)
     }
 
 }
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 a5eeb69..3735c31 100644
--- a/src/commonMain/kotlin/net/taler/wallet/kotlin/crypto/Crypto.kt
+++ b/src/commonMain/kotlin/net/taler/wallet/kotlin/crypto/Crypto.kt
@@ -1,11 +1,22 @@
 package net.taler.wallet.kotlin.crypto
 
-interface Crypto {
+internal interface Crypto {
     fun sha512(input: ByteArray): ByteArray
+    fun eddsaGetPublic(eddsaPrivateKey: ByteArray): ByteArray
+    fun ecdheGetPublic(ecdhePrivateKey: ByteArray): ByteArray
+    fun createEddsaKeyPair(): EddsaKeyPair
+    fun createEcdheKeyPair(): EcdheKeyPair
+    fun eddsaSign(msg: ByteArray, eddsaPrivateKey: ByteArray): ByteArray
+    fun eddsaVerify(msg: ByteArray, sig: ByteArray, eddsaPub: ByteArray): 
Boolean
+    fun keyExchangeEddsaEcdhe(eddsaPrivateKey: ByteArray, ecdhePublicKey: 
ByteArray): ByteArray
+    fun keyExchangeEcdheEddsa(ecdhePrivateKey: ByteArray, eddsaPublicKey: 
ByteArray): ByteArray
 }
 
-expect object CryptoFactory {
-    fun getCrypto(): Crypto
+class EddsaKeyPair(val privateKey: ByteArray, val publicKey: ByteArray)
+class EcdheKeyPair(val privateKey: ByteArray, val publicKey: ByteArray)
+
+internal expect object CryptoFactory {
+    internal fun getCrypto(): Crypto
 }
 
 private val hexArray = arrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', 
'9', 'a', 'b', 'c', 'd', 'e', 'f')
diff --git 
a/src/commonTest/kotlin/net/taler/wallet/kotlin/Base32CrockfordTest.kt 
b/src/commonTest/kotlin/net/taler/wallet/kotlin/Base32CrockfordTest.kt
index daa505a..4a52a47 100644
--- a/src/commonTest/kotlin/net/taler/wallet/kotlin/Base32CrockfordTest.kt
+++ b/src/commonTest/kotlin/net/taler/wallet/kotlin/Base32CrockfordTest.kt
@@ -5,6 +5,7 @@ import kotlin.test.Test
 import kotlin.test.assertEquals
 import kotlin.test.assertTrue
 
+@ExperimentalStdlibApi
 class Base32CrockfordTest {
 
     private class TestVector(val value: ByteArray, val encoding: List<String>)
@@ -94,4 +95,13 @@ class Base32CrockfordTest {
         assertTrue(bytes contentEquals Base32Crockford.decode("FVCK"))
     }
 
+    @Test
+    fun testEncodingDecoding() {
+        val input = "Hello, World"
+        val encoded = Base32Crockford.encode(input.encodeToByteArray())
+        val decoded = Base32Crockford.decode(encoded)
+        val output = decoded.decodeToString()
+        assertEquals(input, output)
+    }
+
 }
diff --git 
a/src/commonTest/kotlin/net/taler/wallet/kotlin/crypto/EllipticCurveTest.kt 
b/src/commonTest/kotlin/net/taler/wallet/kotlin/crypto/EllipticCurveTest.kt
new file mode 100644
index 0000000..c74d9ff
--- /dev/null
+++ b/src/commonTest/kotlin/net/taler/wallet/kotlin/crypto/EllipticCurveTest.kt
@@ -0,0 +1,96 @@
+package net.taler.wallet.kotlin.crypto
+
+import net.taler.wallet.kotlin.Base32Crockford
+import kotlin.random.Random
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+
+class EllipticCurveTest {
+
+    private val crypto = CryptoFactory.getCrypto()
+
+    @Test
+    fun testExchangeTvgEddsaKey() {
+        val pri = "9TM70AKDTS57AWY9JK2J4TMBTMW6K62WHHGZWYDG0VM5ABPZKD40"
+        val pub = "8GSJZ649T2PXMKZC01Y4ANNBE7MF14QVK9SQEC4E46ZHKCVG8AS0"
+        val pubBytes = crypto.eddsaGetPublic(Base32Crockford.decode(pri))
+        assertEquals(pub, Base32Crockford.encode(pubBytes))
+    }
+
+    @Test
+    fun testExchangeTvgEcdheKey() {
+        val pri = "X4T4N0M8PVQXQEBW2BA7049KFSM7J437NSDFC6GDNM3N5J9367A0"
+        val pub = "M997P494MS6A95G1P0QYWW2VNPSHSX5Q6JBY5B9YMNYWP0B50X3G"
+        val pubBytes = crypto.ecdheGetPublic(Base32Crockford.decode(pri))
+        assertEquals(pub, Base32Crockford.encode(pubBytes))
+    }
+
+    @Test
+    fun testCreateEddsaKeyPair() {
+        val pair1 = crypto.createEddsaKeyPair()
+        val pair2 = crypto.createEddsaKeyPair()
+        assertFalse(pair1.privateKey contentEquals pair2.privateKey)
+        assertFalse(pair1.publicKey contentEquals pair2.publicKey)
+    }
+
+    @Test
+    fun testCreateEcdheKeyPair() {
+        val pair1 = crypto.createEcdheKeyPair()
+        val pair2 = crypto.createEcdheKeyPair()
+        assertFalse(pair1.privateKey contentEquals pair2.privateKey)
+        assertFalse(pair1.publicKey contentEquals pair2.publicKey)
+    }
+
+    @Test
+    @ExperimentalStdlibApi
+    fun testEddsaSignAndVerify() {
+        val msg = "Hallo world!".encodeToByteArray()
+        val pri = "9TM70AKDTS57AWY9JK2J4TMBTMW6K62WHHGZWYDG0VM5ABPZKD40"
+        val expectedSig =
+            
"Z6H76JXPJFP3JBGSF54XBF0BVXDJ0CJBK4YT9GVR1AT916ZD57KP53YZN5G67A4YN95WGMZKQW7744483P5JDF06B6S7TMK195QGP20"
+        val sig = crypto.eddsaSign(msg, Base32Crockford.decode(pri))
+        assertEquals(expectedSig, Base32Crockford.encode(sig))
+
+        val pub = crypto.eddsaGetPublic(Base32Crockford.decode(pri))
+        assertTrue(crypto.eddsaVerify(msg, sig, pub))
+
+        val wrongSig = Random.nextBytes(64)
+        assertFalse(crypto.eddsaVerify(msg, wrongSig, pub))
+
+        val wrongPub = Random.nextBytes(32)
+        assertFalse(crypto.eddsaVerify(msg, sig, wrongPub))
+
+        val wrongMsg = Random.nextBytes(16)
+        assertFalse(crypto.eddsaVerify(wrongMsg, sig, pub))
+    }
+
+    @Test
+    fun testExchangeTvgEddsaEcdh() {
+        val ecdhePrivateKey = 
"4AFZWMSGTVCHZPQ0R81NWXDCK4N58G7SDBBE5KXE080Y50370JJG"
+        val ecdhePublicKey = 
"FXFN5GPAFTKVPWJDPVXQ87167S8T82T5ZV8CDYC0NH2AE14X0M30"
+        val ecdhePublicKeyBytes = 
crypto.ecdheGetPublic(Base32Crockford.decode(ecdhePrivateKey))
+        assertEquals(ecdhePublicKey, 
Base32Crockford.encode(ecdhePublicKeyBytes))
+
+        val eddsaPrivateKey = 
"1KG54M8T3X8BSFSZXCR3SQBSR7Y9P53NX61M864S7TEVMJ2XVPF0"
+        val eddsaPublicKey = 
"7BXWKG6N224C57RTDV8XEAHR108HG78NMA995BE8QAT5GC1S7E80"
+        val eddsaPublicKeyBytes = 
crypto.eddsaGetPublic(Base32Crockford.decode(eddsaPrivateKey))
+        assertEquals(eddsaPublicKey, 
Base32Crockford.encode(eddsaPublicKeyBytes))
+
+        val keyMaterial =
+            
"PKZ42Z56SVK2796HG1QYBRJ6ZQM2T9QGA3JA4AAZ8G7CWK9FPX175Q9JE5P0ZAX3HWWPHAQV4DPCK10R9X3SAXHRV0WF06BHEC2ZTKR"
+        val keyMaterial1Bytes = crypto.keyExchangeEddsaEcdhe(
+            Base32Crockford.decode(eddsaPrivateKey),
+            Base32Crockford.decode(ecdhePublicKey)
+        )
+        assertEquals(keyMaterial, Base32Crockford.encode(keyMaterial1Bytes))
+
+        val keyMaterial2Bytes = crypto.keyExchangeEcdheEddsa(
+            Base32Crockford.decode(ecdhePrivateKey),
+            Base32Crockford.decode(eddsaPublicKey)
+        )
+        assertEquals(keyMaterial, Base32Crockford.encode(keyMaterial2Bytes))
+    }
+
+}
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 f41080f..c401b73 100644
--- a/src/commonTest/kotlin/net/taler/wallet/kotlin/crypto/Sha512Test.kt
+++ b/src/commonTest/kotlin/net/taler/wallet/kotlin/crypto/Sha512Test.kt
@@ -1,5 +1,6 @@
 package net.taler.wallet.kotlin.crypto
 
+import net.taler.wallet.kotlin.Base32Crockford
 import kotlin.test.Test
 import kotlin.test.assertEquals
 
@@ -36,7 +37,8 @@ class Sha512Test {
     fun testAbc896bits() {
         assertEquals(
             
"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909",
-            
crypto.sha512("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".encodeToByteArray()).toHexString()
+            
crypto.sha512("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".encodeToByteArray())
+                .toHexString()
         )
     }
 
@@ -49,4 +51,12 @@ class Sha512Test {
         )
     }
 
+    @Test
+    fun testExchangeTvgHashCode() {
+        val input = "91JPRV3F5GG4EKJN41A62V35E8"
+        val output =
+            
"CW96WR74JS8T53EC8GKSGD49QKH4ZNFTZXDAWMMV5GJ1E4BM6B8GPN5NVHDJ8ZVXNCW7Q4WBYCV61HCA3PZC2YJD850DT29RHHN7ESR"
+        assertEquals(output, 
Base32Crockford.encode(crypto.sha512(Base32Crockford.decode(input))))
+    }
+
 }
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 e1786d9..e36b833 100644
--- a/src/jsMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
+++ b/src/jsMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
@@ -3,35 +3,113 @@ package net.taler.wallet.kotlin.crypto
 import org.khronos.webgl.Uint8Array
 import org.khronos.webgl.get
 
-actual object CryptoFactory {
-    actual fun getCrypto(): Crypto = CryptoJsImpl
+internal actual object CryptoFactory {
+    internal actual fun getCrypto(): Crypto = CryptoJsImpl
 }
 
-object CryptoJsImpl : Crypto {
+internal object CryptoJsImpl : Crypto {
 
     override fun sha512(input: ByteArray): ByteArray {
         return nacl.hash(input.toUint8Array()).toByteArray()
     }
 
-}
+    override fun eddsaGetPublic(eddsaPrivateKey: ByteArray): ByteArray {
+        val pair = nacl.sign.keyPair.fromSeed(eddsaPrivateKey.toUint8Array())
+        return pair.publicKey.toByteArray()
+    }
 
-private fun Uint8Array.toByteArray(): ByteArray {
-    val result = ByteArray(this.length)
-    for (i in 0 until this.length) {
-        result[i] = this[i]
+    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)
+    }
+
+    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())
     }
-    return result
-}
 
-private fun ByteArray.toUint8Array():Uint8Array {
-    return Uint8Array(this.toTypedArray())
 }
 
 @Suppress("ClassName")
 @JsModule("tweetnacl")
 @JsNonModule
-external class nacl {
+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?
     }
 }
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 d1ec46a..f5eca15 100644
--- a/src/linuxMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
+++ b/src/linuxMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoFactory.kt
@@ -1,26 +1,86 @@
 package net.taler.wallet.kotlin.crypto
 
+import kotlinx.cinterop.CValuesRef
+import kotlinx.cinterop.UByteVar
+import kotlinx.cinterop.refTo
 import org.libsodium.*
-import kotlinx.cinterop.*
 
-actual object CryptoFactory {
+internal actual object CryptoFactory {
     @ExperimentalUnsignedTypes
-    actual fun getCrypto(): Crypto = CryptoNativeImpl
+    internal actual fun getCrypto(): Crypto = CryptoNativeImpl
 }
 
 @ExperimentalUnsignedTypes
-object CryptoNativeImpl : Crypto {
+internal object CryptoNativeImpl : Crypto {
 
     override fun sha512(input: ByteArray): ByteArray {
         val output = ByteArray(crypto_hash_sha512_bytes().toInt())
-        val cInput = if (input.isEmpty()) null else 
input.toUByteArray().refTo(0)
-        val cInputSize = input.size.toULong()
-        output.usePinned { pinned ->
-            @Suppress("UNCHECKED_CAST")
-            val cOutput = pinned.addressOf(0) as CValuesRef<UByteVar>
-            crypto_hash_sha512(cOutput, cInput, cInputSize)
-        }
+        val cInput = if (input.isEmpty()) null else input.toCValuesRef()
+        crypto_hash_sha512(output.toCValuesRef(), cInput, input.size.toULong())
         return output
     }
 
+    override fun eddsaGetPublic(eddsaPrivateKey: ByteArray): ByteArray {
+        val publicKey = ByteArray(crypto_sign_PUBLICKEYBYTES.toInt())
+        val privateKey = ByteArray(crypto_sign_SECRETKEYBYTES.toInt())
+        crypto_sign_seed_keypair(publicKey.toCValuesRef(), 
privateKey.toCValuesRef(), eddsaPrivateKey.toCValuesRef())
+        return publicKey
+    }
+
+    override fun ecdheGetPublic(ecdhePrivateKey: ByteArray): ByteArray {
+        val publicKey = ByteArray(crypto_scalarmult_BYTES.toInt())
+        crypto_scalarmult_base(publicKey.toCValuesRef(), 
ecdhePrivateKey.toCValuesRef())
+        return publicKey
+    }
+
+    override fun createEddsaKeyPair(): EddsaKeyPair {
+        val privateKey = ByteArray(crypto_sign_SECRETKEYBYTES.toInt())
+        randombytes(privateKey.toCValuesRef(), 
crypto_sign_SECRETKEYBYTES.toULong())
+        val publicKey = eddsaGetPublic(privateKey)
+        return EddsaKeyPair(privateKey, publicKey)
+    }
+
+    override fun createEcdheKeyPair(): EcdheKeyPair {
+        val privateKey = ByteArray(crypto_scalarmult_BYTES.toInt())
+        randombytes(privateKey.toCValuesRef(), 
crypto_scalarmult_BYTES.toULong())
+        val publicKey = ecdheGetPublic(privateKey)
+        return EcdheKeyPair(privateKey, publicKey)
+    }
+
+    override fun eddsaSign(msg: ByteArray, eddsaPrivateKey: ByteArray): 
ByteArray {
+        val publicKey = ByteArray(crypto_sign_PUBLICKEYBYTES.toInt())
+        val privateKey = ByteArray(crypto_sign_SECRETKEYBYTES.toInt())
+        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())
+        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
+    }
+
+    override fun keyExchangeEddsaEcdhe(eddsaPrivateKey: ByteArray, 
ecdhePublicKey: ByteArray): ByteArray {
+        val privateKey = sha512(eddsaPrivateKey).copyOfRange(0, 32)
+        val sharedKey = ByteArray(crypto_scalarmult_BYTES.toInt())
+        crypto_scalarmult(sharedKey.toCValuesRef(), privateKey.toCValuesRef(), 
ecdhePublicKey.toCValuesRef())
+        return sha512(sharedKey)
+    }
+
+    override fun keyExchangeEcdheEddsa(ecdhePrivateKey: ByteArray, 
eddsaPublicKey: ByteArray): ByteArray {
+        val curve25519Pub = 
ByteArray(crypto_scalarmult_curve25519_BYTES.toInt())
+        val cCurve25519Pub = curve25519Pub.toCValuesRef()
+        crypto_sign_ed25519_pk_to_curve25519(cCurve25519Pub, 
eddsaPublicKey.toCValuesRef())
+
+        val sharedKey = ByteArray(crypto_scalarmult_BYTES.toInt())
+        crypto_scalarmult(sharedKey.toCValuesRef(), 
ecdhePrivateKey.toCValuesRef(), cCurve25519Pub)
+        return sha512(sharedKey)
+    }
+
+    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.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]