我想验证一些下载的数据是否未修改。我的期望是,如果我修改原始数据,签名就会失败。虽然这在某些情况下是真的(data2
(,但在其他情况下却出乎意料地不起作用(data3
(。使用hashes/Digest
返回相同的结果。
import CryptoKit
let rootKey = P256.Signing.PrivateKey()
let publicKey = rootKey.publicKey
let data = Data(bytes: [0xA, 0xB, 0xC, 0xD], count: 4)
let digest = SHA256.hash(data: data)
let signature = try rootKey.signature(for: data)
let hashSignature = try rootKey.signature(for: digest)
// now alter the data
let data2 = Data(bytes: [0x0, 0xB, 0xC, 0xD], count: 4)
let data3 = Data(bytes: [0xA, 0xB, 0xC, 0xE], count: 4)
publicKey.isValidSignature(signature, for: data) // true, as expected
publicKey.isValidSignature(signature, for: data2) // false, as expected
publicKey.isValidSignature(signature, for: data3) // why is THIS true/valid?
publicKey.isValidSignature(hashSignature, for: SHA256.hash(data: data)) // true
publicKey.isValidSignature(hashSignature, for: SHA256.hash(data: data2)) // false
publicKey.isValidSignature(hashSignature, for: SHA256.hash(data: data3)) // true
为了简单起见,使用了CCD_ 4。这在(我的(CommonCrypto
/SecKey...
实现中也失败了。
好的,我发现了问题。您的代码是100%正确的。这个问题是由Swift中的一些相当有问题的错误引起的-我认为。更聪明的Swift专家-请纠正并启发我!
顺便说一句:我用的是Xcode Version 12.2 beta 3 (12B5035g)
数据不平等错误
func testDataInequality() {
func hexString(_ data: Data) -> String {
data.map { String(format: "%02hhx", $0) }.joined()
}
let data = Data(bytes: [0xA, 0xB, 0xC, 0xD], count: 4)
let data3 = Data(bytes: [0xA, 0xB, 0xC, 0xE], count: 4)
XCTAssertEqual(data.count, data3.count)
XCTAssertEqual(data.count, 4)
XCTAssertNotEqual(data, data3, "Expected 'data': (hexString(data)) to NOT equal: 'data3': (hexString(data3)), but it did.")
}
这个简单的单元测试失败了,但它不应该失败。意思是,data
和data3
显然不一样,因为我们看到了[0xA, 0xB, 0xC, 0xD] != [0xA, 0xB, 0xC, 0xE]
。我们使用XCTAssertNotEqual
断言它们不应该相等,但这个断言失败了,这意味着Swift相信它们是相等的。
我使用嵌套方法hexString
分别打印了data
和data3
的内容,我们在Xcode:中运行测试时收到了这个错误消息
XCTAssertNotEqual failed: ("4 bytes") is equal to ("4 bytes") - Expected 'data': 0a000000 to NOT equal: 'data3': 0a000000, but it did.
正如我们所看到的,data
和data3
都错误地采用了值:0a000000
,如[0xa, 0x0, 0x0, 0x0]
中所示。
更改为对数据使用不推荐使用的初始值设定项:
@available(swift 4.2)
@available(swift, deprecated: 5, message: "use `init(_:)` instead")
public init<S>(bytes elements: S) where S : Sequence, S.Element == UInt8
而不是";正确的";(不推荐使用(您正在使用的bytes:count
,我们得到了正确的行为。。。。
因此更改为:
let data = Data(bytes: [0xA, 0xB, 0xC, 0xD])
let data3 = Data(bytes: [0xA, 0xB, 0xC, 0xE])
然后重新运行测试,看看它是否有效。
此外,您可以添加以下断言:
XCTAssertEqual(hexString(data), "0a0b0c0d")
XCTAssertEqual(hexString(data3), "0a0b0c0e")
我会确保将此报告为Swift错误。
多亏了Sajjon的回答,我才弄清楚自己做错了什么。这似乎不是一个bug,而是一个简单的类型转换问题:
let bytes = [UInt8]([0xA, 0xB, 0xC, 0xD])
var foo = Data(bytes: bytes, count: 4)
print(hexString(foo)) // 0a0b0c0d
foo[1] <<= 1
print(hexString(foo)) // 0a160c0d
let bar = Data(bytes: [0xA, 0xB, 0xC, 0xD], count: 32)
print(hexString(bar)) // 0a000000000000000b000000000000000c000000000000000d00000000000000
我在原始数据中定义了bytes
,因此它们默认为Int
,也就是Int64
。提供4的数据长度只是省略了数据的前4个字节之后的所有内容。