Small refactoring to create the PrivateZap Event

This commit is contained in:
Vitor Pamplona 2023-08-22 16:10:32 -04:00
parent 2d30f3e9d2
commit f027d23fcf
3 changed files with 60 additions and 16 deletions

View File

@ -41,9 +41,6 @@ class EventFactory {
ContactListEvent.kind -> ContactListEvent(id, pubKey, createdAt, tags, content, sig)
DeletionEvent.kind -> DeletionEvent(id, pubKey, createdAt, tags, content, sig)
// Will never happen.
// DirectMessageEvent.kind -> DirectMessageEvent(createdAt, tags, content)
EmojiPackEvent.kind -> EmojiPackEvent(id, pubKey, createdAt, tags, content, sig)
EmojiPackSelectionEvent.kind -> EmojiPackSelectionEvent(id, pubKey, createdAt, tags, content, sig)
SealedGossipEvent.kind -> SealedGossipEvent(id, pubKey, createdAt, tags, content, sig)
@ -59,6 +56,7 @@ class EventFactory {
LnZapEvent.kind -> LnZapEvent(id, pubKey, createdAt, tags, content, sig)
LnZapPaymentRequestEvent.kind -> LnZapPaymentRequestEvent(id, pubKey, createdAt, tags, content, sig)
LnZapPaymentResponseEvent.kind -> LnZapPaymentResponseEvent(id, pubKey, createdAt, tags, content, sig)
LnZapPrivateEvent.kind -> LnZapPrivateEvent(id, pubKey, createdAt, tags, content, sig)
LnZapRequestEvent.kind -> LnZapRequestEvent(id, pubKey, createdAt, tags, content, sig)
LongTextNoteEvent.kind -> LongTextNoteEvent(id, pubKey, createdAt, tags, content, sig)
MetadataEvent.kind -> MetadataEvent(id, pubKey, createdAt, tags, content, sig)

View File

@ -0,0 +1,43 @@
package com.vitorpamplona.quartz.events
import android.util.Log
import androidx.compose.runtime.Immutable
import com.vitorpamplona.quartz.crypto.CryptoUtils
import com.vitorpamplona.quartz.encoders.Bech32
import com.vitorpamplona.quartz.encoders.HexKey
import com.vitorpamplona.quartz.encoders.LnInvoiceUtil
import com.vitorpamplona.quartz.encoders.toHexKey
import com.vitorpamplona.quartz.utils.TimeUtils
import java.nio.charset.Charset
import java.security.SecureRandom
import javax.crypto.BadPaddingException
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
@Immutable
class LnZapPrivateEvent(
id: HexKey,
pubKey: HexKey,
createdAt: Long,
tags: List<List<String>>,
content: String,
sig: HexKey
) : Event(id, pubKey, createdAt, kind, tags, content, sig) {
companion object {
const val kind = 9733
fun create(
privateKey: ByteArray,
tags: List<List<String>> = emptyList(),
content: String = "",
createdAt: Long = TimeUtils.now()
): Event {
val pubKey = CryptoUtils.pubkeyCreate(privateKey).toHexKey()
val id = generateId(pubKey, createdAt, kind, tags, content)
val sig = CryptoUtils.sign(id, privateKey).toHexKey()
return Event(id.toHexKey(), pubKey, createdAt, kind, tags, content, sig)
}
}
}

View File

@ -86,9 +86,9 @@ class LnZapRequestEvent(
privkey = CryptoUtils.privkeyCreate()
pubKey = CryptoUtils.pubkeyCreate(privkey).toHexKey()
} else if (zapType == LnZapEvent.ZapType.PRIVATE) {
var encryptionPrivateKey = createEncryptionPrivateKey(privateKey.toHexKey(), originalNote.id(), createdAt)
var noteJson = (create(privkey, 9733, listOf(tags[0], tags[1]), message)).toJson()
var encryptedContent = encryptPrivateZapMessage(noteJson, encryptionPrivateKey, originalNote.pubKey().hexToByteArray())
val encryptionPrivateKey = createEncryptionPrivateKey(privateKey.toHexKey(), originalNote.id(), createdAt)
val noteJson = (LnZapPrivateEvent.create(privkey, listOf(tags[0], tags[1]), message)).toJson()
val encryptedContent = encryptPrivateZapMessage(noteJson, encryptionPrivateKey, originalNote.pubKey().hexToByteArray())
tags = tags + listOf(listOf("anon", encryptedContent))
content = "" // make sure public content is empty, as the content is encrypted
privkey = encryptionPrivateKey // sign event with generated privkey
@ -119,9 +119,9 @@ class LnZapRequestEvent(
pubKey = CryptoUtils.pubkeyCreate(privkey).toHexKey()
tags = tags + listOf(listOf("anon", ""))
} else if (zapType == LnZapEvent.ZapType.PRIVATE) {
var encryptionPrivateKey = createEncryptionPrivateKey(privateKey.toHexKey(), userHex, createdAt)
var noteJson = (create(privkey, 9733, listOf(tags[0], tags[1]), message)).toJson()
var encryptedContent = encryptPrivateZapMessage(noteJson, encryptionPrivateKey, userHex.hexToByteArray())
val encryptionPrivateKey = createEncryptionPrivateKey(privateKey.toHexKey(), userHex, createdAt)
val noteJson = LnZapPrivateEvent.create(privkey, listOf(tags[0], tags[1]), message).toJson()
val encryptedContent = encryptPrivateZapMessage(noteJson, encryptionPrivateKey, userHex.hexToByteArray())
tags = tags + listOf(listOf("anon", encryptedContent))
content = ""
privkey = encryptionPrivateKey
@ -132,21 +132,22 @@ class LnZapRequestEvent(
return LnZapRequestEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig.toHexKey())
}
fun createEncryptionPrivateKey(privkey: String, id: String, createdAt: Long): ByteArray {
var str = privkey + id + createdAt.toString()
var strbyte = str.toByteArray(Charset.forName("utf-8"))
val str = privkey + id + createdAt.toString()
val strbyte = str.toByteArray(Charset.forName("utf-8"))
return CryptoUtils.sha256(strbyte)
}
private fun encryptPrivateZapMessage(msg: String, privkey: ByteArray, pubkey: ByteArray): String {
var sharedSecret = CryptoUtils.getSharedSecretNIP04(privkey, pubkey)
val sharedSecret = CryptoUtils.getSharedSecretNIP04(privkey, pubkey)
val iv = ByteArray(16)
SecureRandom().nextBytes(iv)
val keySpec = SecretKeySpec(sharedSecret, "AES")
val ivSpec = IvParameterSpec(iv)
var utf8message = msg.toByteArray(Charset.forName("utf-8"))
val utf8message = msg.toByteArray(Charset.forName("utf-8"))
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec)
val encryptedMsg = cipher.doFinal(utf8message)
@ -158,7 +159,7 @@ class LnZapRequestEvent(
}
private fun decryptPrivateZapMessage(msg: String, privkey: ByteArray, pubkey: ByteArray): String {
var sharedSecret = CryptoUtils.getSharedSecretNIP04(privkey, pubkey)
val sharedSecret = CryptoUtils.getSharedSecretNIP04(privkey, pubkey)
if (sharedSecret.size != 16 && sharedSecret.size != 32) {
throw IllegalArgumentException("Invalid shared secret size")
}
@ -170,8 +171,10 @@ class LnZapRequestEvent(
val encryptedMsg = parts.first().run { Bech32.decode(this).second }
val encryptedBytes = Bech32.five2eight(encryptedMsg, 0)
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(sharedSecret, "AES"), IvParameterSpec(
Bech32.five2eight(iv, 0)))
cipher.init(
Cipher.DECRYPT_MODE, SecretKeySpec(sharedSecret, "AES"), IvParameterSpec(
Bech32.five2eight(iv, 0))
)
try {
val decryptedMsgBytes = cipher.doFinal(encryptedBytes)