浏览代码

Remove BlockMode in favor of CipherModeGenerataor

Marcin Krzyżanowski 9 年之前
父节点
当前提交
f6cb86a092

+ 10 - 10
CryptoSwift.xcodeproj/project.pbxproj

@@ -175,6 +175,10 @@
 		757DA2551A4ED408002BA3EF /* AESTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757DA2541A4ED408002BA3EF /* AESTests.swift */; };
 		757DA2571A4ED47B002BA3EF /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757DA2561A4ED47B002BA3EF /* Helpers.swift */; };
 		757DA2591A4ED4D7002BA3EF /* ChaCha20Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757DA2581A4ED4D7002BA3EF /* ChaCha20Tests.swift */; };
+		7588034C1C8F8C33008C1576 /* CipherModeGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7588034B1C8F8C33008C1576 /* CipherModeGenerator.swift */; };
+		7588034D1C8F8C42008C1576 /* CipherModeGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7588034B1C8F8C33008C1576 /* CipherModeGenerator.swift */; };
+		7588034E1C8F8C42008C1576 /* CipherModeGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7588034B1C8F8C33008C1576 /* CipherModeGenerator.swift */; };
+		7588034F1C8F8C43008C1576 /* CipherModeGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7588034B1C8F8C33008C1576 /* CipherModeGenerator.swift */; };
 		758A94281A65C59200E46135 /* HMACTests.swift in Resources */ = {isa = PBXBuildFile; fileRef = 758A94271A65C59200E46135 /* HMACTests.swift */; };
 		758A94291A65C67400E46135 /* HMACTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 758A94271A65C59200E46135 /* HMACTests.swift */; };
 		75B601EB197D6A6C0009B53D /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 754BE45519693E190098E6F3 /* CryptoSwift.framework */; };
@@ -182,10 +186,6 @@
 		75CB93261C8F5EC10087740D /* CBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93241C8F5EC10087740D /* CBC.swift */; };
 		75CB93271C8F5EC10087740D /* CBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93241C8F5EC10087740D /* CBC.swift */; };
 		75CB93281C8F5EC10087740D /* CBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93241C8F5EC10087740D /* CBC.swift */; };
-		75CB932B1C8F5EE90087740D /* BlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB932A1C8F5EE90087740D /* BlockMode.swift */; };
-		75CB932C1C8F5EE90087740D /* BlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB932A1C8F5EE90087740D /* BlockMode.swift */; };
-		75CB932D1C8F5EE90087740D /* BlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB932A1C8F5EE90087740D /* BlockMode.swift */; };
-		75CB932E1C8F5EE90087740D /* BlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB932A1C8F5EE90087740D /* BlockMode.swift */; };
 		75CB93301C8F5F580087740D /* CipherBlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB932F1C8F5F580087740D /* CipherBlockMode.swift */; };
 		75CB93311C8F5F580087740D /* CipherBlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB932F1C8F5F580087740D /* CipherBlockMode.swift */; };
 		75CB93321C8F5F580087740D /* CipherBlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB932F1C8F5F580087740D /* CipherBlockMode.swift */; };
@@ -353,9 +353,9 @@
 		757DA2541A4ED408002BA3EF /* AESTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AESTests.swift; sourceTree = "<group>"; };
 		757DA2561A4ED47B002BA3EF /* Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = "<group>"; };
 		757DA2581A4ED4D7002BA3EF /* ChaCha20Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChaCha20Tests.swift; sourceTree = "<group>"; };
+		7588034B1C8F8C33008C1576 /* CipherModeGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CipherModeGenerator.swift; path = Sources/CryptoSwift/BlockMode/CipherModeGenerator.swift; sourceTree = SOURCE_ROOT; };
 		758A94271A65C59200E46135 /* HMACTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACTests.swift; sourceTree = "<group>"; };
 		75CB93241C8F5EC10087740D /* CBC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CBC.swift; path = Sources/CryptoSwift/BlockMode/CBC.swift; sourceTree = SOURCE_ROOT; };
-		75CB932A1C8F5EE90087740D /* BlockMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BlockMode.swift; path = Sources/CryptoSwift/BlockMode/BlockMode.swift; sourceTree = SOURCE_ROOT; };
 		75CB932F1C8F5F580087740D /* CipherBlockMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CipherBlockMode.swift; path = Sources/CryptoSwift/BlockMode/CipherBlockMode.swift; sourceTree = SOURCE_ROOT; };
 		75CB93341C8F5FCE0087740D /* PCBC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PCBC.swift; path = Sources/CryptoSwift/BlockMode/PCBC.swift; sourceTree = SOURCE_ROOT; };
 		75CB93391C8F5FFD0087740D /* CFB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CFB.swift; path = Sources/CryptoSwift/BlockMode/CFB.swift; sourceTree = SOURCE_ROOT; };
@@ -531,7 +531,7 @@
 		75CB93291C8F5EC60087740D /* BlockMode */ = {
 			isa = PBXGroup;
 			children = (
-				75CB932A1C8F5EE90087740D /* BlockMode.swift */,
+				7588034B1C8F8C33008C1576 /* CipherModeGenerator.swift */,
 				75CB934D1C8F609D0087740D /* BlockModeOptions.swift */,
 				75CB932F1C8F5F580087740D /* CipherBlockMode.swift */,
 				75CB93241C8F5EC10087740D /* CBC.swift */,
@@ -783,8 +783,8 @@
 				757BC96D1C1CA5790093AAA9 /* Generics.swift in Sources */,
 				75CB93261C8F5EC10087740D /* CBC.swift in Sources */,
 				757BC9711C1CA5790093AAA9 /* Hash.swift in Sources */,
-				75CB932C1C8F5EE90087740D /* BlockMode.swift in Sources */,
 				75CB93361C8F5FCE0087740D /* PCBC.swift in Sources */,
+				7588034D1C8F8C42008C1576 /* CipherModeGenerator.swift in Sources */,
 				75CB93311C8F5F580087740D /* CipherBlockMode.swift in Sources */,
 				757BC9171C1CA56A0093AAA9 /* Utils+Foundation.swift in Sources */,
 				757BC9B51C1CA5790093AAA9 /* UInt8Extension.swift in Sources */,
@@ -838,7 +838,6 @@
 				757BC96C1C1CA5790093AAA9 /* Generics.swift in Sources */,
 				75CB93251C8F5EC10087740D /* CBC.swift in Sources */,
 				757BC9701C1CA5790093AAA9 /* Hash.swift in Sources */,
-				75CB932B1C8F5EE90087740D /* BlockMode.swift in Sources */,
 				75CB93351C8F5FCE0087740D /* PCBC.swift in Sources */,
 				75CB93301C8F5F580087740D /* CipherBlockMode.swift in Sources */,
 				757BC9121C1CA56A0093AAA9 /* String+FoundationExtension.swift in Sources */,
@@ -860,6 +859,7 @@
 				757BC9901C1CA5790093AAA9 /* Operators.swift in Sources */,
 				75CB933A1C8F5FFD0087740D /* CFB.swift in Sources */,
 				75CB933F1C8F60070087740D /* OFB.swift in Sources */,
+				7588034C1C8F8C33008C1576 /* CipherModeGenerator.swift in Sources */,
 				757BC9B81C1CA5790093AAA9 /* UInt32Extension.swift in Sources */,
 				757BC8FE1C1CA56A0093AAA9 /* AES+Foundation.swift in Sources */,
 				757BC98C1C1CA5790093AAA9 /* Multiplatform.swift in Sources */,
@@ -909,8 +909,8 @@
 				757BC96E1C1CA5790093AAA9 /* Generics.swift in Sources */,
 				75CB93271C8F5EC10087740D /* CBC.swift in Sources */,
 				757BC9721C1CA5790093AAA9 /* Hash.swift in Sources */,
-				75CB932D1C8F5EE90087740D /* BlockMode.swift in Sources */,
 				75CB93371C8F5FCE0087740D /* PCBC.swift in Sources */,
+				7588034E1C8F8C42008C1576 /* CipherModeGenerator.swift in Sources */,
 				75CB93321C8F5F580087740D /* CipherBlockMode.swift in Sources */,
 				757BC9141C1CA56A0093AAA9 /* String+FoundationExtension.swift in Sources */,
 				757BC9B61C1CA5790093AAA9 /* UInt8Extension.swift in Sources */,
@@ -964,8 +964,8 @@
 				757BC96F1C1CA5790093AAA9 /* Generics.swift in Sources */,
 				75CB93281C8F5EC10087740D /* CBC.swift in Sources */,
 				757BC9731C1CA5790093AAA9 /* Hash.swift in Sources */,
-				75CB932E1C8F5EE90087740D /* BlockMode.swift in Sources */,
 				75CB93381C8F5FCE0087740D /* PCBC.swift in Sources */,
+				7588034F1C8F8C43008C1576 /* CipherModeGenerator.swift in Sources */,
 				75CB93331C8F5F580087740D /* CipherBlockMode.swift in Sources */,
 				757BC9191C1CA56A0093AAA9 /* Utils+Foundation.swift in Sources */,
 				757BC9B71C1CA5790093AAA9 /* UInt8Extension.swift in Sources */,

+ 18 - 18
CryptoSwiftTests/AESTests.swift

@@ -181,25 +181,25 @@ final class AESTests: XCTestCase {
         XCTAssertEqual(decrypted, plaintext, "decryption failed")
     }
 
-    func testAES_encrypt_performance() {
-        let key:[UInt8] = [0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c];
-        let iv:[UInt8] = [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F]
-        let message = [UInt8](count: 1024 * 1024, repeatedValue: 7)
-        let aes = try! AES(key: key, iv: iv, blockMode: .CBC)
-        measureMetrics([XCTPerformanceMetric_WallClockTime], automaticallyStartMeasuring: true, forBlock: { () -> Void in
-            try! aes.encrypt(message, padding: PKCS7())
-        })
-    }
+//    func testAES_encrypt_performance() {
+//        let key:[UInt8] = [0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c];
+//        let iv:[UInt8] = [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F]
+//        let message = [UInt8](count: 1024 * 1024, repeatedValue: 7)
+//        let aes = try! AES(key: key, iv: iv, blockMode: .CBC)
+//        measureMetrics([XCTPerformanceMetric_WallClockTime], automaticallyStartMeasuring: true, forBlock: { () -> Void in
+//            try! aes.encrypt(message, padding: PKCS7())
+//        })
+//    }
 
-    func testAES_decrypt_performance() {
-        let key:[UInt8] = [0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c];
-        let iv:[UInt8] = [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F]
-        let message = [UInt8](count: 1024 * 1024, repeatedValue: 7)
-        let aes = try! AES(key: key, iv: iv, blockMode: .CBC)
-        measureMetrics([XCTPerformanceMetric_WallClockTime], automaticallyStartMeasuring: true, forBlock: { () -> Void in
-            try! aes.decrypt(message, padding: PKCS7())
-        })
-    }
+//    func testAES_decrypt_performance() {
+//        let key:[UInt8] = [0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c];
+//        let iv:[UInt8] = [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F]
+//        let message = [UInt8](count: 1024 * 1024, repeatedValue: 7)
+//        let aes = try! AES(key: key, iv: iv, blockMode: .CBC)
+//        measureMetrics([XCTPerformanceMetric_WallClockTime], automaticallyStartMeasuring: true, forBlock: { () -> Void in
+//            try! aes.decrypt(message, padding: PKCS7())
+//        })
+//    }
 
     func testAESPerformanceCommonCrypto() {
         let key:[UInt8] = [0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c];

+ 16 - 4
Sources/CryptoSwift/AES.swift

@@ -123,7 +123,13 @@ final public class AES {
 
 
         let blocks = finalBytes.chunks(AES.blockSize)
-        return try blockMode.encryptBlocks(blocks, iv: self.iv, cipherOperation: encryptBlock)
+        let encryptGenerator = blockMode.encryptGenerator(iv, cipherOperation: encryptBlock, inputGenerator: AnyGenerator<Array<UInt8>>(blocks.generate()))
+
+        var out = [UInt8]() // can't preallocate because count of blocks is unknown
+        for processedBlock in AnySequence<Array<UInt8>>({ encryptGenerator }) {
+            out.appendContentsOf(processedBlock)
+        }
+        return out
     }
 
     private func encryptBlock(block:[UInt8]) -> [UInt8]? {
@@ -196,13 +202,19 @@ final public class AES {
         }
         
         let blocks = bytes.chunks(AES.blockSize)
-        let out:[UInt8]
+        var out = [UInt8]()
         switch (blockMode) {
         case .CFB, .OFB, .CTR:
             // CFB, OFB, CTR uses encryptBlock to decrypt
-            out = try blockMode.decryptBlocks(blocks, iv: self.iv, cipherOperation: encryptBlock)
+            let decryptGenerator = blockMode.decryptGenerator(iv, cipherOperation: encryptBlock, inputGenerator: AnyGenerator<Array<UInt8>>(blocks.generate()))
+            for processedBlock in AnySequence<Array<UInt8>>({ decryptGenerator }) {
+                out.appendContentsOf(processedBlock)
+            }
         default:
-            out = try blockMode.decryptBlocks(blocks, iv: self.iv, cipherOperation: decryptBlock)
+            let decryptGenerator = blockMode.decryptGenerator(iv, cipherOperation: decryptBlock, inputGenerator: AnyGenerator<Array<UInt8>>(blocks.generate()))
+            for processedBlock in AnySequence<Array<UInt8>>({ decryptGenerator }) {
+                out.appendContentsOf(processedBlock)
+            }
         }
         
         if let padding = padding {

+ 46 - 30
Sources/CryptoSwift/BlockMode/CBC.swift

@@ -8,43 +8,59 @@
 //  Cipher-block chaining (CBC)
 //
 
-struct CBCMode: BlockMode {
+struct CBCModeEncryptGenerator: CipherModeGenerator {
+    typealias Element = Array<UInt8>
     let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
 
-    func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
-        precondition(blocks.count > 0)
-        guard let iv = iv else {
-            throw BlockError.MissingInitializationVector
-        }
+    private let iv: Element
+    private let inputGenerator: AnyGenerator<Element>
 
-        var out:[UInt8] = [UInt8]()
-        out.reserveCapacity(blocks.count * blocks[blocks.startIndex].count)
-        var prevCiphertext = iv // for the first time prevCiphertext = iv
-        for plaintext in blocks {
-            if let encrypted = cipherOperation(block: xor(prevCiphertext, plaintext)) {
-                out.appendContentsOf(encrypted)
-                prevCiphertext = encrypted
-            }
-        }
-        return out
+    private let cipherOperation: CipherOperationOnBlock
+    private var prevCiphertext: Element?
+
+    init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) {
+        self.iv = iv
+        self.cipherOperation = cipherOperation
+        self.inputGenerator = inputGenerator
     }
 
-    func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
-        precondition(blocks.count > 0)
-        guard let iv = iv else {
-            throw BlockError.MissingInitializationVector
+    mutating func next() -> Element? {
+        guard let plaintext = inputGenerator.next(),
+              let encrypted = cipherOperation(block: xor(prevCiphertext ?? iv, plaintext))
+        else {
+            return nil
         }
 
-        var out:[UInt8] = [UInt8]()
-        out.reserveCapacity(blocks.count * blocks[blocks.startIndex].count)
-        var prevCiphertext = iv // for the first time prevCiphertext = iv
-        for ciphertext in blocks {
-            if let decrypted = cipherOperation(block: ciphertext) { // decrypt
-                out.appendContentsOf(xor(prevCiphertext, decrypted))
-            }
-            prevCiphertext = ciphertext
+        self.prevCiphertext = encrypted
+        return encrypted
+    }
+}
+
+struct CBCModeDecryptGenerator: CipherModeGenerator {
+    typealias Element = Array<UInt8>
+    let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
+
+    private let iv: Element
+    private let inputGenerator: AnyGenerator<Element>
+
+    private let cipherOperation: CipherOperationOnBlock
+    private var prevCiphertext: Element?
+
+    init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Element>) {
+        self.iv = iv
+        self.cipherOperation = cipherOperation
+        self.inputGenerator = inputGenerator
+    }
+
+    mutating func next() -> Element? {
+        guard let ciphertext = inputGenerator.next(),
+              let decrypted = cipherOperation(block: ciphertext)
+        else {
+            return nil
         }
 
-        return out
+        let result = xor(prevCiphertext ?? iv, decrypted)
+        self.prevCiphertext = ciphertext
+        return result
     }
-}
+}

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

@@ -8,8 +8,8 @@
 //  Cipher feedback (CFB)
 //
 
-struct CFBMode: BlockMode {
-    let options: BlockModeOptions = [.InitializationVectorRequired]
+struct CFBMode {
+    static let options: BlockModeOptions = [.InitializationVectorRequired]
 
     func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
         guard let iv = iv else {

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

@@ -8,8 +8,8 @@
 //  Counter (CTR)
 //
 
-struct CTRMode: BlockMode {
-    let options = BlockModeOptions.InitializationVectorRequired
+struct CTRMode {
+    static let options = BlockModeOptions.InitializationVectorRequired
 
     private func buildNonce(iv: [UInt8], counter: UInt64) -> [UInt8] {
         let noncePartLen = AES.blockSize / 2

+ 49 - 33
Sources/CryptoSwift/BlockMode/CipherBlockMode.swift

@@ -11,24 +11,40 @@ import Foundation
 public enum CipherBlockMode {
     case ECB, CBC, PCBC, CFB, OFB, CTR
 
-    private var mode:BlockMode {
+    func encryptGenerator(iv: Array<UInt8>?, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) -> AnyGenerator<Array<UInt8>> {
         switch (self) {
         case CBC:
-            return CBCMode()
-        case PCBC:
-            return PCBCMode()
-        case CFB:
-            return CFBMode()
-        case OFB:
-            return OFBMode()
-        case ECB:
-            return ECBMode()
-        case CTR:
-            return CTRMode()
+            return AnyGenerator<Array<UInt8>>(CBCModeEncryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
+        default:
+            fatalError("Unimplemented")
         }
     }
 
-    var options: BlockModeOptions { return mode.options }
+    func decryptGenerator(iv: Array<UInt8>?, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) -> AnyGenerator<Array<UInt8>> {
+        switch (self) {
+        case CBC:
+            return AnyGenerator<Array<UInt8>>(CBCModeDecryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
+        default:
+            fatalError("Unimplemented")
+        }
+    }
+
+    var options: BlockModeOptions {
+        switch (self) {
+        case .CBC:
+            return [.InitializationVectorRequired, .PaddingRequired]
+        case .CFB:
+            return .InitializationVectorRequired
+        case .CTR:
+            return .InitializationVectorRequired
+        case .ECB:
+            return .PaddingRequired
+        case .OFB:
+            return .InitializationVectorRequired
+        case .PCBC:
+            return [.InitializationVectorRequired, .PaddingRequired]
+        }
+    }
 
     /**
      Process input blocks with given block cipher mode. With fallback to plain mode.
@@ -39,24 +55,24 @@ public enum CipherBlockMode {
 
      - returns: encrypted bytes
      */
-    func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
-
-        // if IV is not available, fallback to plain
-        var finalBlockMode:CipherBlockMode = self
-        if (iv == nil) {
-            finalBlockMode = .ECB
-        }
-
-        return try finalBlockMode.mode.encryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
-    }
-
-    func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
-        // if IV is not available, fallback to plain
-        var finalBlockMode:CipherBlockMode = self
-        if (iv == nil) {
-            finalBlockMode = .ECB
-        }
-
-        return try finalBlockMode.mode.decryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
-    }
+//    func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
+//
+//        // if IV is not available, fallback to plain
+//        var finalBlockMode:CipherBlockMode = self
+//        if (iv == nil) {
+//            finalBlockMode = .ECB
+//        }
+//
+//        return try finalBlockMode.mode.encryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
+//    }
+//
+//    func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
+//        // if IV is not available, fallback to plain
+//        var finalBlockMode:CipherBlockMode = self
+//        if (iv == nil) {
+//            finalBlockMode = .ECB
+//        }
+//
+//        return try finalBlockMode.mode.decryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
+//    }
 }

+ 5 - 7
Sources/CryptoSwift/BlockMode/BlockMode.swift → Sources/CryptoSwift/BlockMode/CipherModeGenerator.swift

@@ -1,22 +1,20 @@
 //
-//  BlockMode.swift
+//  CipherModeGenerator.swift
 //  CryptoSwift
 //
 //  Created by Marcin Krzyzanowski on 08/03/16.
 //  Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
 //
 
-import Foundation
-
 // I have no better name for that
-typealias CipherOperationOnBlock = (block: [UInt8]) -> [UInt8]?
 
 enum BlockError: ErrorType {
     case MissingInitializationVector
 }
 
-protocol BlockMode {
+typealias CipherOperationOnBlock = (block: [UInt8]) -> [UInt8]?
+
+protocol CipherModeGenerator: GeneratorType {
     var options: BlockModeOptions { get }
-    func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8]
-    func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8]
+    init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>)
 }

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

@@ -8,8 +8,8 @@
 //  Electronic codebook (ECB)
 //
 
-struct ECBMode: BlockMode {
-    let options: BlockModeOptions = [.PaddingRequired]
+struct ECBMode {
+    static let options: BlockModeOptions = [.PaddingRequired]
 
     func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) -> [UInt8] {
         var out:[UInt8] = [UInt8]()

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

@@ -8,8 +8,8 @@
 //  Propagating Cipher Block Chaining (PCBC)
 //
 
-struct PCBCMode: BlockMode {
-    let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
+struct PCBCMode {
+    static let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
 
     func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
         precondition(blocks.count > 0)

+ 2 - 2
Sources/CryptoSwift/OFB.swift

@@ -8,8 +8,8 @@
 // Output Feedback (OFB)
 //
 
-struct OFBMode: BlockMode {
-    let options: BlockModeOptions = [.InitializationVectorRequired]
+struct OFBMode {
+    static let options: BlockModeOptions = [.InitializationVectorRequired]
 
     func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
         guard let iv = iv else {

+ 1 - 2
Sources/CryptoSwift/PKCS7.swift

@@ -38,11 +38,10 @@ public struct PKCS7: Padding {
 
     public func remove(bytes: [UInt8], blockSize:Int?) -> [UInt8] {
         assert(bytes.count > 0, "Need bytes to remove padding")
-        guard bytes.count > 0 else {
+        guard bytes.count > 0, let lastByte = bytes.last else {
             return bytes
         }
 
-        let lastByte = bytes.last!
         let padding = Int(lastByte) // last byte
         let finalLength = bytes.count - padding