Enables decryption by nip04 and nip44 on NostrWalletConnect objects, NIP-51 lists and NIP-04 messages

This commit is contained in:
Vitor Pamplona
2024-08-28 15:20:25 -04:00
parent 0f86e3d8fb
commit cb4a73bb9c
9 changed files with 137 additions and 6 deletions
@@ -81,6 +81,17 @@ object CryptoUtils {
return nip01.sha256(data)
}
fun decrypt(
msg: String,
privateKey: ByteArray,
pubKey: ByteArray,
): String? =
if (Nip04.isNIP04(msg)) {
decryptNIP04(msg, privateKey, pubKey)
} else {
decryptNIP44(msg, privateKey, pubKey)
}
/** NIP 04 Utils */
fun encryptNIP04(
msg: String,
@@ -22,7 +22,6 @@ package com.vitorpamplona.quartz.crypto.nip04
import android.util.Log
import com.vitorpamplona.quartz.crypto.SharedKeyCache
import com.vitorpamplona.quartz.crypto.nip44.Nip44v1
import com.vitorpamplona.quartz.encoders.Hex
import fr.acinq.secp256k1.Secp256k1
import java.security.SecureRandom
@@ -128,6 +127,10 @@ class Nip04(
pubKey: ByteArray,
): ByteArray = secp256k1.pubKeyTweakMul(h02 + pubKey, privateKey).copyOfRange(1, 33)
companion object {
fun isNIP04(encoded: String) = EncryptedInfo.isNIP04(encoded)
}
class EncryptedInfo(
val ciphertext: ByteArray,
val nonce: ByteArray,
@@ -138,7 +141,7 @@ class Nip04(
fun decodePayload(payload: String): EncryptedInfo? {
return try {
val byteArray = Base64.getDecoder().decode(payload)
check(byteArray[0].toInt() == Nip44v1.EncryptedInfo.V)
check(byteArray[0].toInt() == V)
return EncryptedInfo(
nonce = byteArray.copyOfRange(1, 25),
ciphertext = byteArray.copyOfRange(25, byteArray.size),
@@ -149,6 +152,11 @@ class Nip04(
}
}
fun isNIP04(encoded: String): Boolean {
val l = encoded.length
return encoded[l - 28] == '?' && encoded[l - 27] == 'i' && encoded[l - 26] == 'v' && encoded[l - 25] == '='
}
fun decodeFromNIP04(payload: String): EncryptedInfo? =
try {
val parts = payload.split("?iv=")
@@ -108,7 +108,7 @@ abstract class GeneralListEvent(
}
try {
signer.nip04Decrypt(content, pubKey) {
signer.decrypt(content, pubKey) {
privateTagsCache = mapper.readValue<Array<Array<String>>>(it)
privateTagsCache?.let { onReady(it) }
}
@@ -62,7 +62,7 @@ class LnZapPaymentRequestEvent(
}
try {
signer.nip04Decrypt(content, talkingWith(signer.pubKey)) { jsonText ->
signer.decrypt(content, talkingWith(signer.pubKey)) { jsonText ->
val payInvoiceMethod = mapper.readValue(jsonText, Request::class.java)
lnInvoice = (payInvoiceMethod as? PayInvoiceMethod)?.params?.invoice
@@ -57,7 +57,7 @@ class LnZapPaymentResponseEvent(
onReady: (String) -> Unit,
) {
try {
signer.nip04Decrypt(content, talkingWith(signer.pubKey)) { content -> onReady(content) }
signer.decrypt(content, talkingWith(signer.pubKey)) { content -> onReady(content) }
} catch (e: Exception) {
Log.w("PrivateDM", "Error decrypting the message ${e.message}")
}
@@ -92,7 +92,7 @@ class PrivateDmEvent(
return
}
signer.nip04Decrypt(content, talkingWith(signer.pubKey)) { retVal ->
signer.decrypt(content, talkingWith(signer.pubKey)) { retVal ->
val content =
if (retVal.startsWith(NIP_18_ADVERTISEMENT)) {
retVal.substring(16)
@@ -20,6 +20,7 @@
*/
package com.vitorpamplona.quartz.signers
import com.vitorpamplona.quartz.crypto.nip04.Nip04
import com.vitorpamplona.quartz.encoders.HexKey
import com.vitorpamplona.quartz.encoders.toHexKey
import com.vitorpamplona.quartz.events.Event
@@ -67,6 +68,18 @@ abstract class NostrSigner(
onReady: (LnZapPrivateEvent) -> Unit,
)
fun decrypt(
encryptedContent: String,
fromPublicKey: HexKey,
onReady: (String) -> Unit,
) {
if (Nip04.isNIP04(encryptedContent)) {
nip04Decrypt(encryptedContent, fromPublicKey, onReady)
} else {
nip44Decrypt(encryptedContent, fromPublicKey, onReady)
}
}
fun <T : Event> assembleRumor(
createdAt: Long,
kind: Int,