Separating NIP24 into the encryption NIP 44 and the messaging NIP 24

pull/553/head
Vitor Pamplona 2023-08-22 09:41:40 -04:00
rodzic d73dec8f0b
commit fa4257ad7d
8 zmienionych plików z 46 dodań i 46 usunięć

Wyświetl plik

@ -21,7 +21,7 @@ class ImageUploadTesting {
val image = "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"
fun testBase(server: FileServer) {
private fun testBase(server: FileServer) {
val bytes = Base64.getDecoder().decode(image)
val inputStream = bytes.inputStream()
@ -39,7 +39,7 @@ class ImageUploadTesting {
"image/gif",
server,
onSuccess = { newUrl, contentType ->
println("Uploaded to $url")
println("Uploaded $contentType to $url")
url = newUrl
countDownLatch.countDown()
},

Wyświetl plik

@ -4128,7 +4128,7 @@ https://nostr.build/i/fd53fcf5ad950fbe45127e4bcee1b59e8301d41de6beee211f45e344db
}
private fun printStateForDebug(state: RichTextViewerState) {
state.paragraphs.forEachIndexed { index, paragraph ->
state.paragraphs.forEach { paragraph ->
paragraph.words.forEach { seg ->
println(
"\"${

Wyświetl plik

@ -38,7 +38,7 @@ class CryptoBenchmark {
val keyPair2 = KeyPair()
benchmarkRule.measureRepeated {
assertNotNull(CryptoUtils.getSharedSecretNIP24(keyPair1.privKey!!, keyPair2.pubKey))
assertNotNull(CryptoUtils.getSharedSecretNIP44(keyPair1.privKey!!, keyPair2.pubKey))
}
}
@ -58,7 +58,7 @@ class CryptoBenchmark {
val keyPair2 = KeyPair()
benchmarkRule.measureRepeated {
assertNotNull(CryptoUtils.computeSharedSecretNIP24(keyPair1.privKey!!, keyPair2.pubKey))
assertNotNull(CryptoUtils.computeSharedSecretNIP44(keyPair1.privKey!!, keyPair2.pubKey))
}
}

Wyświetl plik

@ -166,7 +166,7 @@ class GiftWrapReceivingBenchmark {
val toDecrypt = decodeNIP44(wrappedEvent.content) ?: return
benchmarkRule.measureRepeated {
assertNotNull(CryptoUtils.decryptNIP24(toDecrypt, sender.privKey!!, wrappedEvent.pubKey.hexToByteArray()))
assertNotNull(CryptoUtils.decryptNIP44(toDecrypt, sender.privKey!!, wrappedEvent.pubKey.hexToByteArray()))
}
}
@ -191,7 +191,7 @@ class GiftWrapReceivingBenchmark {
)
val toDecrypt = decodeNIP44(wrappedEvent.content) ?: return
val innerJson = CryptoUtils.decryptNIP24(toDecrypt, sender.privKey!!, wrappedEvent.pubKey.hexToByteArray())
val innerJson = CryptoUtils.decryptNIP44(toDecrypt, sender.privKey!!, wrappedEvent.pubKey.hexToByteArray())
benchmarkRule.measureRepeated {
assertNotNull(innerJson?.let { Event.fromJson(it) })
@ -236,7 +236,7 @@ class GiftWrapReceivingBenchmark {
val toDecrypt = decodeNIP44(seal.content) ?: return
benchmarkRule.measureRepeated {
assertNotNull(CryptoUtils.decryptNIP24(toDecrypt, sender.privKey!!, seal.pubKey.hexToByteArray()))
assertNotNull(CryptoUtils.decryptNIP44(toDecrypt, sender.privKey!!, seal.pubKey.hexToByteArray()))
}
}
@ -256,7 +256,7 @@ class GiftWrapReceivingBenchmark {
)
val toDecrypt = decodeNIP44(seal.content) ?: return
val innerJson = CryptoUtils.decryptNIP24(toDecrypt, sender.privKey!!, seal.pubKey.hexToByteArray())
val innerJson = CryptoUtils.decryptNIP44(toDecrypt, sender.privKey!!, seal.pubKey.hexToByteArray())
benchmarkRule.measureRepeated {
assertNotNull(innerJson?.let { Gossip.fromJson(it) })

Wyświetl plik

@ -24,7 +24,7 @@ class CryptoUtilsTest {
val privateKey = "f410f88bcec6cbfda04d6a273c7b1dd8bba144cd45b71e87109cfa11dd7ed561"
val publicKey = "765cd7cf91d3ad07423d114d5a39c61d52b2cdbc18ba055ddbbeec71fbe2aa2f"
val key = CryptoUtils.getSharedSecretNIP24(privateKey = privateKey.hexToByteArray(), pubKey = publicKey.hexToByteArray())
val key = CryptoUtils.getSharedSecretNIP44(privateKey = privateKey.hexToByteArray(), pubKey = publicKey.hexToByteArray())
assertEquals("577c966f499dddd8e8dcc34e8f352e283cc177e53ae372794947e0b8ede7cfd8", key.toHexKey())
}
@ -34,8 +34,8 @@ class CryptoUtilsTest {
val sender = KeyPair()
val receiver = KeyPair()
val sharedSecret1 = CryptoUtils.getSharedSecretNIP24(sender.privKey!!, receiver.pubKey)
val sharedSecret2 = CryptoUtils.getSharedSecretNIP24(receiver.privKey!!, sender.pubKey)
val sharedSecret1 = CryptoUtils.getSharedSecretNIP44(sender.privKey!!, receiver.pubKey)
val sharedSecret2 = CryptoUtils.getSharedSecretNIP44(receiver.privKey!!, sender.pubKey)
assertEquals(sharedSecret1.toHexKey(), sharedSecret2.toHexKey())
@ -73,14 +73,14 @@ class CryptoUtilsTest {
}
@Test
fun encryptDecryptNIP24Test() {
fun encryptDecryptNIP44Test() {
val msg = "Hi"
val privateKey = CryptoUtils.privkeyCreate()
val publicKey = CryptoUtils.pubkeyCreate(privateKey)
val encrypted = CryptoUtils.encryptNIP24(msg, privateKey, publicKey)
val decrypted = CryptoUtils.decryptNIP24(encrypted, privateKey, publicKey)
val encrypted = CryptoUtils.encryptNIP44(msg, privateKey, publicKey)
val decrypted = CryptoUtils.decryptNIP44(encrypted, privateKey, publicKey)
assertEquals(msg, decrypted)
}
@ -99,15 +99,15 @@ class CryptoUtilsTest {
}
@Test
fun encryptSharedSecretDecryptNIP24Test() {
fun encryptSharedSecretDecryptNIP44Test() {
val msg = "Hi"
val privateKey = CryptoUtils.privkeyCreate()
val publicKey = CryptoUtils.pubkeyCreate(privateKey)
val sharedSecret = CryptoUtils.getSharedSecretNIP24(privateKey, publicKey)
val sharedSecret = CryptoUtils.getSharedSecretNIP44(privateKey, publicKey)
val encrypted = CryptoUtils.encryptNIP24(msg, sharedSecret)
val decrypted = CryptoUtils.decryptNIP24(encrypted, sharedSecret)
val encrypted = CryptoUtils.encryptNIP44(msg, sharedSecret)
val decrypted = CryptoUtils.decryptNIP44(encrypted, sharedSecret)
assertEquals(msg, decrypted)
}

Wyświetl plik

@ -17,7 +17,7 @@ import javax.crypto.spec.SecretKeySpec
object CryptoUtils {
private val sharedKeyCache04 = LruCache<Int, ByteArray>(200)
private val sharedKeyCache24 = LruCache<Int, ByteArray>(200)
private val sharedKeyCache44 = LruCache<Int, ByteArray>(200)
private val secp256k1 = Secp256k1.get()
private val libSodium = SodiumAndroid()
@ -26,7 +26,7 @@ object CryptoUtils {
fun clearCache() {
sharedKeyCache04.evictAll()
sharedKeyCache24.evictAll()
sharedKeyCache44.evictAll()
}
fun randomInt(bound: Int): Int {
@ -115,12 +115,12 @@ object CryptoUtils {
return String(cipher.doFinal(encryptedMsg))
}
fun encryptNIP24(msg: String, privateKey: ByteArray, pubKey: ByteArray): EncryptedInfo {
val sharedSecret = getSharedSecretNIP24(privateKey, pubKey)
return encryptNIP24(msg, sharedSecret)
fun encryptNIP44(msg: String, privateKey: ByteArray, pubKey: ByteArray): EncryptedInfo {
val sharedSecret = getSharedSecretNIP44(privateKey, pubKey)
return encryptNIP44(msg, sharedSecret)
}
fun encryptNIP24(msg: String, sharedSecret: ByteArray): EncryptedInfo {
fun encryptNIP44(msg: String, sharedSecret: ByteArray): EncryptedInfo {
val nonce = ByteArray(24)
random.nextBytes(nonce)
@ -134,16 +134,16 @@ object CryptoUtils {
return EncryptedInfo(
ciphertext = cipher ?: ByteArray(0),
nonce = nonce,
v = Nip44Version.NIP24.versionCode
v = Nip44Version.NIP44.versionCode
)
}
fun decryptNIP24(encryptedInfo: EncryptedInfo, privateKey: ByteArray, pubKey: ByteArray): String? {
val sharedSecret = getSharedSecretNIP24(privateKey, pubKey)
return decryptNIP24(encryptedInfo, sharedSecret)
fun decryptNIP44(encryptedInfo: EncryptedInfo, privateKey: ByteArray, pubKey: ByteArray): String? {
val sharedSecret = getSharedSecretNIP44(privateKey, pubKey)
return decryptNIP44(encryptedInfo, sharedSecret)
}
fun decryptNIP24(encryptedInfo: EncryptedInfo, sharedSecret: ByteArray): String? {
fun decryptNIP44(encryptedInfo: EncryptedInfo, sharedSecret: ByteArray): String? {
return cryptoStreamXChaCha20Xor(
libSodium = libSodium,
messageBytes = encryptedInfo.ciphertext,
@ -174,20 +174,20 @@ object CryptoUtils {
/**
* @return 32B shared secret
*/
fun getSharedSecretNIP24(privateKey: ByteArray, pubKey: ByteArray): ByteArray {
fun getSharedSecretNIP44(privateKey: ByteArray, pubKey: ByteArray): ByteArray {
val hash = combinedHashCode(privateKey, pubKey)
val preComputed = sharedKeyCache24[hash]
val preComputed = sharedKeyCache44[hash]
if (preComputed != null) return preComputed
val computed = computeSharedSecretNIP24(privateKey, pubKey)
sharedKeyCache24.put(hash, computed)
val computed = computeSharedSecretNIP44(privateKey, pubKey)
sharedKeyCache44.put(hash, computed)
return computed
}
/**
* @return 32B shared secret
*/
fun computeSharedSecretNIP24(privateKey: ByteArray, pubKey: ByteArray): ByteArray =
fun computeSharedSecretNIP44(privateKey: ByteArray, pubKey: ByteArray): ByteArray =
sha256(secp256k1.pubKeyTweakMul(h02 + pubKey, privateKey).copyOfRange(1, 33))
}
@ -196,7 +196,7 @@ data class EncryptedInfoString(val ciphertext: String, val nonce: String, val v:
enum class Nip44Version(val versionCode: Int) {
NIP04(0),
NIP24(1)
NIP44(1)
}
@ -234,10 +234,10 @@ fun decodeByteArray(base64: String): EncryptedInfo? {
fun encodeJackson(info: EncryptedInfo): String {
return Event.mapper.writeValueAsString(
EncryptedInfoString(
v = info.v,
nonce = Base64.getEncoder().encodeToString(info.nonce),
ciphertext = Base64.getEncoder().encodeToString(info.ciphertext)
)
v = info.v,
nonce = Base64.getEncoder().encodeToString(info.nonce),
ciphertext = Base64.getEncoder().encodeToString(info.ciphertext)
)
)
}

Wyświetl plik

@ -51,7 +51,7 @@ class GiftWrapEvent(
return when (toDecrypt.v) {
Nip44Version.NIP04.versionCode -> CryptoUtils.decryptNIP04(toDecrypt, privKey, pubKey.hexToByteArray())
Nip44Version.NIP24.versionCode -> CryptoUtils.decryptNIP24(toDecrypt, privKey, pubKey.hexToByteArray())
Nip44Version.NIP44.versionCode -> CryptoUtils.decryptNIP44(toDecrypt, privKey, pubKey.hexToByteArray())
else -> null
}
} catch (e: Exception) {
@ -71,10 +71,10 @@ class GiftWrapEvent(
createdAt: Long = TimeUtils.randomWithinAWeek()
): GiftWrapEvent {
val privateKey = CryptoUtils.privkeyCreate() // GiftWrap is always a random key
val sharedSecret = CryptoUtils.getSharedSecretNIP24(privateKey, recipientPubKey.hexToByteArray())
val sharedSecret = CryptoUtils.getSharedSecretNIP44(privateKey, recipientPubKey.hexToByteArray())
val content = encodeNIP44(
CryptoUtils.encryptNIP24(
CryptoUtils.encryptNIP44(
toJson(event),
sharedSecret
)

Wyświetl plik

@ -53,7 +53,7 @@ class SealedGossipEvent(
return when (toDecrypt.v) {
Nip44Version.NIP04.versionCode -> CryptoUtils.decryptNIP04(toDecrypt, privKey, pubKey.hexToByteArray())
Nip44Version.NIP24.versionCode -> CryptoUtils.decryptNIP24(toDecrypt, privKey, pubKey.hexToByteArray())
Nip44Version.NIP44.versionCode -> CryptoUtils.decryptNIP44(toDecrypt, privKey, pubKey.hexToByteArray())
else -> null
}
} catch (e: Exception) {
@ -81,10 +81,10 @@ class SealedGossipEvent(
privateKey: ByteArray,
createdAt: Long = TimeUtils.randomWithinAWeek()
): SealedGossipEvent {
val sharedSecret = CryptoUtils.getSharedSecretNIP24(privateKey, encryptTo.hexToByteArray())
val sharedSecret = CryptoUtils.getSharedSecretNIP44(privateKey, encryptTo.hexToByteArray())
val content = encodeNIP44(
CryptoUtils.encryptNIP24(
CryptoUtils.encryptNIP44(
Gossip.toJson(gossip),
sharedSecret
)