diff --git a/Sources/CryptoExtras/AES/AES_CBC.swift b/Sources/CryptoExtras/AES/AES_CBC.swift index f94910bf..3ecd035e 100644 --- a/Sources/CryptoExtras/AES/AES_CBC.swift +++ b/Sources/CryptoExtras/AES/AES_CBC.swift @@ -124,6 +124,10 @@ extension AES { throw CryptoKitError.incorrectKeySize } + guard ciphertext.count % AES._CBC.blockSize == 0 else { + throw CryptoKitError.incorrectParameterSize + } + var plaintext = Data() plaintext.reserveCapacity(ciphertext.count) diff --git a/Tests/CryptoExtrasTests/AES_CBCTests.swift b/Tests/CryptoExtrasTests/AES_CBCTests.swift index 11fa7ec4..bc903ce7 100644 --- a/Tests/CryptoExtrasTests/AES_CBCTests.swift +++ b/Tests/CryptoExtrasTests/AES_CBCTests.swift @@ -163,6 +163,23 @@ final class CBCTests: XCTestCase { } } + func testDecryptRejectsNonBlockAlignedCiphertext() throws { + let key = SymmetricKey(data: try Data(hexString: "b6fc08df9b778d11850356b8bfc9561a")) + let iv = try AES._CBC.IV(ivBytes: Array(hexString: "00000000000000000000000000000000")) + + // 17 bytes — not a multiple of the 16-byte block size. + let nonAligned = try Data(hexString: "00112233445566778899aabbccddeeff00") + + for noPadding in [false, true] { + XCTAssertThrowsError(try AES._CBC.decrypt(nonAligned, using: key, iv: iv, noPadding: noPadding)) { error in + guard let error = error as? CryptoKitError, case .incorrectParameterSize = error else { + XCTFail("Unexpected error for noPadding=\(noPadding): \(error)") + return + } + } + } + } + func testToDataConversion() throws { let randomBytes = (0..<16).map { _ in UInt8.random(in: UInt8.min...UInt8.max) } let dataIn = Data(randomBytes)