Pārlūkot izejas kodu

CCM read tag from the combined ciphertext

Marcin Krzyzanowski 6 gadi atpakaļ
vecāks
revīzija
55906316cb

+ 7 - 1
Sources/CryptoSwift/BlockMode/CCM.swift

@@ -67,6 +67,8 @@ class CCMModeWorker: StreamModeWorker, SeekableModeWorker, CounterModeWorker, Fi
     private let nonce: Array<UInt8>
     private var last_y: ArraySlice<UInt8> = []
     private var keystream: Array<UInt8> = []
+    // Known Tag used to validate during decryption
+    private var expectedTag: Array<UInt8>?
 
     public enum Error: Swift.Error {
         case invalidParameter
@@ -167,7 +169,11 @@ class CCMModeWorker: StreamModeWorker, SeekableModeWorker, CounterModeWorker, Fi
     }
 
     func willDecryptLast(bytes ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
-        return ciphertext
+        // get tag of additionalBufferSize size
+        // `ciphertext` contains at least additionalBufferSize bytes
+        // overwrite expectedTag property used later for verification
+        self.expectedTag = Array(ciphertext.suffix(tagLength))
+        return ciphertext[ciphertext.startIndex..<ciphertext.endIndex.advanced(by: -Swift.min(tagLength,ciphertext.count))]
     }
 
     func didDecryptLast(bytes plaintext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {

+ 16 - 17
Sources/CryptoSwift/BlockMode/GCM.swift

@@ -152,21 +152,6 @@ final class GCMModeWorker: BlockModeWorker, FinalizingEncryptModeWorker, Finaliz
         return Array(ciphertext)
     }
 
-    func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
-        counter = incrementCounter(counter)
-
-        // update ghash incrementally
-        gf.ghashUpdate(block: Array(ciphertext))
-
-        guard let ekN = cipherOperation(counter.bytes.slice) else {
-            return Array(ciphertext)
-        }
-
-        // ciphertext block ^ ek1
-        let plaintext = xor(ciphertext, ekN) as Array<UInt8>
-        return plaintext
-    }
-
     func finalize(encrypt ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
         // Calculate MAC tag.
         let ghash = gf.ghashFinish()
@@ -183,8 +168,18 @@ final class GCMModeWorker: BlockModeWorker, FinalizingEncryptModeWorker, Finaliz
         }
     }
 
-    func finalize(decrypt plaintext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
-        // do nothing
+    func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
+        counter = incrementCounter(counter)
+
+        // update ghash incrementally
+        gf.ghashUpdate(block: Array(ciphertext))
+
+        guard let ekN = cipherOperation(counter.bytes.slice) else {
+            return Array(ciphertext)
+        }
+
+        // ciphertext block ^ ek1
+        let plaintext = xor(ciphertext, ekN) as Array<UInt8>
         return plaintext
     }
 
@@ -216,6 +211,10 @@ final class GCMModeWorker: BlockModeWorker, FinalizingEncryptModeWorker, Finaliz
         throw GCM.Error.fail
     }
 
+    func finalize(decrypt plaintext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
+        // do nothing
+        return plaintext
+    }
 }
 
 // MARK: - Local utils

+ 13 - 1
Sources/CryptoSwift/StreamDecryptor.swift

@@ -27,9 +27,21 @@ final class StreamDecryptor: Cryptor, Updatable {
 
     // MARK: Updatable
     public func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool) throws -> Array<UInt8> {
+        // TODO: accumulate `worker.additionalBufferSize`
+        // and pass it to willDecrypt(), most likely it will contains MAC
+        var bytes = bytes
+
+        if isLast, var finalizingWorker = worker as? FinalizingDecryptModeWorker, isLast == true {
+            bytes = try finalizingWorker.willDecryptLast(bytes: bytes)
+        }
+
         var plaintext = Array<UInt8>(reserveCapacity: bytes.count)
         for chunk in Array(bytes).batched(by: blockSize) {
-            plaintext += worker.encrypt(block: chunk)
+            plaintext += worker.decrypt(block: chunk)
+        }
+
+        if isLast, var finalizingWorker = worker as? FinalizingDecryptModeWorker, isLast == true {
+            plaintext = Array(try finalizingWorker.didDecryptLast(bytes: plaintext.slice))
         }
 
         // omit unecessary calculation if not needed