Message validation refactor

This commit is contained in:
charles 2022-05-06 11:38:09 +10:00
parent edb4f96f0a
commit bb50182a18
5 changed files with 54 additions and 23 deletions

View File

@ -359,7 +359,7 @@ object OpenGroupApi {
room: String, room: String,
server: String server: String
): Promise<OpenGroupMessage, Exception> { ): Promise<OpenGroupMessage, Exception> {
val signedMessage = message.sign() ?: return Promise.ofFail(Error.SigningFailed) val signedMessage = message.sign(room, server, fallbackSigningType = IdPrefix.STANDARD) ?: return Promise.ofFail(Error.SigningFailed)
val jsonMessage = signedMessage.toJSON() val jsonMessage = signedMessage.toJSON()
val request = Request( val request = Request(
verb = POST, verb = POST,

View File

@ -1,10 +1,12 @@
package org.session.libsession.messaging.open_groups package org.session.libsession.messaging.open_groups
import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.utilities.SodiumUtilities
import org.session.libsignal.crypto.PushTransportDetails import org.session.libsignal.crypto.PushTransportDetails
import org.session.libsignal.protos.SignalServiceProtos import org.session.libsignal.protos.SignalServiceProtos
import org.session.libsignal.utilities.Base64 import org.session.libsignal.utilities.Base64
import org.session.libsignal.utilities.Base64.decode import org.session.libsignal.utilities.Base64.decode
import org.session.libsignal.utilities.IdPrefix
import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.toHexString import org.session.libsignal.utilities.toHexString
import org.whispersystems.curve25519.Curve25519 import org.whispersystems.curve25519.Curve25519
@ -29,30 +31,47 @@ data class OpenGroupMessage(
fun fromJSON(json: Map<String, Any>): OpenGroupMessage? { fun fromJSON(json: Map<String, Any>): OpenGroupMessage? {
val base64EncodedData = json["data"] as? String ?: return null val base64EncodedData = json["data"] as? String ?: return null
val sentTimestamp = json["posted"] as? Long ?: return null val sentTimestamp = json["posted"] as? Double ?: return null
val serverID = json["id"] as? Int val serverID = json["id"] as? Int
val sender = json["session_id"] as? String val sender = json["session_id"] as? String
val base64EncodedSignature = json["signature"] as? String val base64EncodedSignature = json["signature"] as? String
return OpenGroupMessage( return OpenGroupMessage(
serverID = serverID?.toLong(), serverID = serverID?.toLong(),
sender = sender, sender = sender,
sentTimestamp = sentTimestamp, sentTimestamp = (sentTimestamp * 1000).toLong(),
base64EncodedData = base64EncodedData, base64EncodedData = base64EncodedData,
base64EncodedSignature = base64EncodedSignature base64EncodedSignature = base64EncodedSignature
) )
} }
} }
fun sign(): OpenGroupMessage? { fun sign(room: String, server: String, fallbackSigningType: IdPrefix): OpenGroupMessage? {
if (base64EncodedData.isEmpty()) return null if (base64EncodedData.isEmpty()) return null
val (publicKey, privateKey) = MessagingModuleConfiguration.shared.storage.getUserX25519KeyPair().let { it.publicKey to it.privateKey } val userEdKeyPair = MessagingModuleConfiguration.shared.getUserED25519KeyPair() ?: return null
if (sender != publicKey.serialize().toHexString()) return null val openGroup = MessagingModuleConfiguration.shared.storage.getOpenGroup(room, server) ?: return null
val signature = try { val signature = when {
curve.calculateSignature(privateKey.serialize(), decode(base64EncodedData)) openGroup.capabilities.contains("blind") -> {
} catch (e: Exception) { val blindedKeyPair = SodiumUtilities.blindedKeyPair(openGroup.publicKey, userEdKeyPair) ?: return null
Log.w("Loki", "Couldn't sign open group message.", e) SodiumUtilities.sogsSignature(
return null decode(base64EncodedData),
userEdKeyPair.secretKey.asBytes,
blindedKeyPair.secretKey.asBytes,
blindedKeyPair.publicKey.asBytes
) ?: return null
}
fallbackSigningType == IdPrefix.UN_BLINDED -> {
curve.calculateSignature(userEdKeyPair.secretKey.asBytes, decode(base64EncodedData))
}
else -> {
val (publicKey, privateKey) = MessagingModuleConfiguration.shared.storage.getUserX25519KeyPair().let { it.publicKey to it.privateKey }
if (sender != publicKey.serialize().toHexString()) return null
try {
curve.calculateSignature(privateKey.serialize(), decode(base64EncodedData))
} catch (e: Exception) {
Log.w("Loki", "Couldn't sign open group message.", e)
return null
}
}
} }
return copy(base64EncodedSignature = Base64.encodeBytes(signature)) return copy(base64EncodedSignature = Base64.encodeBytes(signature))
} }

View File

@ -8,9 +8,9 @@ import com.goterl.lazysodium.interfaces.Sign
import org.session.libsession.messaging.utilities.SessionId import org.session.libsession.messaging.utilities.SessionId
import org.session.libsignal.crypto.ecc.ECKeyPair import org.session.libsignal.crypto.ecc.ECKeyPair
import org.session.libsignal.utilities.Hex import org.session.libsignal.utilities.Hex
import org.session.libsignal.utilities.IdPrefix
import org.session.libsignal.utilities.hexEncodedPublicKey import org.session.libsignal.utilities.hexEncodedPublicKey
import org.session.libsignal.utilities.removing05PrefixIfNeeded import org.session.libsignal.utilities.removingIdPrefixIfNeeded
import org.session.libsignal.utilities.toHexString
object MessageDecrypter { object MessageDecrypter {
@ -26,7 +26,7 @@ object MessageDecrypter {
*/ */
public fun decrypt(ciphertext: ByteArray, x25519KeyPair: ECKeyPair): Pair<ByteArray, String> { public fun decrypt(ciphertext: ByteArray, x25519KeyPair: ECKeyPair): Pair<ByteArray, String> {
val recipientX25519PrivateKey = x25519KeyPair.privateKey.serialize() val recipientX25519PrivateKey = x25519KeyPair.privateKey.serialize()
val recipientX25519PublicKey = Hex.fromStringCondensed(x25519KeyPair.hexEncodedPublicKey.removing05PrefixIfNeeded()) val recipientX25519PublicKey = Hex.fromStringCondensed(x25519KeyPair.hexEncodedPublicKey.removingIdPrefixIfNeeded())
val signatureSize = Sign.BYTES val signatureSize = Sign.BYTES
val ed25519PublicKeySize = Sign.PUBLICKEYBYTES val ed25519PublicKeySize = Sign.PUBLICKEYBYTES

View File

@ -8,7 +8,7 @@ import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.sending_receiving.MessageSender.Error import org.session.libsession.messaging.sending_receiving.MessageSender.Error
import org.session.libsignal.utilities.Hex import org.session.libsignal.utilities.Hex
import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.removing05PrefixIfNeeded import org.session.libsignal.utilities.removingIdPrefixIfNeeded
object MessageEncrypter { object MessageEncrypter {
@ -24,7 +24,7 @@ object MessageEncrypter {
*/ */
internal fun encrypt(plaintext: ByteArray, recipientHexEncodedX25519PublicKey: String): ByteArray { internal fun encrypt(plaintext: ByteArray, recipientHexEncodedX25519PublicKey: String): ByteArray {
val userED25519KeyPair = MessagingModuleConfiguration.shared.getUserED25519KeyPair() ?: throw Error.NoUserED25519KeyPair val userED25519KeyPair = MessagingModuleConfiguration.shared.getUserED25519KeyPair() ?: throw Error.NoUserED25519KeyPair
val recipientX25519PublicKey = Hex.fromStringCondensed(recipientHexEncodedX25519PublicKey.removing05PrefixIfNeeded()) val recipientX25519PublicKey = Hex.fromStringCondensed(recipientHexEncodedX25519PublicKey.removingIdPrefixIfNeeded())
val verificationData = plaintext + userED25519KeyPair.publicKey.asBytes + recipientX25519PublicKey val verificationData = plaintext + userED25519KeyPair.publicKey.asBytes + recipientX25519PublicKey
val signature = ByteArray(Sign.BYTES) val signature = ByteArray(Sign.BYTES)

View File

@ -229,15 +229,15 @@ object MessageSender {
message.profile = Profile(displayName) message.profile = Profile(displayName)
} }
} }
// Validate the message
if (message !is VisibleMessage || !message.isValid()) {
throw Error.InvalidMessage
}
val messageBody = message.toProto()?.toByteArray()!!
val plaintext = PushTransportDetails.getPaddedMessageBody(messageBody)
when (destination) { when (destination) {
is Destination.LegacyOpenGroup -> { is Destination.LegacyOpenGroup -> {
message.recipient = "${destination.server}.${destination.roomToken}" message.recipient = "${destination.server}.${destination.roomToken}"
// Validate the message
if (message !is VisibleMessage || !message.isValid()) {
throw Error.InvalidMessage
}
val messageBody = message.toProto()?.toByteArray()!!
val plaintext = PushTransportDetails.getPaddedMessageBody(messageBody)
val openGroupMessage = OpenGroupMessage( val openGroupMessage = OpenGroupMessage(
sender = message.sender, sender = message.sender,
sentTimestamp = message.sentTimestamp!!, sentTimestamp = message.sentTimestamp!!,
@ -253,6 +253,12 @@ object MessageSender {
} }
is Destination.OpenGroup -> { is Destination.OpenGroup -> {
message.recipient = "${destination.server}.${destination.roomToken}" message.recipient = "${destination.server}.${destination.roomToken}"
// Validate the message
if (message !is VisibleMessage || !message.isValid()) {
throw Error.InvalidMessage
}
val messageBody = message.toProto()?.toByteArray()!!
val plaintext = PushTransportDetails.getPaddedMessageBody(messageBody)
val openGroupMessage = OpenGroupMessage( val openGroupMessage = OpenGroupMessage(
sender = message.sender, sender = message.sender,
sentTimestamp = message.sentTimestamp!!, sentTimestamp = message.sentTimestamp!!,
@ -268,6 +274,12 @@ object MessageSender {
} }
is Destination.OpenGroupInbox -> { is Destination.OpenGroupInbox -> {
message.recipient = destination.blinkedPublicKey message.recipient = destination.blinkedPublicKey
// Validate the message
if (message !is VisibleMessage || !message.isValid()) {
throw Error.InvalidMessage
}
val messageBody = message.toProto()?.toByteArray()!!
val plaintext = PushTransportDetails.getPaddedMessageBody(messageBody)
val base64EncodedData = Base64.encodeBytes(plaintext) val base64EncodedData = Base64.encodeBytes(plaintext)
OpenGroupApi.sendDirectMessage(base64EncodedData, destination.blinkedPublicKey, destination.server).success { OpenGroupApi.sendDirectMessage(base64EncodedData, destination.blinkedPublicKey, destination.server).success {
message.openGroupServerMessageID = it.id message.openGroupServerMessageID = it.id