From 87990026eadf2795bc18f358a66ac7bd83351cb1 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 24 Jul 2023 11:34:16 -0400 Subject: [PATCH] Refactoring dependency path to center in CryptoUtils --- .../amethyst/service/Bech32Util.kt | 2 +- .../amethyst/service/CryptoUtils.kt | 21 +++++++++++++++---- .../amethyst/service/FileHeader.kt | 5 +---- .../amethyst/service/model/Event.kt | 9 ++++---- .../service/model/HTTPAuthorizationEvent.kt | 5 +---- .../service/model/LnZapRequestEvent.kt | 3 +-- .../amethyst/ui/components/Robohash.kt | 4 ++-- .../ui/components/ZoomableContentView.kt | 8 ++----- 8 files changed, 29 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/Bech32Util.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/Bech32Util.kt index 764b1a3f6..efcbe061d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/Bech32Util.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/Bech32Util.kt @@ -22,7 +22,7 @@ import kotlin.jvm.JvmStatic * Bech32 works with 5 bits values, we use this type to make it explicit: whenever you see Int5 it means 5 bits values, * and whenever you see Byte it means 8 bits values. */ -public typealias Int5 = Byte +private typealias Int5 = Byte /** * Bech32 and Bech32m address formats. diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/CryptoUtils.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/CryptoUtils.kt index 0c622bc68..791fc65f0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/CryptoUtils.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/CryptoUtils.kt @@ -2,6 +2,7 @@ package com.vitorpamplona.amethyst.service import fr.acinq.secp256k1.Hex import fr.acinq.secp256k1.Secp256k1 +import java.security.MessageDigest import java.security.SecureRandom import java.util.Base64 import javax.crypto.Cipher @@ -9,6 +10,9 @@ import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.SecretKeySpec object CryptoUtils { + private val secp256k1 = Secp256k1.get() + private val random = SecureRandom() + /** * Provides a 32B "private key" aka random number */ @@ -54,15 +58,24 @@ object CryptoUtils { return String(cipher.doFinal(encryptedMsg)) } + fun verifySignature( + signature: ByteArray, + hash: ByteArray, + pubKey: ByteArray + ): Boolean { + return secp256k1.verifySchnorr(signature, hash, pubKey) + } + + fun sha256(data: ByteArray): ByteArray { + // Creates a new buffer every time + return MessageDigest.getInstance("SHA-256").digest(data) + } + /** * @return 32B shared secret */ fun getSharedSecret(privateKey: ByteArray, pubKey: ByteArray): ByteArray = secp256k1.pubKeyTweakMul(Hex.decode("02") + pubKey, privateKey).copyOfRange(1, 33) - - private val secp256k1 = Secp256k1.get() - - private val random = SecureRandom() } fun Int.toByteArray(): ByteArray { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/FileHeader.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/FileHeader.kt index b0c2d4c14..4b4ca0bb6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/FileHeader.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/FileHeader.kt @@ -6,7 +6,6 @@ import android.util.Log import com.vitorpamplona.amethyst.model.toHexKey import com.vitorpamplona.amethyst.ui.actions.ImageDownloader import io.trbl.blurhash.BlurHash -import java.security.MessageDigest import kotlin.math.roundToInt class FileHeader( @@ -45,9 +44,7 @@ class FileHeader( onError: () -> Unit ) { try { - val sha256 = MessageDigest.getInstance("SHA-256") - - val hash = sha256.digest(data).toHexKey() + val hash = CryptoUtils.sha256(data).toHexKey() val size = data.size val (blurHash, dim) = if (mimeType?.startsWith("image/") == true) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/model/Event.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/model/Event.kt index f86581914..343409499 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/model/Event.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/model/Event.kt @@ -13,7 +13,6 @@ import fr.acinq.secp256k1.Hex import fr.acinq.secp256k1.Secp256k1 import java.lang.reflect.Type import java.math.BigDecimal -import java.security.MessageDigest import java.util.* @Immutable @@ -157,14 +156,14 @@ open class Event( """.trimIndent() ) } - if (!secp256k1.verifySchnorr(Hex.decode(sig), Hex.decode(id), Hex.decode(pubKey))) { + if (!CryptoUtils.verifySignature(Hex.decode(sig), Hex.decode(id), Hex.decode(pubKey))) { throw Exception("""Bad signature!""") } } override fun hasValidSignature(): Boolean { return try { - id.contentEquals(generateId()) && secp256k1.verifySchnorr(Hex.decode(sig), Hex.decode(id), Hex.decode(pubKey)) + id.contentEquals(generateId()) && CryptoUtils.verifySignature(Hex.decode(sig), Hex.decode(id), Hex.decode(pubKey)) } catch (e: Exception) { Log.e("Event", "Fail checking if event $id has a valid signature", e) false @@ -182,7 +181,7 @@ open class Event( .replace("\\u2028", "\u2028") .replace("\\u2029", "\u2029") - return MessageDigest.getInstance("SHA-256").digest(rawEventJson.toByteArray()).toHexKey() + return CryptoUtils.sha256(rawEventJson.toByteArray()).toHexKey() } private class EventDeserializer : JsonDeserializer { @@ -336,7 +335,7 @@ open class Event( .replace("\\u2028", "\u2028") .replace("\\u2029", "\u2029") - return MessageDigest.getInstance("SHA-256").digest(rawEventJson.toByteArray()) + return CryptoUtils.sha256(rawEventJson.toByteArray()) } fun create(privateKey: ByteArray, kind: Int, tags: List> = emptyList(), content: String = "", createdAt: Long = TimeUtils.now()): Event { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/model/HTTPAuthorizationEvent.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/model/HTTPAuthorizationEvent.kt index 8334b668d..e2f9f6018 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/model/HTTPAuthorizationEvent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/model/HTTPAuthorizationEvent.kt @@ -5,7 +5,6 @@ import com.vitorpamplona.amethyst.model.HexKey import com.vitorpamplona.amethyst.model.TimeUtils import com.vitorpamplona.amethyst.model.toHexKey import com.vitorpamplona.amethyst.service.CryptoUtils -import java.security.MessageDigest @Immutable class HTTPAuthorizationEvent( @@ -27,11 +26,9 @@ class HTTPAuthorizationEvent( privateKey: ByteArray, createdAt: Long = TimeUtils.now() ): HTTPAuthorizationEvent { - val sha256 = MessageDigest.getInstance("SHA-256") - var hash = "" body?.let { - hash = sha256.digest(it.toByteArray()).toHexKey() + hash = CryptoUtils.sha256(it.toByteArray()).toHexKey() } val tags = listOfNotNull( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/model/LnZapRequestEvent.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/model/LnZapRequestEvent.kt index 289dda413..9412d8ddc 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/model/LnZapRequestEvent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/model/LnZapRequestEvent.kt @@ -5,7 +5,6 @@ import com.vitorpamplona.amethyst.model.* import com.vitorpamplona.amethyst.service.Bech32 import com.vitorpamplona.amethyst.service.CryptoUtils import java.nio.charset.Charset -import java.security.MessageDigest import java.security.SecureRandom import javax.crypto.BadPaddingException import javax.crypto.Cipher @@ -133,7 +132,7 @@ class LnZapRequestEvent( fun createEncryptionPrivateKey(privkey: String, id: String, createdAt: Long): ByteArray { var str = privkey + id + createdAt.toString() var strbyte = str.toByteArray(Charset.forName("utf-8")) - return MessageDigest.getInstance("SHA-256").digest(strbyte) + return CryptoUtils.sha256(strbyte) } private fun encryptPrivateZapMessage(msg: String, privkey: ByteArray, pubkey: ByteArray): String { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/Robohash.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/Robohash.kt index e2f92c79e..e8f635e8f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/Robohash.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/Robohash.kt @@ -13,9 +13,9 @@ import coil.fetch.Fetcher import coil.fetch.SourceResult import coil.request.ImageRequest import coil.request.Options +import com.vitorpamplona.amethyst.service.CryptoUtils import com.vitorpamplona.amethyst.service.checkNotInMainThread import okio.Buffer -import java.security.MessageDigest private fun toHex(color: Color): String { val argb = color.toArgb() @@ -35,7 +35,7 @@ private fun bytesToRGB(b1: Byte, b2: Byte, b3: Byte): Color { private fun svgString(msg: String): String { checkNotInMainThread() - val hash = MessageDigest.getInstance("SHA-256").digest(msg.toByteArray()) + val hash = CryptoUtils.sha256(msg.toByteArray()) val hashHex = hash.joinToString(separator = "") { b -> "%02x".format(b) } val bgColor = bytesToRGB(hash[0], hash[1], hash[2]) val fgColor = bytesToRGB(hash[3], hash[4], hash[5]) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index 57e1813b3..eb958abdc 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -69,6 +69,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.ConnectivityType import com.vitorpamplona.amethyst.model.toHexKey import com.vitorpamplona.amethyst.service.BlurHashRequester +import com.vitorpamplona.amethyst.service.CryptoUtils import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.ui.actions.CloseButton import com.vitorpamplona.amethyst.ui.actions.LoadingAnimation @@ -91,7 +92,6 @@ import kotlinx.coroutines.launch import net.engawapg.lib.zoomable.rememberZoomState import net.engawapg.lib.zoomable.zoomable import java.io.File -import java.security.MessageDigest @Immutable abstract class ZoomableContent( @@ -697,11 +697,7 @@ private fun verifyHash(content: ZoomableUrlContent, context: Context): Boolean? if (content.hash == null) return null context.imageLoader.diskCache?.get(content.url)?.use { snapshot -> - val imageFile = snapshot.data.toFile() - val bytes = imageFile.readBytes() - val sha256 = MessageDigest.getInstance("SHA-256") - - val hash = sha256.digest(bytes).toHexKey() + val hash = CryptoUtils.sha256(snapshot.data.toFile().readBytes()).toHexKey() Log.d("Image Hash Verification", "$hash == ${content.hash}")