summaryrefslogtreecommitdiff
path: root/wallet/src/androidMain/kotlin/net/taler/lib/wallet/crypto/RsaBlinding.kt
diff options
context:
space:
mode:
authorTorsten Grote <t@grobox.de>2020-08-17 09:29:54 -0300
committerTorsten Grote <t@grobox.de>2020-08-17 09:29:54 -0300
commitdade0470c7e378c72ac2f2fd2a623416dadbff10 (patch)
tree083449814b1ad1320677e115f42f9a76125ccd76 /wallet/src/androidMain/kotlin/net/taler/lib/wallet/crypto/RsaBlinding.kt
parenta307a498dc8a42df129e8eaff591e9144ed96298 (diff)
downloadwallet-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.kt136
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)