You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Data.hash currently hashes the first 80 bytes of data, which means that all data values of the same size whose first 80 bytes are the same hash equal. Hashing only the first 80 bytes opens an opportunity of DOS attacks when the attacker provides a data key of the same size whose first 80 bytes are the same.
Example app:
import Foundation
let keySize = 88
let N = 100_000
var dictionary: [Data: Int] = [:]
var data0 = Data([UInt8](repeating: 0, count: keySize - 8))
func makeData(data0: Data, value: Int) -> Data {
let a = (value >> 0) & 0xFF
let b = (value >> 8) & 0xFF
let c = (value >> 16) & 0xFF
let d = (value >> 24) & 0xFF
var data = data0
data.append(UInt8(a))
data.append(UInt8(b))
data.append(UInt8(c))
data.append(UInt8(d))
return data
}
print("start, N = \(N), keySize = \(keySize)")
let keys = (0 ..< N).map {
makeData(data0: data0, value: $0)
}
var startTime = Date()
for (i, key) in keys.enumerated() {
dictionary[key] = i
}
var elapsedTime = Date().timeIntervalSince(startTime)
print("initializing dictionary took \(elapsedTime) seconds")
var key = makeData(data0: data0, value: N)
startTime = Date()
dictionary[key] = N
elapsedTime = Date().timeIntervalSince(startTime)
print("dictionary insert took: \(elapsedTime) seconds")
key = makeData(data0: data0, value: N/2)
startTime = Date()
let result = dictionary[key]!
elapsedTime = Date().timeIntervalSince(startTime)
print("dictionary lookup (\(result)) took: \(elapsedTime) seconds")
For N = 100K and keySize = 88 this gives:
start, N = 100_000 and keySize = 88
initializing dictionary took 120 seconds
dictionary insert took: 0.0025 seconds
dictionary lookup (50000) took: 0.00195 seconds
For comparison for the same N and keySize = 80 this gives a sharply different result:
start, N = 100_000, keySize = 80
initializing dictionary took 0.054 seconds (2000+ times faster)
dictionary insert took: 0.0 seconds (many times faster)
dictionary lookup (50000) took: 0.0 seconds (many times faster)
This is the relevant portion of the code in the current (at the time of writing) main branch:
Data.hash currently hashes the first 80 bytes of data, which means that all data values of the same size whose first 80 bytes are the same hash equal. Hashing only the first 80 bytes opens an opportunity of DOS attacks when the attacker provides a data key of the same size whose first 80 bytes are the same.
Example app:
For N = 100K and keySize = 88 this gives:
For comparison for the same N and keySize = 80 this gives a sharply different result:
This is the relevant portion of the code in the current (at the time of writing) main branch:
https://github.com/apple/swift-corelibs-foundation/blob/dbca8c7ddcfd19f7f6f6e1b60fd3ee3f748e263c/Darwin/Foundation-swiftoverlay/Data.swift#L1082-L1086
https://github.com/apple/swift-corelibs-foundation/blob/dbca8c7ddcfd19f7f6f6e1b60fd3ee3f748e263c/Darwin/Foundation-swiftoverlay/Data.swift#L1286-L1290
The text was updated successfully, but these errors were encountered: