测试 CryptoKit 的数据验证

Testing CryptoKit's data validation

我想验证一些下载的数据未被修改。我的期望是,如果我修改原始数据,签名将失败。虽然这在某些情况下是正确的 (data2),但令人惊讶的是在其他情况下却不起作用 (data3)。使用散列/Digest returns 相同的结果。

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

为简单起见,使用 CryptoKit。这在(我的)CommonCrypto/SecKey... 实现中也失败了。

好的,我发现了问题。您的代码 100% 正确。这个问题是由 Swift 中一些相当有问题的错误引起的 - 我 认为 。聪明的Swift高手请指正赐教!

顺便说一句:我正在使用 Xcode Version 12.2 beta 3 (12B5035g)

数据不平等错误

func testDataInequality() {
    func hexString(_ data: Data) -> String {
        data.map { String(format: "%02hhx", [=10=]) }.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.")
}

这个简单的单元测试失败了,但应该不会失败。意思是,datadata3 显然不一样,因为我们看到 [0xA, 0xB, 0xC, 0xD] != [0xA, 0xB, 0xC, 0xE]。我们使用 XCTAssertNotEqual 断言它们不应该相等,但是这个断言失败了,这意味着 Swift 相信它们是相等的。

我使用嵌套方法hexString分别打印了datadata3的内容,我们在运行测试[=56]时得到这个错误信息=]:

XCTAssertNotEqual failed: ("4 bytes") is equal to ("4 bytes") - Expected 'data': 0a000000 to NOT equal: 'data3':  0a000000, but it did.

我们可以看到 datadata3 都错误地取值: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 错误。

多亏了,我才能够弄清楚我做错了什么。这似乎不是一个错误,而是一个简单的类型转换问题:

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 a.k.a。 Int64。提供 4 的数据长度会简单地忽略前 4 个字节数据之后的所有内容。