浏览代码

use block parameter where block is expected (workers)

Marcin Krzyzanowski 7 年之前
父节点
当前提交
81893af39b

+ 25 - 9
Sources/CryptoSwift/AES.Cryptors.swift

@@ -52,7 +52,7 @@ extension AES {
             var encrypted = Array<UInt8>(reserveCapacity: accumulated.count)
             for chunk in accumulated.batched(by: AES.blockSize) {
                 if isLast || (accumulated.count - processedBytes) >= AES.blockSize {
-                    encrypted += worker.encrypt(chunk)
+                    encrypted += worker.encrypt(block: chunk)
                     processedBytes += chunk.count
                 }
             }
@@ -100,17 +100,33 @@ extension AES {
                 accumulated += bytes
             }
 
-            var processedBytes = 0
+            var processedBytesCount = 0
             var plaintext = Array<UInt8>(reserveCapacity: accumulated.count)
+            // Processing in a block-size manner. It's good for block modes, but bad for stream modes.
             for var chunk in accumulated.batched(by: AES.blockSize) {
-                if isLast || (accumulated.count - processedBytes) >= AES.blockSize {
+                if isLast || (accumulated.count - processedBytesCount) >= AES.blockSize {
 
                     if isLast, var finalizingWorker = worker as? BlockModeWorkerFinalizing {
-                        chunk = try finalizingWorker.willDecryptLast(ciphertext: chunk)
+                        // ERR: chunk is limited by block, but I don't want block
+                        // For GCM: Tag is appended at the end and shouldn't be processed
+                        //          so chunk is stripped of the Tag.
+                        /*
+                         Failure scenario:
+                         Encrypt:
+                         Input: 11 bytes
+                         Combined: 11 + 16 (ciphertext + tag)
+
+                         Decrypt in chunks:
+                         1st chunk: 16 bytes = 11 ciphertext + 4 bytes of tag
+                         2nd chunk: 11 bytes = 11 remaining bytes of tag
+
+                         Problem: by the time of 1st chunk, the total length is unknown so can't decide to decrypt only 11 bytes.
+                         */
+                        chunk = try finalizingWorker.willDecryptLast(block: chunk)
                     }
 
                     if !chunk.isEmpty {
-                        plaintext += worker.decrypt(chunk)
+                        plaintext += worker.decrypt(block: chunk)
                     }
 
                     // remove "offset" from the beginning of first chunk
@@ -120,14 +136,14 @@ extension AES {
                     }
 
                     if var finalizingWorker = worker as? BlockModeWorkerFinalizing, isLast == true {
-                        plaintext = try finalizingWorker.didDecryptLast(plaintext: plaintext.slice)
+                        plaintext = try finalizingWorker.didDecryptLast(block: plaintext.slice)
                     }
 
-                    processedBytes += chunk.count
+                    processedBytesCount += chunk.count
                 }
             }
-            accumulated.removeFirst(processedBytes)
-            processedBytesTotalCount += processedBytes
+            accumulated.removeFirst(processedBytesCount) // super-slow
+            processedBytesTotalCount += processedBytesCount
 
             if isLast {
                 plaintext = padding.remove(from: plaintext, blockSize: AES.blockSize)

+ 4 - 4
Sources/CryptoSwift/BlockMode/BlockModeWorker.swift

@@ -16,8 +16,8 @@
 public protocol BlockModeWorker {
     var cipherOperation: CipherOperationOnBlock { get }
 
-    mutating func encrypt(_ plaintext: ArraySlice<UInt8>) -> Array<UInt8>
-    mutating func decrypt(_ ciphertext: ArraySlice<UInt8>) -> Array<UInt8>
+    mutating func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8>
+    mutating func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8>
 }
 
 // TODO: remove and merge with BlockModeWorker
@@ -26,7 +26,7 @@ public protocol BlockModeWorkerFinalizing: BlockModeWorker {
     // Called after the last block is encrypted
     mutating func finalize(encrypt ciphertext: ArraySlice<UInt8>) throws -> Array<UInt8>
     // Called before decryption, hence input is ciphertext
-    mutating func willDecryptLast(ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8>
+    mutating func willDecryptLast(block ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8>
     // Called after decryption, hence input is ciphertext
-    mutating func didDecryptLast(plaintext: ArraySlice<UInt8>) throws -> Array<UInt8>
+    mutating func didDecryptLast(block plaintext: ArraySlice<UInt8>) throws -> Array<UInt8>
 }

+ 2 - 2
Sources/CryptoSwift/BlockMode/CBC.swift

@@ -48,7 +48,7 @@ struct CBCModeWorker: BlockModeWorker {
         self.cipherOperation = cipherOperation
     }
 
-    mutating func encrypt(_ plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
+    mutating func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
         guard let ciphertext = cipherOperation(xor(prev ?? iv, plaintext)) else {
             return Array(plaintext)
         }
@@ -56,7 +56,7 @@ struct CBCModeWorker: BlockModeWorker {
         return ciphertext
     }
 
-    mutating func decrypt(_ ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
+    mutating func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
         guard let plaintext = cipherOperation(ciphertext) else {
             return Array(ciphertext)
         }

+ 2 - 2
Sources/CryptoSwift/BlockMode/CFB.swift

@@ -48,7 +48,7 @@ struct CFBModeWorker: BlockModeWorker {
         self.cipherOperation = cipherOperation
     }
 
-    mutating func encrypt(_ plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
+    mutating func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
         guard let ciphertext = cipherOperation(prev ?? iv) else {
             return Array(plaintext)
         }
@@ -56,7 +56,7 @@ struct CFBModeWorker: BlockModeWorker {
         return Array(prev ?? [])
     }
 
-    mutating func decrypt(_ ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
+    mutating func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
         guard let plaintext = cipherOperation(prev ?? iv) else {
             return Array(ciphertext)
         }

+ 3 - 3
Sources/CryptoSwift/BlockMode/CTR.swift

@@ -48,7 +48,7 @@ struct CTRModeWorker: RandomAccessBlockModeWorker {
         self.cipherOperation = cipherOperation
     }
 
-    mutating func encrypt(_ plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
+    mutating func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
         let nonce = buildNonce(iv, counter: UInt64(counter))
         counter = counter + 1
 
@@ -59,8 +59,8 @@ struct CTRModeWorker: RandomAccessBlockModeWorker {
         return xor(plaintext, ciphertext)
     }
 
-    mutating func decrypt(_ ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
-        return encrypt(ciphertext)
+    mutating func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
+        return encrypt(block: ciphertext)
     }
 }
 

+ 3 - 3
Sources/CryptoSwift/BlockMode/ECB.swift

@@ -35,14 +35,14 @@ struct ECBModeWorker: BlockModeWorker {
         self.cipherOperation = cipherOperation
     }
 
-    mutating func encrypt(_ plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
+    mutating func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
         guard let ciphertext = cipherOperation(plaintext) else {
             return Array(plaintext)
         }
         return ciphertext
     }
 
-    mutating func decrypt(_ ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
-        return encrypt(ciphertext)
+    mutating func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
+        return encrypt(block: ciphertext)
     }
 }

+ 4 - 4
Sources/CryptoSwift/BlockMode/GCM.swift

@@ -125,7 +125,7 @@ final class GCMModeWorker: BlockModeWorkerFinalizing {
         eky0 = UInt128(cipherOperation(counter.bytes.slice)!)
     }
 
-    func encrypt(_ plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
+    func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
         counter = incrementCounter(counter)
 
         guard let ekyN = cipherOperation(counter.bytes.slice) else {
@@ -141,7 +141,7 @@ final class GCMModeWorker: BlockModeWorkerFinalizing {
         return Array(ciphertext)
     }
 
-    func decrypt(_ ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
+    func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
         counter = incrementCounter(counter)
 
         // update ghash incrementally
@@ -175,7 +175,7 @@ final class GCMModeWorker: BlockModeWorkerFinalizing {
     // The authenticated decryption operation has five inputs: K, IV , C, A, and T. It has only a single
     // output, either the plaintext value P or a special symbol FAIL that indicates that the inputs are not
     // authentic.
-    func willDecryptLast(ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
+    func willDecryptLast(block ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
         // Validate tag
         switch mode {
         case .combined:
@@ -189,7 +189,7 @@ final class GCMModeWorker: BlockModeWorkerFinalizing {
         }
     }
 
-    func didDecryptLast(plaintext: ArraySlice<UInt8>) throws -> Array<UInt8> {
+    func didDecryptLast(block plaintext: ArraySlice<UInt8>) throws -> Array<UInt8> {
         // Calculate MAC tag.
         let ghash = gf.ghashFinish()
         let computedTag = Array((ghash ^ eky0).bytes.prefix(GCMModeWorker.tagSize))

+ 2 - 2
Sources/CryptoSwift/BlockMode/OFB.swift

@@ -48,7 +48,7 @@ struct OFBModeWorker: BlockModeWorker {
         self.cipherOperation = cipherOperation
     }
 
-    mutating func encrypt(_ plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
+    mutating func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
         guard let ciphertext = cipherOperation(prev ?? iv) else {
             return Array(plaintext)
         }
@@ -56,7 +56,7 @@ struct OFBModeWorker: BlockModeWorker {
         return xor(plaintext, ciphertext)
     }
 
-    mutating func decrypt(_ ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
+    mutating func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
         guard let decrypted = cipherOperation(prev ?? iv) else {
             return Array(ciphertext)
         }

+ 2 - 2
Sources/CryptoSwift/BlockMode/PCBC.swift

@@ -48,7 +48,7 @@ struct PCBCModeWorker: BlockModeWorker {
         self.cipherOperation = cipherOperation
     }
 
-    mutating func encrypt(_ plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
+    mutating func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
         guard let ciphertext = cipherOperation(xor(prev ?? iv, plaintext)) else {
             return Array(plaintext)
         }
@@ -56,7 +56,7 @@ struct PCBCModeWorker: BlockModeWorker {
         return ciphertext
     }
 
-    mutating func decrypt(_ ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
+    mutating func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
         guard let plaintext = cipherOperation(ciphertext) else {
             return Array(ciphertext)
         }

+ 2 - 2
Sources/CryptoSwift/Blowfish.swift

@@ -504,7 +504,7 @@ extension Blowfish: Cipher {
         out.reserveCapacity(bytes.count)
 
         for chunk in bytes.batched(by: Blowfish.blockSize) {
-            out += encryptWorker.encrypt(chunk)
+            out += encryptWorker.encrypt(block: chunk)
         }
 
         if blockMode.options.contains(.paddingRequired) && (out.count % Blowfish.blockSize != 0) {
@@ -527,7 +527,7 @@ extension Blowfish: Cipher {
         out.reserveCapacity(bytes.count)
 
         for chunk in Array(bytes).batched(by: Blowfish.blockSize) {
-            out += decryptWorker.decrypt(chunk) // FIXME: copying here is innefective
+            out += decryptWorker.decrypt(block: chunk) // FIXME: copying here is innefective
         }
 
         out = padding.remove(from: out, blockSize: Blowfish.blockSize)