diff options
author | Torsten Grote <t@grobox.de> | 2020-08-17 09:29:54 -0300 |
---|---|---|
committer | Torsten Grote <t@grobox.de> | 2020-08-17 09:29:54 -0300 |
commit | dade0470c7e378c72ac2f2fd2a623416dadbff10 (patch) | |
tree | 083449814b1ad1320677e115f42f9a76125ccd76 /wallet/src/androidMain/kotlin/net/taler/lib/wallet/crypto/RsaBlinding.kt | |
parent | a307a498dc8a42df129e8eaff591e9144ed96298 (diff) | |
download | wallet-kotlin-dade0470c7e378c72ac2f2fd2a623416dadbff10.tar.gz wallet-kotlin-dade0470c7e378c72ac2f2fd2a623416dadbff10.tar.bz2 wallet-kotlin-dade0470c7e378c72ac2f2fd2a623416dadbff10.zip |
Provide a blocking API for iOS (until Kotlin 1.4 is out)
and put base crypto into dedicated package (to be split out later).
Diffstat (limited to 'wallet/src/androidMain/kotlin/net/taler/lib/wallet/crypto/RsaBlinding.kt')
-rw-r--r-- | wallet/src/androidMain/kotlin/net/taler/lib/wallet/crypto/RsaBlinding.kt | 136 |
1 files changed, 0 insertions, 136 deletions
diff --git a/wallet/src/androidMain/kotlin/net/taler/lib/wallet/crypto/RsaBlinding.kt b/wallet/src/androidMain/kotlin/net/taler/lib/wallet/crypto/RsaBlinding.kt deleted file mode 100644 index 70c7c78..0000000 --- a/wallet/src/androidMain/kotlin/net/taler/lib/wallet/crypto/RsaBlinding.kt +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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.lib.wallet.crypto - -import java.math.BigInteger -import kotlin.math.abs -import kotlin.math.ceil -import kotlin.math.floor - -internal object RsaBlinding { - - fun rsaBlind(hm: ByteArray, bks: ByteArray, rsaPubEnc: ByteArray): ByteArray { - val rsaPub = rsaPubDecode(rsaPubEnc) - val data = rsaFullDomainHash(hm, rsaPub) - val r = rsaBlindingKeyDerive(rsaPub, bks) - val rE = r.modPow(rsaPub.e, rsaPub.n) - val bm = rE.multiply(data).mod(rsaPub.n) - return bm.toByteArrayWithoutSign() - } - - fun rsaUnblind(sig: ByteArray, rsaPubEnc: ByteArray, bks: ByteArray): ByteArray { - val rsaPub = rsaPubDecode(rsaPubEnc) - val blindedSig = BigInteger(1, sig) - val r = rsaBlindingKeyDerive(rsaPub, bks) - val rInv = r.modInverse(rsaPub.n) - val s = blindedSig.multiply(rInv).mod(rsaPub.n) - return s.toByteArrayWithoutSign() - } - - fun rsaVerify(hm: ByteArray, rsaSig: ByteArray, rsaPubEnc: ByteArray): Boolean { - val rsaPub = rsaPubDecode(rsaPubEnc) - val d = rsaFullDomainHash(hm, rsaPub) - val sig = BigInteger(1, rsaSig) - val sigE = sig.modPow(rsaPub.e, rsaPub.n) - return sigE == d - } - - private fun rsaBlindingKeyDerive(rsaPub: RsaPublicKey, bks: ByteArray): BigInteger { - val salt = "Blinding KDF extrator HMAC key".encodeToByteArray() - val info = "Blinding KDF".encodeToByteArray() - return kdfMod(rsaPub.n, bks, salt, info) - } - - private fun rsaPubDecode(publicKey: ByteArray): RsaPublicKey { - val modulusLength = abs((publicKey[0].toInt() shl 8) or publicKey[1].toInt()) - val exponentLength = abs((publicKey[2].toInt() shl 8) or publicKey[3].toInt()) - if (4 + exponentLength + modulusLength != publicKey.size) { - throw Error("invalid RSA public key (format wrong)") - } - val modulus = publicKey.copyOfRange(4, 4 + modulusLength) - val exponent = publicKey.copyOfRange( - 4 + modulusLength, - 4 + modulusLength + exponentLength - ) - return RsaPublicKey(BigInteger(1, modulus), BigInteger(1, exponent)) - } - - private fun rsaFullDomainHash(hm: ByteArray, rsaPublicKey: RsaPublicKey): BigInteger { - val info = "RSA-FDA FTpsW!".encodeToByteArray() - val salt = rsaPubEncode(rsaPublicKey) - val r = kdfMod(rsaPublicKey.n, hm, salt, info) - rsaGcdValidate(r, rsaPublicKey.n) - return r - } - - private fun rsaPubEncode(rsaPublicKey: RsaPublicKey): ByteArray { - val mb = rsaPublicKey.n.toByteArrayWithoutSign() - val eb = rsaPublicKey.e.toByteArrayWithoutSign() - val out = ByteArray(4 + mb.size + eb.size) - out[0] = ((mb.size ushr 8) and 0xff).toByte() - out[1] = (mb.size and 0xff).toByte() - out[2] = ((eb.size ushr 8) and 0xff).toByte() - out[3] = (eb.size and 0xff).toByte() - mb.copyInto(out, destinationOffset = 4) - eb.copyInto(out, destinationOffset = 4 + mb.size) - return out - } - - private fun kdfMod(n: BigInteger, ikm: ByteArray, salt: ByteArray, info: ByteArray): BigInteger { - val nBits = n.bitLength() - val bufLen = floor((nBits.toDouble() - 1) / 8 + 1).toInt() - val mask = (1 shl (8 - (bufLen * 8 - nBits))) - 1 - var counter = 0 - while (true) { - val ctx = ByteArray(info.size + 2) - info.copyInto(ctx) - ctx[ctx.size - 2] = ((counter ushr 8) and 0xff).toByte() - ctx[ctx.size - 1] = (counter and 0xff).toByte() - val buf = CryptoJvmImpl.kdf(bufLen, ikm, salt, ctx) - val arr = buf.copyOf() - arr[0] = (arr[0].toInt() and mask).toByte() - val r = BigInteger(1, arr) - if (r < n) return r - counter++ - } - } - - /** - * Test for malicious RSA key. - * - * Assuming n is an RSA modulous and r is generated using a call to - * GNUNET_CRYPTO_kdf_mod_mpi, if gcd(r,n) != 1 then n must be a - * malicious RSA key designed to deanomize the user. - * - * @param r KDF result - * @param n RSA modulus of the public key - */ - private fun rsaGcdValidate(r: BigInteger, n: BigInteger) { - if (r.gcd(n) != BigInteger.ONE) throw Error("malicious RSA public key") - } - - // TODO check that this strips *only* the sign correctly - private fun BigInteger.toByteArrayWithoutSign(): ByteArray = this.toByteArray().let { - val byteLength = ceil(this.bitLength().toDouble() / 8).toInt() - val signBitPosition = ceil((this.bitLength() + 1).toDouble() / 8).toInt() - val start = signBitPosition - byteLength - it.copyOfRange(start, it.size) // stripping least significant byte (sign) - } - -} - -internal class RsaPublicKey(val n: BigInteger, val e: BigInteger) |