From 9bac52051ac9dae47fe0686948cbab108b98f31a Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 14 Jan 2026 05:41:26 +0700 Subject: [PATCH] Revert Noise nonce size to 4 bytes for backward compatibility This change reverts the nonce size increase introduced in f41a390 ('BCH-01-010: Noise Protocol spec compliance improvements'). While 8-byte nonces are recommended by the Noise specification, increasing the size from 4 bytes broke wire compatibility with existing clients. This caused all encrypted DMs to fail between updated and non-updated clients. Changes: - Revert NONCE_SIZE_BYTES to 4. - Restore 4-byte nonce extraction logic in extractNonceFromCiphertextPayload. - Restore 4-byte nonce serialization in nonceToBytes. - Restore UInt32.max overflow check in encrypt. Note: Other improvements from BCH-01-010 (constant-time comparisons, safe arithmetic in replay window, sensitive data clearing) are preserved. --- bitchat/Noise/NoiseProtocol.swift | 39 +++++++++++++++++-------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/bitchat/Noise/NoiseProtocol.swift b/bitchat/Noise/NoiseProtocol.swift index b49baa0a..e099f648 100644 --- a/bitchat/Noise/NoiseProtocol.swift +++ b/bitchat/Noise/NoiseProtocol.swift @@ -129,9 +129,7 @@ struct NoiseProtocolName { /// - Warning: Nonce reuse would be catastrophic for security final class NoiseCipherState { // Constants for replay protection - // BCH-01-010: Use full 8-byte nonces per Noise Protocol specification - // This provides 2^64 nonce space instead of limited 2^32 - private static let NONCE_SIZE_BYTES = 8 + private static let NONCE_SIZE_BYTES = 4 private static let REPLAY_WINDOW_SIZE = 1024 private static let REPLAY_WINDOW_BYTES = REPLAY_WINDOW_SIZE / 8 // 128 bytes private static let HIGH_NONCE_WARNING_THRESHOLD: UInt64 = 1_000_000_000 @@ -224,29 +222,37 @@ final class NoiseCipherState { /// Extract nonce from combined payload /// Returns tuple of (nonce, ciphertext) or nil if invalid - /// BCH-01-010: Updated to extract full 8-byte nonce per Noise spec private func extractNonceFromCiphertextPayload(_ combinedPayload: Data) throws -> (nonce: UInt64, ciphertext: Data)? { guard combinedPayload.count >= Self.NONCE_SIZE_BYTES else { return nil } - - // Extract 8-byte nonce (big-endian) + + // Extract 4-byte nonce (big-endian) let nonceData = combinedPayload.prefix(Self.NONCE_SIZE_BYTES) let extractedNonce = nonceData.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) -> UInt64 in - bytes.load(as: UInt64.self).bigEndian + let byteArray = bytes.bindMemory(to: UInt8.self) + var result: UInt64 = 0 + for i in 0.. Data { - var nonceValue = nonce.bigEndian - return Data(bytes: &nonceValue, count: Self.NONCE_SIZE_BYTES) + var bytes = Data(count: Self.NONCE_SIZE_BYTES) + withUnsafeBytes(of: nonce.bigEndian) { ptr in + // Copy only the last 4 bytes from the 8-byte UInt64 + let sourceBytes = ptr.bindMemory(to: UInt8.self) + bytes.replaceSubrange(0.. Data { @@ -256,10 +262,9 @@ final class NoiseCipherState { // Debug logging for nonce tracking let currentNonce = nonce - - // BCH-01-010: With 8-byte nonces, we have full 2^64 nonce space - // Check against UInt64.max - 1 to prevent overflow - guard nonce < UInt64.max else { + + // Check if nonce exceeds 4-byte limit (UInt32 max value) + guard nonce <= UInt64(UInt32.max) - 1 else { throw NoiseError.nonceExceeded }