/* * 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 */ 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 internal actual object CryptoFactory { internal actual fun getCrypto(): Crypto = CryptoJvmImpl } internal object CryptoJvmImpl : CryptoImpl() { private val sodium = LazySodiumJava(SodiumJava()) override fun sha256(input: ByteArray): ByteArray { val output = ByteArray(Hash.SHA256_BYTES) sodium.cryptoHashSha256(output, input, input.size.toLong()) return output } override fun sha512(input: ByteArray): ByteArray { val output = ByteArray(Hash.SHA512_BYTES) sodium.cryptoHashSha512(output, input, input.size.toLong()) return output } override fun getHashSha512State(): HashSha512State { return JvmHashSha512State() } override fun getRandomBytes(num: Int): ByteArray { return sodium.randomBytesBuf(num) } 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) } override fun rsaBlind(hm: ByteArray, bks: ByteArray, rsaPubEnc: ByteArray): ByteArray { return RsaBlinding.rsaBlind(hm, bks, rsaPubEnc) } override fun rsaUnblind(sig: ByteArray, rsaPubEnc: ByteArray, bks: ByteArray): ByteArray { return RsaBlinding.rsaUnblind(sig, rsaPubEnc, bks) } override fun rsaVerify(hm: ByteArray, rsaSig: ByteArray, rsaPubEnc: ByteArray): Boolean { 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 } } }