diff --git a/Sources/CryptoSwift/ChaCha20.swift b/Sources/CryptoSwift/ChaCha20.swift index 4243eaa4..45ec1184 100644 --- a/Sources/CryptoSwift/ChaCha20.swift +++ b/Sources/CryptoSwift/ChaCha20.swift @@ -28,8 +28,8 @@ public final class ChaCha20: BlockCipher { fileprivate let key: Key fileprivate var counter: Array - public init(key: Array, iv nonce: Array) throws { - precondition(nonce.count == 12 || nonce.count == 8) + public init(key: Array, counter: Array = [0, 0, 0, 0], iv nonce: Array) throws { + precondition(counter.count == 4 && (nonce.count == 12 || nonce.count == 8)) if key.count != 32 { throw Error.invalidKeyOrInitializationVector @@ -39,9 +39,11 @@ public final class ChaCha20: BlockCipher { self.keySize = self.key.count if nonce.count == 8 { - self.counter = [0, 0, 0, 0, 0, 0, 0, 0] + nonce + self.counter = counter + [0, 0, 0, 0] + nonce + } else if nonce.count == 12 { + self.counter = counter + nonce } else { - self.counter = [0, 0, 0, 0] + nonce + throw Error.invalidKeyOrInitializationVector } assert(self.counter.count == 16) diff --git a/Tests/CryptoSwiftTests/ChaCha20Tests.swift b/Tests/CryptoSwiftTests/ChaCha20Tests.swift index cdad6e60..ce976162 100644 --- a/Tests/CryptoSwiftTests/ChaCha20Tests.swift +++ b/Tests/CryptoSwiftTests/ChaCha20Tests.swift @@ -106,6 +106,36 @@ final class ChaCha20Tests: XCTestCase { XCTFail() } } + + /// Test Vector - https://datatracker.ietf.org/doc/html/rfc9001#name-chacha20-poly1305-short-hea + func testChaCha20ExplicitCounterV1() { + let hpKey = Array(hex: "0x25a282b9e82f06f21f488917a4fc8f1b73573685608597d0efcb076b0ab7a7a4") + /// Sample = 0x5e5cd55c41f69080575d7999c25a5bfb + let counter = Array(hex: "0x5e5cd55c") + let iv = Array(hex: "0x41f69080575d7999c25a5bfb") + + do { + let mask = try CryptoSwift.ChaCha20(key: hpKey, counter: counter, iv: iv).encrypt(Array(repeating: 0, count: 5)) + XCTAssertEqual(mask, Array(hex: "0xaefefe7d03")) + } catch { + XCTFail("\(error)") + } + } + + /// Test Vector - https://www.ietf.org/archive/id/draft-ietf-quic-v2-10.html#name-chacha20-poly1305-short-head + func testChaCha20ExplicitCounterV2() { + let hpKey = Array(hex: "0xd659760d2ba434a226fd37b35c69e2da8211d10c4f12538787d65645d5d1b8e2") + /// Sample = 0xe7b6b932bc27d786f4bc2bb20f2162ba + let counter = Array(hex: "0xe7b6b932") + let iv = Array(hex: "0xbc27d786f4bc2bb20f2162ba") + + do { + let mask = try CryptoSwift.ChaCha20(key: hpKey, counter: counter, iv: iv).encrypt(Array(repeating: 0, count: 5)) + XCTAssertEqual(mask, Array(hex: "0x97580e32bf")) + } catch { + XCTFail("\(error)") + } + } } extension ChaCha20Tests { @@ -114,7 +144,9 @@ extension ChaCha20Tests { ("testChaCha20", testChaCha20), ("testCore", testCore), ("testVector1Py", testVector1Py), - ("testChaCha20EncryptPartial", testChaCha20EncryptPartial) + ("testChaCha20EncryptPartial", testChaCha20EncryptPartial), + ("testChaCha20ExplicitCounterV1", testChaCha20ExplicitCounterV1), + ("testChaCha20ExplicitCounterV2", testChaCha20ExplicitCounterV2) ] return tests