mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-12 03:57:42 +00:00
Remove weird roundabout way of doing decryption
This commit is contained in:
@@ -2,13 +2,11 @@ package org.session.libsession.messaging
|
||||
|
||||
import android.content.Context
|
||||
import org.session.libsession.database.MessageDataProvider
|
||||
import org.session.libsignal.service.loki.api.crypto.SessionProtocol
|
||||
|
||||
class MessagingModuleConfiguration(
|
||||
val context: Context,
|
||||
val storage: StorageProtocol,
|
||||
val messageDataProvider: MessageDataProvider,
|
||||
val sessionProtocol: SessionProtocol
|
||||
val messageDataProvider: MessageDataProvider
|
||||
) {
|
||||
|
||||
companion object {
|
||||
@@ -16,11 +14,10 @@ class MessagingModuleConfiguration(
|
||||
|
||||
fun configure(context: Context,
|
||||
storage: StorageProtocol,
|
||||
messageDataProvider: MessageDataProvider,
|
||||
sessionProtocol: SessionProtocol
|
||||
messageDataProvider: MessageDataProvider
|
||||
) {
|
||||
if (Companion::shared.isInitialized) { return }
|
||||
shared = MessagingModuleConfiguration(context, storage, messageDataProvider, sessionProtocol)
|
||||
shared = MessagingModuleConfiguration(context, storage, messageDataProvider)
|
||||
}
|
||||
}
|
||||
}
|
@@ -92,7 +92,7 @@ interface StorageProtocol {
|
||||
fun removeLastDeletionServerId(room: String, server: String)
|
||||
|
||||
// Message Handling
|
||||
fun isMessageDuplicated(timestamp: Long, sender: String): Boolean
|
||||
fun isDuplicateMessage(timestamp: Long, sender: String): Boolean
|
||||
fun getReceivedMessageTimestamps(): Set<Long>
|
||||
fun addReceivedMessageTimestamp(timestamp: Long)
|
||||
fun removeReceivedMessageTimestamps(timestamps: Set<Long>)
|
||||
|
@@ -0,0 +1,52 @@
|
||||
package org.session.libsession.messaging.sending_receiving
|
||||
|
||||
import android.util.Log
|
||||
import com.goterl.lazycode.lazysodium.LazySodiumAndroid
|
||||
import com.goterl.lazycode.lazysodium.SodiumAndroid
|
||||
import com.goterl.lazycode.lazysodium.interfaces.Box
|
||||
import com.goterl.lazycode.lazysodium.interfaces.Sign
|
||||
import org.session.libsignal.libsignal.ecc.ECKeyPair
|
||||
import org.session.libsignal.service.loki.utilities.hexEncodedPublicKey
|
||||
import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded
|
||||
import org.session.libsignal.service.loki.utilities.toHexString
|
||||
import org.session.libsignal.utilities.Hex
|
||||
|
||||
object MessageDecrypter {
|
||||
|
||||
private val sodium by lazy { LazySodiumAndroid(SodiumAndroid()) }
|
||||
|
||||
public fun decrypt(ciphertext: ByteArray, x25519KeyPair: ECKeyPair): Pair<ByteArray, String> {
|
||||
val recipientX25519PrivateKey = x25519KeyPair.privateKey.serialize()
|
||||
val recipientX25519PublicKey = Hex.fromStringCondensed(x25519KeyPair.hexEncodedPublicKey.removing05PrefixIfNeeded())
|
||||
val signatureSize = Sign.BYTES
|
||||
val ed25519PublicKeySize = Sign.PUBLICKEYBYTES
|
||||
|
||||
// 1. ) Decrypt the message
|
||||
val plaintextWithMetadata = ByteArray(ciphertext.size - Box.SEALBYTES)
|
||||
try {
|
||||
sodium.cryptoBoxSealOpen(plaintextWithMetadata, ciphertext, ciphertext.size.toLong(), recipientX25519PublicKey, recipientX25519PrivateKey)
|
||||
} catch (exception: Exception) {
|
||||
Log.d("Loki", "Couldn't decrypt message due to error: $exception.")
|
||||
throw MessageReceiver.Error.DecryptionFailed
|
||||
}
|
||||
if (plaintextWithMetadata.size <= (signatureSize + ed25519PublicKeySize)) { throw MessageReceiver.Error.DecryptionFailed }
|
||||
// 2. ) Get the message parts
|
||||
val signature = plaintextWithMetadata.sliceArray(plaintextWithMetadata.size - signatureSize until plaintextWithMetadata.size)
|
||||
val senderED25519PublicKey = plaintextWithMetadata.sliceArray(plaintextWithMetadata.size - (signatureSize + ed25519PublicKeySize) until plaintextWithMetadata.size - signatureSize)
|
||||
val plaintext = plaintextWithMetadata.sliceArray(0 until plaintextWithMetadata.size - (signatureSize + ed25519PublicKeySize))
|
||||
// 3. ) Verify the signature
|
||||
val verificationData = (plaintext + senderED25519PublicKey + recipientX25519PublicKey)
|
||||
try {
|
||||
val isValid = sodium.cryptoSignVerifyDetached(signature, verificationData, verificationData.size, senderED25519PublicKey)
|
||||
if (!isValid) { throw MessageReceiver.Error.InvalidSignature }
|
||||
} catch (exception: Exception) {
|
||||
Log.d("Loki", "Couldn't verify message signature due to error: $exception.")
|
||||
throw MessageReceiver.Error.InvalidSignature
|
||||
}
|
||||
// 4. ) Get the sender's X25519 public key
|
||||
val senderX25519PublicKey = ByteArray(Sign.CURVE25519_PUBLICKEYBYTES)
|
||||
sodium.convertPublicKeyEd25519ToCurve25519(senderX25519PublicKey, senderED25519PublicKey)
|
||||
|
||||
return Pair(plaintext, "05" + senderX25519PublicKey.toHexString())
|
||||
}
|
||||
}
|
@@ -10,35 +10,25 @@ import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||
|
||||
object MessageReceiver {
|
||||
|
||||
private val lastEncryptionKeyPairRequest = mutableMapOf<String, Long>()
|
||||
|
||||
internal sealed class Error(val description: String) : Exception(description) {
|
||||
internal sealed class Error(message: String) : Exception(message) {
|
||||
object DuplicateMessage: Error("Duplicate message.")
|
||||
object InvalidMessage: Error("Invalid message.")
|
||||
object UnknownMessage: Error("Unknown message type.")
|
||||
object UnknownEnvelopeType: Error("Unknown envelope type.")
|
||||
object NoUserX25519KeyPair: Error("Couldn't find user X25519 key pair.")
|
||||
object NoUserED25519KeyPair: Error("Couldn't find user ED25519 key pair.")
|
||||
object DecryptionFailed : Exception("Couldn't decrypt message.")
|
||||
object InvalidSignature: Error("Invalid message signature.")
|
||||
object NoData: Error("Received an empty envelope.")
|
||||
object SenderBlocked: Error("Received a message from a blocked user.")
|
||||
object NoThread: Error("Couldn't find thread for message.")
|
||||
object SelfSend: Error("Message addressed at self.")
|
||||
object ParsingFailed : Error("Couldn't parse ciphertext message.")
|
||||
// Shared sender keys
|
||||
object InvalidGroupPublicKey: Error("Invalid group public key.")
|
||||
object NoGroupKeyPair: Error("Missing group key pair.")
|
||||
|
||||
internal val isRetryable: Boolean = when (this) {
|
||||
is DuplicateMessage -> false
|
||||
is InvalidMessage -> false
|
||||
is UnknownMessage -> false
|
||||
is UnknownEnvelopeType -> false
|
||||
is InvalidSignature -> false
|
||||
is NoData -> false
|
||||
is NoThread -> false
|
||||
is SenderBlocked -> false
|
||||
is SelfSend -> false
|
||||
is DuplicateMessage, is InvalidMessage, is UnknownMessage,
|
||||
is UnknownEnvelopeType, is InvalidSignature, is NoData,
|
||||
is SenderBlocked, is SelfSend -> false
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
@@ -46,13 +36,15 @@ object MessageReceiver {
|
||||
internal fun parse(data: ByteArray, openGroupServerID: Long?, isRetry: Boolean = false): Pair<Message, SignalServiceProtos.Content> {
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val userPublicKey = storage.getUserPublicKey()
|
||||
val isOpenGroupMessage = openGroupServerID != null
|
||||
val isOpenGroupMessage = (openGroupServerID != null)
|
||||
// Parse the envelope
|
||||
val envelope = SignalServiceProtos.Envelope.parseFrom(data)
|
||||
// If the message failed to process the first time around we retry it later (if the error is retryable). In this case the timestamp
|
||||
// will already be in the database but we don't want to treat the message as a duplicate. The isRetry flag is a simple workaround
|
||||
// for this issue.
|
||||
if (storage.isMessageDuplicated(envelope.timestamp, GroupUtil.doubleEncodeGroupID(envelope.source)) && !isRetry) throw Error.DuplicateMessage
|
||||
if (storage.isDuplicateMessage(envelope.timestamp, GroupUtil.doubleEncodeGroupID(envelope.source)) && !isRetry) {
|
||||
throw Error.DuplicateMessage
|
||||
}
|
||||
// Decrypt the contents
|
||||
val ciphertext = envelope.content ?: throw Error.NoData
|
||||
var plaintext: ByteArray? = null
|
||||
@@ -65,7 +57,7 @@ object MessageReceiver {
|
||||
when (envelope.type) {
|
||||
SignalServiceProtos.Envelope.Type.SESSION_MESSAGE -> {
|
||||
val userX25519KeyPair = MessagingModuleConfiguration.shared.storage.getUserX25519KeyPair()
|
||||
val decryptionResult = MessageReceiverDecryption.decryptWithSessionProtocol(ciphertext.toByteArray(), userX25519KeyPair)
|
||||
val decryptionResult = MessageDecrypter.decrypt(ciphertext.toByteArray(), userX25519KeyPair)
|
||||
plaintext = decryptionResult.first
|
||||
sender = decryptionResult.second
|
||||
}
|
||||
@@ -81,7 +73,7 @@ object MessageReceiver {
|
||||
var encryptionKeyPair = encryptionKeyPairs.removeLast()
|
||||
fun decrypt() {
|
||||
try {
|
||||
val decryptionResult = MessageReceiverDecryption.decryptWithSessionProtocol(ciphertext.toByteArray(), encryptionKeyPair)
|
||||
val decryptionResult = MessageDecrypter.decrypt(ciphertext.toByteArray(), encryptionKeyPair)
|
||||
plaintext = decryptionResult.first
|
||||
sender = decryptionResult.second
|
||||
} catch (e: Exception) {
|
||||
@@ -100,9 +92,9 @@ object MessageReceiver {
|
||||
}
|
||||
}
|
||||
// Don't process the envelope any further if the message has been handled already
|
||||
if (storage.isMessageDuplicated(envelope.timestamp, sender!!) && !isRetry) throw Error.DuplicateMessage
|
||||
if (storage.isDuplicateMessage(envelope.timestamp, sender!!) && !isRetry) throw Error.DuplicateMessage
|
||||
// Don't process the envelope any further if the sender is blocked
|
||||
if (isBlock(sender!!)) throw Error.SenderBlocked
|
||||
if (isBlocked(sender!!)) throw Error.SenderBlocked
|
||||
// Parse the proto
|
||||
val proto = SignalServiceProtos.Content.parseFrom(PushTransportDetails.getStrippedPaddingMessageBody(plaintext))
|
||||
// Parse the message
|
||||
@@ -113,7 +105,7 @@ object MessageReceiver {
|
||||
ExpirationTimerUpdate.fromProto(proto) ?:
|
||||
ConfigurationMessage.fromProto(proto) ?:
|
||||
VisibleMessage.fromProto(proto) ?: throw Error.UnknownMessage
|
||||
// Ignore self sends if needed
|
||||
// Ignore self send if needed
|
||||
if (!message.isSelfSendValid && sender == userPublicKey) throw Error.SelfSend
|
||||
// Guard against control messages in open groups
|
||||
if (isOpenGroupMessage && message !is VisibleMessage) throw Error.InvalidMessage
|
||||
|
@@ -1,11 +0,0 @@
|
||||
package org.session.libsession.messaging.sending_receiving
|
||||
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsignal.libsignal.ecc.ECKeyPair
|
||||
|
||||
object MessageReceiverDecryption {
|
||||
|
||||
internal fun decryptWithSessionProtocol(ciphertext: ByteArray, x25519KeyPair: ECKeyPair): Pair<ByteArray, String> {
|
||||
return MessagingModuleConfiguration.shared.sessionProtocol.decrypt(ciphertext, x25519KeyPair)
|
||||
}
|
||||
}
|
@@ -34,7 +34,7 @@ import java.security.MessageDigest
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
internal fun MessageReceiver.isBlock(publicKey: String): Boolean {
|
||||
internal fun MessageReceiver.isBlocked(publicKey: String): Boolean {
|
||||
val context = MessagingModuleConfiguration.shared.context
|
||||
val recipient = Recipient.from(context, Address.fromSerialized(publicKey), false)
|
||||
return recipient.isBlocked
|
||||
@@ -323,7 +323,7 @@ private fun MessageReceiver.handleClosedGroupEncryptionKeyPair(message: ClosedGr
|
||||
// Find our wrapper and decrypt it if possible
|
||||
val wrapper = kind.wrappers.firstOrNull { it.publicKey!! == userPublicKey } ?: return
|
||||
val encryptedKeyPair = wrapper.encryptedKeyPair!!.toByteArray()
|
||||
val plaintext = MessageReceiverDecryption.decryptWithSessionProtocol(encryptedKeyPair, userKeyPair).first
|
||||
val plaintext = MessageDecrypter.decrypt(encryptedKeyPair, userKeyPair).first
|
||||
// Parse it
|
||||
val proto = SignalServiceProtos.KeyPair.parseFrom(plaintext)
|
||||
val keyPair = ECKeyPair(DjbECPublicKey(proto.publicKey.toByteArray().removing05PrefixIfNeeded()), DjbECPrivateKey(proto.privateKey.toByteArray()))
|
||||
|
Reference in New Issue
Block a user