Encrypt private media before fragmentation

This commit is contained in:
jack
2026-07-26 02:08:56 +02:00
committed by jack
parent 974510ad9e
commit a31cd80027
25 changed files with 892 additions and 137 deletions
+37 -3
View File
@@ -740,11 +740,38 @@ final class NoiseEncryptionService {
return try sessionManager.encrypt(data, for: peerID)
}
/// Encrypts a finalized private-media packet. Ordinary Noise application
/// messages retain the 64 KiB ceiling; this purpose-specific path permits
/// the bounded `BitchatFilePacket` envelope and refuses every other typed
/// payload so the larger allocation budget cannot become a generic bypass.
func encryptPrivateFilePayload(_ data: Data, for peerID: PeerID) throws -> Data {
guard data.first == NoisePayloadType.privateFile.rawValue,
NoiseSecurityValidator.validatePrivateFileMessageSize(data) else {
throw NoiseSecurityError.messageTooLarge
}
guard rateLimiter.allowMessage(from: peerID) else {
throw NoiseSecurityError.rateLimitExceeded
}
guard hasEstablishedSession(with: peerID) else {
onHandshakeRequired?(peerID)
throw NoiseEncryptionError.handshakeRequired
}
// `maxPrivateFilePlaintextSize` already subtracts the cipher's fixed
// nonce/tag overhead, so the result is bounded without a second copy.
return try sessionManager.encrypt(data, for: peerID)
}
/// Decrypt data from a specific peer
func decrypt(_ data: Data, from peerID: PeerID) throws -> Data {
// Validate message size
guard NoiseSecurityValidator.validateMessageSize(data) else {
// Standard transport ciphertext has 20 bytes of nonce/tag overhead.
// A larger candidate is admitted only up to the framed-file ceiling;
// after authenticated decryption it must prove it is `.privateFile`.
let isStandardCiphertext = NoiseSecurityValidator.validateCiphertextSize(data)
guard isStandardCiphertext || NoiseSecurityValidator.validatePrivateFileCiphertextSize(data) else {
throw NoiseSecurityError.messageTooLarge
}
@@ -758,7 +785,14 @@ final class NoiseEncryptionService {
throw NoiseEncryptionError.sessionNotEstablished
}
return try sessionManager.decrypt(data, from: peerID)
let decrypted = try sessionManager.decrypt(data, from: peerID)
if !isStandardCiphertext {
guard decrypted.first == NoisePayloadType.privateFile.rawValue,
NoiseSecurityValidator.validatePrivateFileMessageSize(decrypted) else {
throw NoiseSecurityError.messageTooLarge
}
}
return decrypted
}
// MARK: - Peer Management