mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-11-01 07:51:15 +00:00
fix: stop fragmentation eating a signature byte off an unpadded frame
createFragments encoded the packet with padding on and then called MessagePadding.unpad to strip it again. Across most of the fragmentation range no padding was ever applied: pad() declines a request needing more than 255 bytes, and optimalBlockSize() returns the input size unchanged above 2048, so frames of 513-768, 1009-1792 and >=2033 bytes come back untouched. An unpadded frame ends with the last byte of the signature, which is uniformly random. unpad reads it as a PKCS#7 pad length, and a value of 0x01 satisfies the tail check trivially, so a real signature byte is stripped. Every receiver reassembles the fragments faithfully and then fails the size check in decodeCore, which is why the message dies on all of them at once with nothing in the sender's log. Ask the encoder for the unpadded frame instead. Byte-identical for frames that really were padded, so nothing changes on the wire.
This commit is contained in:
parent
4f828b5643
commit
ab8c06613d
@ -3,7 +3,6 @@ package com.bitchat.android.mesh
|
||||
import android.util.Log
|
||||
import com.bitchat.android.protocol.BitchatPacket
|
||||
import com.bitchat.android.protocol.MessageType
|
||||
import com.bitchat.android.protocol.MessagePadding
|
||||
import com.bitchat.android.model.FragmentPayload
|
||||
import kotlinx.coroutines.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
@ -66,20 +65,19 @@ class FragmentManager {
|
||||
Log.w(TAG, "Rejecting invalid outbound fragment limit: $maxFragments")
|
||||
return emptyList()
|
||||
}
|
||||
val encoded = packet.toBinaryData()
|
||||
if (encoded == null) {
|
||||
// Fragment the unpadded frame; each fragment will be encoded (and padded) independently - iOS fix.
|
||||
// Ask the encoder to skip padding rather than un-padding afterwards:
|
||||
// pad() declines a request needing more than 255 bytes and
|
||||
// optimalBlockSize() returns the input size above 2048, so frames of
|
||||
// 513-768, 1009-1792 and >=2033 bytes are never padded. Those end
|
||||
// with the last byte of the signature, and unpad() reads a value of
|
||||
// 0x01 as a one-byte pad and strips a real signature byte.
|
||||
val fullData = packet.toBinaryData(padding = false)
|
||||
if (fullData == null) {
|
||||
Log.e(TAG, "Failed to encode packet to binary data")
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
// Fragment the unpadded frame; each fragment will be encoded (and padded) independently - iOS fix
|
||||
val fullData = try {
|
||||
MessagePadding.unpad(encoded)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to unpad data: ${e.message}", e)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
// iOS logic: if data.count > 512 && packet.type != MessageType.fragment.rawValue
|
||||
if (fullData.size <= FRAGMENT_SIZE_THRESHOLD) {
|
||||
return listOf(packet) // No fragmentation needed
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user