Skip to content

Commit 5e655b8

Browse files
committed
Fixed decryption of AES-GCM ciphertexts with custom tag length
1 parent eea72d2 commit 5e655b8

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

Sources/CryptoSwift/BlockDecryptor.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,17 @@ public class BlockDecryptor: Cryptor, Updatable {
4646
// Processing in a block-size manner. It's good for block modes, but bad for stream modes.
4747
for var chunk in accumulatedWithoutSuffix.batched(by: blockSize) {
4848
if isLast || (accumulatedWithoutSuffix.count - processedBytesCount) >= blockSize {
49-
50-
if isLast, var finalizingWorker = worker as? FinalizingDecryptModeWorker {
49+
let isLastChunk = processedBytesCount + chunk.count == accumulatedWithoutSuffix.count
50+
51+
if isLast, isLastChunk, var finalizingWorker = worker as? FinalizingDecryptModeWorker {
5152
chunk = try finalizingWorker.willDecryptLast(bytes: chunk + accumulated.suffix(worker.additionalBufferSize)) // tag size
5253
}
5354

5455
if !chunk.isEmpty {
5556
plaintext += worker.decrypt(block: chunk)
5657
}
5758

58-
if var finalizingWorker = worker as? FinalizingDecryptModeWorker, isLast == true {
59+
if isLast, isLastChunk, var finalizingWorker = worker as? FinalizingDecryptModeWorker {
5960
plaintext = Array(try finalizingWorker.didDecryptLast(bytes: plaintext.slice))
6061
}
6162

Tests/Tests/AESTests.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,43 @@ extension AESTests {
567567
let decrypted = decrypt(encrypted)
568568
XCTAssertEqual(decrypted, plaintext)
569569
}
570+
571+
func testAESGCMTagLengthCombined2() {
572+
let key = Data(base64Encoded: "X2V2b2x2ZV91c2FnZV9zZXJ2ZXJfZW5jcnlwdGlvbl8=")!.bytes
573+
let plaintext = Array<UInt8>(hex: "0x0000000000000000000000000000000000000000")
574+
let iv = Array<UInt8>(hex: "0x000000000000")
575+
576+
let gcm = GCM(iv: iv, tagLength: 12, mode: .combined)
577+
let aes = try! AES(key: key, blockMode: gcm, padding: .noPadding)
578+
let encrypted = try! aes.encrypt(plaintext)
579+
580+
// decrypt
581+
func decrypt(_ encrypted: Array<UInt8>) -> Array<UInt8> {
582+
let decGCM = GCM(iv: iv, authenticationTag: gcm.authenticationTag!, mode: .combined)
583+
let aes = try! AES(key: key, blockMode: decGCM, padding: .noPadding)
584+
return try! aes.decrypt(encrypted)
585+
}
586+
587+
let decrypted = decrypt(encrypted)
588+
XCTAssertEqual(decrypted, plaintext)
589+
}
590+
591+
func testAESGCMTagLengthCombined3() {
592+
let data = Data(base64Encoded: "jkVoOail9ZLbGBX/glT5S7Sql7OcH9Fr3sGt0liSBPKaykJ4+Gc=")!.bytes
593+
let key = Data(base64Encoded: "X2V2b2x2ZV91c2FnZV9zZXJ2ZXJfZW5jcnlwdGlvbl8=")!.bytes
594+
let plaintext = Data(base64Encoded: "fg/LQuxydo5JwrbqBkEAOlweBxs=")!.bytes
595+
596+
let ciphertextLength = 32
597+
let encrypted = data.prefix(upTo: ciphertextLength)
598+
let iv = Array(data.dropFirst(ciphertextLength))
599+
600+
// decrypt
601+
let gcm = GCM(iv: iv, tagLength: 12, mode: .combined)
602+
let aes = try! AES(key: key, blockMode: gcm, padding: .noPadding)
603+
let decrypted = try! aes.decrypt(encrypted)
604+
605+
XCTAssertEqual(decrypted, plaintext)
606+
}
570607

571608
func testAESGCMTestCaseIrregularCombined1() {
572609
// echo -n "0123456789010123456789012345" | openssl enc -aes-128-gcm -K feffe9928665731c6d6a8f9467308308 -iv cafebabefacedbaddecaf888 -nopad -nosalt

0 commit comments

Comments
 (0)