mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-27 00:45:23 +00:00
Encrypt private media before BLE fragmentation (#1434)
Closes the last cleartext private-content path over BLE: private DM images/voice were sent as plaintext signed fileTransfer packets, TTL-relayed across the mesh, so every relay saw the full bytes. Now the complete BitchatFilePacket is encrypted as a single Noise AEAD message (inner type 0x20, matching Android) and the opaque ciphertext is fragmented. Adds an authenticated in-session capability proof (0x21 TLV: capabilities + Ed25519 key), TOFU-style downgrade pinning, a per-send consent dialog for the signed-cleartext fallback to legacy peers, and a cancellation/admission registry so cancel/delete cannot race a deferred cleartext send. Android wire constants (0x20 / 0x21 / capability bit 8) confirmed shipping. The 256-fragment preflight cap applies only to the directed fileTransfer migration fallback; encrypted media to capable peers uses the full receiver ceiling. Rebased over #1428/#1349: identity reads go through BLELocalIdentityStateStore; the session-bound authenticated signing-key check and the announce-path TOFU pin are kept as complementary checks. Full local suite green (1744+197 tests).
This commit is contained in:
@@ -36,6 +36,7 @@ final class MockTransport: Transport {
|
||||
private(set) var sentFavoriteNotifications: [(peerID: PeerID, isFavorite: Bool)] = []
|
||||
private(set) var sentBroadcastFiles: [(packet: BitchatFilePacket, transferID: String)] = []
|
||||
private(set) var sentPrivateFiles: [(packet: BitchatFilePacket, peerID: PeerID, transferID: String)] = []
|
||||
private(set) var sentPrivateFileLegacyAllowances: [Bool] = []
|
||||
private(set) var cancelledTransfers: [String] = []
|
||||
private(set) var sentVerifyChallenges: [(peerID: PeerID, noiseKeyHex: String, nonceA: Data)] = []
|
||||
private(set) var sentVerifyResponses: [(peerID: PeerID, noiseKeyHex: String, nonceA: Data)] = []
|
||||
@@ -58,6 +59,7 @@ final class MockTransport: Transport {
|
||||
var peerNicknames: [PeerID: String] = [:]
|
||||
var peerFingerprints: [PeerID: String] = [:]
|
||||
var peerNoiseStates: [PeerID: LazyHandshakeState] = [:]
|
||||
var privateMediaPolicies: [PeerID: PrivateMediaSendPolicy] = [:]
|
||||
private let mockKeychain = MockKeychain()
|
||||
|
||||
// MARK: - Transport Protocol Implementation
|
||||
@@ -186,6 +188,29 @@ final class MockTransport: Transport {
|
||||
|
||||
func sendFilePrivate(_ packet: BitchatFilePacket, to peerID: PeerID, transferId: String) {
|
||||
sentPrivateFiles.append((packet, peerID, transferId))
|
||||
sentPrivateFileLegacyAllowances.append(false)
|
||||
}
|
||||
|
||||
func sendFilePrivate(
|
||||
_ packet: BitchatFilePacket,
|
||||
to peerID: PeerID,
|
||||
transferId: String,
|
||||
allowLegacyFallback: Bool
|
||||
) {
|
||||
sentPrivateFiles.append((packet, peerID, transferId))
|
||||
sentPrivateFileLegacyAllowances.append(allowLegacyFallback)
|
||||
}
|
||||
|
||||
func privateMediaSendPolicy(to peerID: PeerID) -> PrivateMediaSendPolicy {
|
||||
privateMediaPolicies[peerID] ?? .encrypted
|
||||
}
|
||||
|
||||
func resolvePrivateMediaSendPolicy(
|
||||
to peerID: PeerID,
|
||||
completion: @escaping @MainActor (PrivateMediaSendPolicy) -> Void
|
||||
) {
|
||||
let policy = privateMediaPolicies[peerID] ?? .encrypted
|
||||
Task { @MainActor in completion(policy) }
|
||||
}
|
||||
|
||||
func cancelTransfer(_ transferId: String) {
|
||||
|
||||
Reference in New Issue
Block a user