mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 03:25:19 +00:00
Merge pull request #957 from permissionlesstech/fix/noise-protocol-compatibility
This commit is contained in:
@@ -129,9 +129,7 @@ struct NoiseProtocolName {
|
|||||||
/// - Warning: Nonce reuse would be catastrophic for security
|
/// - Warning: Nonce reuse would be catastrophic for security
|
||||||
final class NoiseCipherState {
|
final class NoiseCipherState {
|
||||||
// Constants for replay protection
|
// Constants for replay protection
|
||||||
// BCH-01-010: Use full 8-byte nonces per Noise Protocol specification
|
private static let NONCE_SIZE_BYTES = 4
|
||||||
// This provides 2^64 nonce space instead of limited 2^32
|
|
||||||
private static let NONCE_SIZE_BYTES = 8
|
|
||||||
private static let REPLAY_WINDOW_SIZE = 1024
|
private static let REPLAY_WINDOW_SIZE = 1024
|
||||||
private static let REPLAY_WINDOW_BYTES = REPLAY_WINDOW_SIZE / 8 // 128 bytes
|
private static let REPLAY_WINDOW_BYTES = REPLAY_WINDOW_SIZE / 8 // 128 bytes
|
||||||
private static let HIGH_NONCE_WARNING_THRESHOLD: UInt64 = 1_000_000_000
|
private static let HIGH_NONCE_WARNING_THRESHOLD: UInt64 = 1_000_000_000
|
||||||
@@ -224,16 +222,20 @@ final class NoiseCipherState {
|
|||||||
|
|
||||||
/// Extract nonce from combined payload <nonce><ciphertext>
|
/// Extract nonce from combined payload <nonce><ciphertext>
|
||||||
/// Returns tuple of (nonce, ciphertext) or nil if invalid
|
/// 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)? {
|
private func extractNonceFromCiphertextPayload(_ combinedPayload: Data) throws -> (nonce: UInt64, ciphertext: Data)? {
|
||||||
guard combinedPayload.count >= Self.NONCE_SIZE_BYTES else {
|
guard combinedPayload.count >= Self.NONCE_SIZE_BYTES else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract 8-byte nonce (big-endian)
|
// Extract 4-byte nonce (big-endian)
|
||||||
let nonceData = combinedPayload.prefix(Self.NONCE_SIZE_BYTES)
|
let nonceData = combinedPayload.prefix(Self.NONCE_SIZE_BYTES)
|
||||||
let extractedNonce = nonceData.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) -> UInt64 in
|
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..<Self.NONCE_SIZE_BYTES {
|
||||||
|
result = (result << 8) | UInt64(byteArray[i])
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract ciphertext (remaining bytes)
|
// Extract ciphertext (remaining bytes)
|
||||||
@@ -242,11 +244,15 @@ final class NoiseCipherState {
|
|||||||
return (nonce: extractedNonce, ciphertext: Data(ciphertext))
|
return (nonce: extractedNonce, ciphertext: Data(ciphertext))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert nonce to 8-byte array (big-endian)
|
/// Convert nonce to 4-byte array (big-endian)
|
||||||
/// BCH-01-010: Write full 8-byte nonce per Noise spec
|
|
||||||
private func nonceToBytes(_ nonce: UInt64) -> Data {
|
private func nonceToBytes(_ nonce: UInt64) -> Data {
|
||||||
var nonceValue = nonce.bigEndian
|
var bytes = Data(count: Self.NONCE_SIZE_BYTES)
|
||||||
return Data(bytes: &nonceValue, 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..<Self.NONCE_SIZE_BYTES, with: sourceBytes.suffix(Self.NONCE_SIZE_BYTES))
|
||||||
|
}
|
||||||
|
return bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
func encrypt(plaintext: Data, associatedData: Data = Data()) throws -> Data {
|
func encrypt(plaintext: Data, associatedData: Data = Data()) throws -> Data {
|
||||||
@@ -257,9 +263,8 @@ final class NoiseCipherState {
|
|||||||
// Debug logging for nonce tracking
|
// Debug logging for nonce tracking
|
||||||
let currentNonce = nonce
|
let currentNonce = nonce
|
||||||
|
|
||||||
// BCH-01-010: With 8-byte nonces, we have full 2^64 nonce space
|
// Check if nonce exceeds 4-byte limit (UInt32 max value)
|
||||||
// Check against UInt64.max - 1 to prevent overflow
|
guard nonce <= UInt64(UInt32.max) - 1 else {
|
||||||
guard nonce < UInt64.max else {
|
|
||||||
throw NoiseError.nonceExceeded
|
throw NoiseError.nonceExceeded
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user