mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 02:45:20 +00:00
Implement Noise XX Handshake Protocol for Direct Messages (#180)
* noise * works? * noise * temporary * better * wip: use subnet * better * barely working * werk * subnet * fix peer ID * 8 byte peer ID * wip noise * wip fixes for noise * std lib for noise * noise handshake one step further * buffers * use fork * fix imports * simplify counter * remove trash * hashing * no prologue * nice * wip, use noise encryption * peer ID hex * simplify session manager * heavy logging * use singleton * Fix Noise session race condition with elegant per-peer actor serialization - Use Kotlin coroutine actors for per-peer packet processing - Each peer gets dedicated actor that processes packets sequentially - Eliminates race conditions in session management without complex locking - Single surgical change in PacketProcessor - minimal, maintainable - Leverages Kotlin's native concurrency primitives * decrypt correctly * iniator works now * clean code and fix signature to null * better * no signature in private message * small fixes * refactor ack * refactor but untested * messages working * wip ack * wip fix ack * more logging * pending tracker * keep pending connections on errors * less logging * refactor model * refactor frombinarydata * idendityannouncement refactor and update to new binary protocol * fix keys * refix keys * dms work * revert to mainnet * do not change bluetooth adapter name * keep code but uncomment * clean up comments * cleanup comments
This commit is contained in:
@@ -7,21 +7,35 @@ import java.nio.ByteOrder
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Message types - exact same as iOS version
|
||||
* Message types - exact same as iOS version with Noise Protocol support
|
||||
*/
|
||||
enum class MessageType(val value: UByte) {
|
||||
ANNOUNCE(0x01u),
|
||||
KEY_EXCHANGE(0x02u),
|
||||
// 0x02 was legacy keyExchange - removed
|
||||
LEAVE(0x03u),
|
||||
MESSAGE(0x04u),
|
||||
MESSAGE(0x04u), // All user messages (private and broadcast)
|
||||
FRAGMENT_START(0x05u),
|
||||
FRAGMENT_CONTINUE(0x06u),
|
||||
FRAGMENT_END(0x07u),
|
||||
CHANNEL_ANNOUNCE(0x08u),
|
||||
CHANNEL_RETENTION(0x09u),
|
||||
DELIVERY_ACK(0x0Au),
|
||||
DELIVERY_STATUS_REQUEST(0x0Bu),
|
||||
READ_RECEIPT(0x0Cu);
|
||||
CHANNEL_ANNOUNCE(0x08u), // Announce password-protected channel status
|
||||
CHANNEL_RETENTION(0x09u), // Announce channel retention status
|
||||
DELIVERY_ACK(0x0Au), // Acknowledge message received
|
||||
DELIVERY_STATUS_REQUEST(0x0Bu), // Request delivery status update
|
||||
READ_RECEIPT(0x0Cu), // Message has been read/viewed
|
||||
|
||||
// Noise Protocol messages - exact same as iOS
|
||||
NOISE_HANDSHAKE_INIT(0x10u), // Noise handshake initiation
|
||||
NOISE_HANDSHAKE_RESP(0x11u), // Noise handshake response
|
||||
NOISE_ENCRYPTED(0x12u), // Noise encrypted transport message
|
||||
NOISE_IDENTITY_ANNOUNCE(0x13u), // Announce static public key for discovery
|
||||
CHANNEL_KEY_VERIFY_REQUEST(0x14u), // Request key verification for a channel
|
||||
CHANNEL_KEY_VERIFY_RESPONSE(0x15u), // Response to key verification request
|
||||
CHANNEL_PASSWORD_UPDATE(0x16u), // Distribute new password to channel members
|
||||
CHANNEL_METADATA(0x17u), // Announce channel creator and metadata
|
||||
|
||||
// Protocol version negotiation
|
||||
VERSION_HELLO(0x20u), // Initial version announcement
|
||||
VERSION_ACK(0x21u); // Version acknowledgment
|
||||
|
||||
companion object {
|
||||
fun fromValue(value: UByte): MessageType? {
|
||||
@@ -74,7 +88,7 @@ data class BitchatPacket(
|
||||
) : this(
|
||||
version = 1u,
|
||||
type = type,
|
||||
senderID = senderID.toByteArray(),
|
||||
senderID = hexStringToByteArray(senderID),
|
||||
recipientID = null,
|
||||
timestamp = (System.currentTimeMillis()).toULong(),
|
||||
payload = payload,
|
||||
@@ -90,6 +104,27 @@ data class BitchatPacket(
|
||||
fun fromBinaryData(data: ByteArray): BitchatPacket? {
|
||||
return BinaryProtocol.decode(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hex string peer ID to binary data (8 bytes) - exactly same as iOS
|
||||
*/
|
||||
private fun hexStringToByteArray(hexString: String): ByteArray {
|
||||
val result = ByteArray(8) { 0 } // Initialize with zeros, exactly 8 bytes
|
||||
var tempID = hexString
|
||||
var index = 0
|
||||
|
||||
while (tempID.length >= 2 && index < 8) {
|
||||
val hexByte = tempID.substring(0, 2)
|
||||
val byte = hexByte.toIntOrNull(16)?.toByte()
|
||||
if (byte != null) {
|
||||
result[index] = byte
|
||||
}
|
||||
tempID = tempID.substring(2)
|
||||
index++
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@@ -219,7 +254,12 @@ object BinaryProtocol {
|
||||
val result = ByteArray(buffer.position())
|
||||
buffer.rewind()
|
||||
buffer.get(result)
|
||||
return result
|
||||
|
||||
// Apply padding to standard block sizes for traffic analysis resistance
|
||||
val optimalSize = MessagePadding.optimalBlockSize(result.size)
|
||||
val paddedData = MessagePadding.pad(result, optimalSize)
|
||||
|
||||
return paddedData
|
||||
|
||||
} catch (e: Exception) {
|
||||
return null
|
||||
@@ -228,9 +268,12 @@ object BinaryProtocol {
|
||||
|
||||
fun decode(data: ByteArray): BitchatPacket? {
|
||||
try {
|
||||
if (data.size < HEADER_SIZE + SENDER_ID_SIZE) return null
|
||||
// Remove padding first - exactly same as iOS
|
||||
val unpaddedData = MessagePadding.unpad(data)
|
||||
|
||||
val buffer = ByteBuffer.wrap(data).apply { order(ByteOrder.BIG_ENDIAN) }
|
||||
if (unpaddedData.size < HEADER_SIZE + SENDER_ID_SIZE) return null
|
||||
|
||||
val buffer = ByteBuffer.wrap(unpaddedData).apply { order(ByteOrder.BIG_ENDIAN) }
|
||||
|
||||
// Header
|
||||
val version = buffer.get().toUByte()
|
||||
@@ -256,7 +299,7 @@ object BinaryProtocol {
|
||||
if (hasRecipient) expectedSize += RECIPIENT_ID_SIZE
|
||||
if (hasSignature) expectedSize += SIGNATURE_SIZE
|
||||
|
||||
if (data.size < expectedSize) return null
|
||||
if (unpaddedData.size < expectedSize) return null
|
||||
|
||||
// SenderID
|
||||
val senderID = ByteArray(SENDER_ID_SIZE)
|
||||
@@ -310,25 +353,3 @@ object BinaryProtocol {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compression utilities - temporarily disabled for initial build
|
||||
*/
|
||||
object CompressionUtil {
|
||||
private const val COMPRESSION_THRESHOLD = 100 // bytes
|
||||
|
||||
fun shouldCompress(data: ByteArray): Boolean {
|
||||
// Temporarily disabled compression
|
||||
return false
|
||||
}
|
||||
|
||||
fun compress(data: ByteArray): ByteArray? {
|
||||
// Temporarily disabled compression
|
||||
return null
|
||||
}
|
||||
|
||||
fun decompress(compressedData: ByteArray, originalSize: Int): ByteArray? {
|
||||
// Temporarily disabled compression
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user