mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-09-19 04:59:59 +00:00
Use the shared packet identity for duplicate detection
Replay and duplicate detection keyed on a 32-bit contentHashCode over at most the first 64 bytes of the payload. Two packets from the same peer in the same millisecond that agreed on that prefix were the same packet as far as this cache was concerned, and a collision here is a dropped message: the second is discarded and nothing reports it. PacketIdUtil is the identity the rest of the stack already uses for this question — gossip sync membership, and the message IDs MessageHandler assigns — and iOS derives it identically: first 16 bytes of SHA-256 over type, senderID, timestamp and the whole payload. The security path now agrees with the sync path instead of carrying a weaker private notion of "same packet", and the FRAGMENT special case disappears because the full payload is covered either way. Peer scoping is deliberately kept. PacketIdUtil covers the packet's own senderID, which is not the peer it arrived from once relayed.
This commit is contained in:
parent
5156f7de89
commit
87ccfe3f6c
@ -3,6 +3,7 @@ package com.bitchat.android.mesh
|
||||
import android.util.Log
|
||||
import com.bitchat.android.crypto.EncryptionService
|
||||
import com.bitchat.android.protocol.BitchatPacket
|
||||
import com.bitchat.android.sync.PacketIdUtil
|
||||
import com.bitchat.android.protocol.MessageType
|
||||
import com.bitchat.android.model.RoutedPacket
|
||||
import com.bitchat.android.noise.AuthenticatedNoiseSession
|
||||
@ -241,18 +242,28 @@ class SecurityManager(private val encryptionService: EncryptionService, private
|
||||
/**
|
||||
* Generate message ID for duplicate detection
|
||||
*/
|
||||
/**
|
||||
* Identity used for replay and duplicate detection.
|
||||
*
|
||||
* This was a 32-bit `contentHashCode()` over at most the first 64 bytes of
|
||||
* the payload. Two packets from the same peer in the same millisecond that
|
||||
* agreed on that prefix collided, and a collision here is a *dropped
|
||||
* message* — the second packet is discarded as a duplicate and there is no
|
||||
* signal that it happened.
|
||||
*
|
||||
* `PacketIdUtil` is the identity the rest of the stack already uses for
|
||||
* exactly this question (gossip sync membership, message IDs in
|
||||
* `MessageHandler`), and iOS derives it the same way: the first 16 bytes of
|
||||
* SHA-256 over type, senderID, timestamp and the **whole** payload. Using
|
||||
* it here makes the security path agree with the sync path instead of
|
||||
* carrying a weaker private notion of "same packet".
|
||||
*
|
||||
* Peer scoping is kept: `PacketIdUtil` covers the packet's own senderID,
|
||||
* while this key is scoped by the peer the packet was received from, and
|
||||
* those are not the same thing for a relayed packet.
|
||||
*/
|
||||
private fun generateMessageID(packet: BitchatPacket, peerID: String): String {
|
||||
return when (MessageType.fromValue(packet.type)) {
|
||||
MessageType.FRAGMENT -> {
|
||||
// For fragments, include the payload hash to distinguish different fragments
|
||||
"${packet.timestamp}-$peerID-${packet.type}-${packet.payload.contentHashCode()}"
|
||||
}
|
||||
else -> {
|
||||
// For other messages, use a truncated payload hash
|
||||
val payloadHash = packet.payload.sliceArray(0 until minOf(64, packet.payload.size)).contentHashCode()
|
||||
"${packet.timestamp}-$peerID-$payloadHash"
|
||||
}
|
||||
}
|
||||
return "$peerID-${PacketIdUtil.computeIdHex(packet)}"
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user