Ver Fonte

Add Cryptor protocol to ciphers

Marcin Krzyżanowski há 9 anos atrás
pai
commit
e18a70a65b

+ 10 - 0
CryptoSwift.xcodeproj/project.pbxproj

@@ -231,6 +231,10 @@
 		75DB81A41CDBFDC700ED181A /* BlockModeWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DB81A21CDBFDC700ED181A /* BlockModeWorker.swift */; };
 		75DB81A41CDBFDC700ED181A /* BlockModeWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DB81A21CDBFDC700ED181A /* BlockModeWorker.swift */; };
 		75DB81A51CDBFDC700ED181A /* BlockModeWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DB81A21CDBFDC700ED181A /* BlockModeWorker.swift */; };
 		75DB81A51CDBFDC700ED181A /* BlockModeWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DB81A21CDBFDC700ED181A /* BlockModeWorker.swift */; };
 		75DB81A61CDBFDC700ED181A /* BlockModeWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DB81A21CDBFDC700ED181A /* BlockModeWorker.swift */; };
 		75DB81A61CDBFDC700ED181A /* BlockModeWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DB81A21CDBFDC700ED181A /* BlockModeWorker.swift */; };
+		75DB81A81CDC06B100ED181A /* Cryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DB81A71CDC06B100ED181A /* Cryptor.swift */; };
+		75DB81A91CDC06B100ED181A /* Cryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DB81A71CDC06B100ED181A /* Cryptor.swift */; };
+		75DB81AA1CDC06B100ED181A /* Cryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DB81A71CDC06B100ED181A /* Cryptor.swift */; };
+		75DB81AB1CDC06B100ED181A /* Cryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DB81A71CDC06B100ED181A /* Cryptor.swift */; };
 		80545D131CA9FECD00474A99 /* Bit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80545D121CA9FECD00474A99 /* Bit.swift */; };
 		80545D131CA9FECD00474A99 /* Bit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80545D121CA9FECD00474A99 /* Bit.swift */; };
 		80545D141CA9FECD00474A99 /* Bit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80545D121CA9FECD00474A99 /* Bit.swift */; };
 		80545D141CA9FECD00474A99 /* Bit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80545D121CA9FECD00474A99 /* Bit.swift */; };
 		80545D151CA9FECD00474A99 /* Bit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80545D121CA9FECD00474A99 /* Bit.swift */; };
 		80545D151CA9FECD00474A99 /* Bit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80545D121CA9FECD00474A99 /* Bit.swift */; };
@@ -390,6 +394,7 @@
 		75CB934D1C8F609D0087740D /* BlockModeOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BlockModeOptions.swift; path = Sources/CryptoSwift/BlockMode/BlockModeOptions.swift; sourceTree = SOURCE_ROOT; };
 		75CB934D1C8F609D0087740D /* BlockModeOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BlockModeOptions.swift; path = Sources/CryptoSwift/BlockMode/BlockModeOptions.swift; sourceTree = SOURCE_ROOT; };
 		75D614BF1BD844F2001358B2 /* CryptoSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CryptoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		75D614BF1BD844F2001358B2 /* CryptoSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CryptoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		75DB81A21CDBFDC700ED181A /* BlockModeWorker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BlockModeWorker.swift; path = Sources/CryptoSwift/BlockMode/BlockModeWorker.swift; sourceTree = SOURCE_ROOT; };
 		75DB81A21CDBFDC700ED181A /* BlockModeWorker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BlockModeWorker.swift; path = Sources/CryptoSwift/BlockMode/BlockModeWorker.swift; sourceTree = SOURCE_ROOT; };
+		75DB81A71CDC06B100ED181A /* Cryptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Cryptor.swift; path = Sources/CryptoSwift/Cryptor.swift; sourceTree = SOURCE_ROOT; };
 		75DF77721BC8EB59006E9520 /* CryptoSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CryptoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		75DF77721BC8EB59006E9520 /* CryptoSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CryptoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		80545D121CA9FECD00474A99 /* Bit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Bit.swift; path = Sources/CryptoSwift/Bit.swift; sourceTree = SOURCE_ROOT; };
 		80545D121CA9FECD00474A99 /* Bit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Bit.swift; path = Sources/CryptoSwift/Bit.swift; sourceTree = SOURCE_ROOT; };
 /* End PBXFileReference section */
 /* End PBXFileReference section */
@@ -482,6 +487,7 @@
 				757F440D1CC1822A002B1F85 /* SecureBytes.swift */,
 				757F440D1CC1822A002B1F85 /* SecureBytes.swift */,
 				757BC91F1C1CA5790093AAA9 /* BytesSequence.swift */,
 				757BC91F1C1CA5790093AAA9 /* BytesSequence.swift */,
 				757BC9201C1CA5790093AAA9 /* ChaCha20.swift */,
 				757BC9201C1CA5790093AAA9 /* ChaCha20.swift */,
+				75DB81A71CDC06B100ED181A /* Cryptor.swift */,
 				757BC9211C1CA5790093AAA9 /* CipherProtocol.swift */,
 				757BC9211C1CA5790093AAA9 /* CipherProtocol.swift */,
 				757F44081CC172B6002B1F85 /* BlockCipher.swift */,
 				757F44081CC172B6002B1F85 /* BlockCipher.swift */,
 				75CB93291C8F5EC60087740D /* BlockMode */,
 				75CB93291C8F5EC60087740D /* BlockMode */,
@@ -846,6 +852,7 @@
 				757BC9811C1CA5790093AAA9 /* IntegerConvertible.swift in Sources */,
 				757BC9811C1CA5790093AAA9 /* IntegerConvertible.swift in Sources */,
 				757BC9511C1CA5790093AAA9 /* BytesSequence.swift in Sources */,
 				757BC9511C1CA5790093AAA9 /* BytesSequence.swift in Sources */,
 				757BC9891C1CA5790093AAA9 /* MD5.swift in Sources */,
 				757BC9891C1CA5790093AAA9 /* MD5.swift in Sources */,
+				75DB81A91CDC06B100ED181A /* Cryptor.swift in Sources */,
 				757BC9A91C1CA5790093AAA9 /* SHA1.swift in Sources */,
 				757BC9A91C1CA5790093AAA9 /* SHA1.swift in Sources */,
 				757BC9911C1CA5790093AAA9 /* Operators.swift in Sources */,
 				757BC9911C1CA5790093AAA9 /* Operators.swift in Sources */,
 				75CB933B1C8F5FFD0087740D /* CFB.swift in Sources */,
 				75CB933B1C8F5FFD0087740D /* CFB.swift in Sources */,
@@ -906,6 +913,7 @@
 				757BC9501C1CA5790093AAA9 /* BytesSequence.swift in Sources */,
 				757BC9501C1CA5790093AAA9 /* BytesSequence.swift in Sources */,
 				757BC9881C1CA5790093AAA9 /* MD5.swift in Sources */,
 				757BC9881C1CA5790093AAA9 /* MD5.swift in Sources */,
 				757BC9A81C1CA5790093AAA9 /* SHA1.swift in Sources */,
 				757BC9A81C1CA5790093AAA9 /* SHA1.swift in Sources */,
+				75DB81A81CDC06B100ED181A /* Cryptor.swift in Sources */,
 				757BC9901C1CA5790093AAA9 /* Operators.swift in Sources */,
 				757BC9901C1CA5790093AAA9 /* Operators.swift in Sources */,
 				75CB933A1C8F5FFD0087740D /* CFB.swift in Sources */,
 				75CB933A1C8F5FFD0087740D /* CFB.swift in Sources */,
 				7588034C1C8F8C33008C1576 /* BlockModeGenerator.swift in Sources */,
 				7588034C1C8F8C33008C1576 /* BlockModeGenerator.swift in Sources */,
@@ -983,6 +991,7 @@
 				757BC9821C1CA5790093AAA9 /* IntegerConvertible.swift in Sources */,
 				757BC9821C1CA5790093AAA9 /* IntegerConvertible.swift in Sources */,
 				757BC9521C1CA5790093AAA9 /* BytesSequence.swift in Sources */,
 				757BC9521C1CA5790093AAA9 /* BytesSequence.swift in Sources */,
 				757BC98A1C1CA5790093AAA9 /* MD5.swift in Sources */,
 				757BC98A1C1CA5790093AAA9 /* MD5.swift in Sources */,
+				75DB81AB1CDC06B100ED181A /* Cryptor.swift in Sources */,
 				757BC9AA1C1CA5790093AAA9 /* SHA1.swift in Sources */,
 				757BC9AA1C1CA5790093AAA9 /* SHA1.swift in Sources */,
 				757BC9921C1CA5790093AAA9 /* Operators.swift in Sources */,
 				757BC9921C1CA5790093AAA9 /* Operators.swift in Sources */,
 				75CB933C1C8F5FFD0087740D /* CFB.swift in Sources */,
 				75CB933C1C8F5FFD0087740D /* CFB.swift in Sources */,
@@ -1043,6 +1052,7 @@
 				757BC9831C1CA5790093AAA9 /* IntegerConvertible.swift in Sources */,
 				757BC9831C1CA5790093AAA9 /* IntegerConvertible.swift in Sources */,
 				757BC9531C1CA5790093AAA9 /* BytesSequence.swift in Sources */,
 				757BC9531C1CA5790093AAA9 /* BytesSequence.swift in Sources */,
 				757BC98B1C1CA5790093AAA9 /* MD5.swift in Sources */,
 				757BC98B1C1CA5790093AAA9 /* MD5.swift in Sources */,
+				75DB81AA1CDC06B100ED181A /* Cryptor.swift in Sources */,
 				757BC9AB1C1CA5790093AAA9 /* SHA1.swift in Sources */,
 				757BC9AB1C1CA5790093AAA9 /* SHA1.swift in Sources */,
 				757BC9931C1CA5790093AAA9 /* Operators.swift in Sources */,
 				757BC9931C1CA5790093AAA9 /* Operators.swift in Sources */,
 				75CB933D1C8F5FFD0087740D /* CFB.swift in Sources */,
 				75CB933D1C8F5FFD0087740D /* CFB.swift in Sources */,

+ 124 - 119
Sources/CryptoSwift/AES.swift

@@ -33,54 +33,6 @@ final public class AES: BlockCipher {
         }
         }
     }
     }
 
 
-    public struct Encryptor {
-        private var worker: BlockModeWorker
-        let padding: Padding
-
-        init(aes: AES) {
-            self.padding = aes.padding;
-            self.worker = aes.cipherBlockMode.worker(aes.iv, cipherOperation: aes.encryptBlock)
-        }
-
-        mutating func update(bytes:[UInt8], isLast: Bool) throws -> [UInt8] {
-            if isLast {
-                let paddedBytes = padding.add(bytes, blockSize: AES.blockSize)
-                var result = [UInt8]()
-                for chunk in paddedBytes.chunks(AES.blockSize) ?? [] {
-                    result.appendContentsOf(worker.encrypt(chunk))
-                }
-                return result
-            }
-
-            return worker.encrypt(bytes)
-        }
-    }
-
-    public struct Decryptor {
-        private var worker: BlockModeWorker
-        let padding: Padding
-
-        init(aes: AES) {
-            self.padding = aes.padding;
-
-            switch (aes.cipherBlockMode) {
-                case .CFB, .OFB, .CTR:
-                    // CFB, OFB, CTR uses encryptBlock to decrypt
-                    self.worker = aes.cipherBlockMode.worker(aes.iv, cipherOperation: aes.encryptBlock)
-                default:
-                    self.worker = aes.cipherBlockMode.worker(aes.iv, cipherOperation: aes.decryptBlock)
-            }
-        }
-
-        mutating func update(bytes:[UInt8], isLast: Bool) throws -> [UInt8] {
-            let plaintext = worker.decrypt(bytes)
-            if isLast {
-                return padding.remove(plaintext, blockSize: AES.blockSize)
-            }
-            return plaintext
-        }
-    }
-
     private let cipherBlockMode:CipherBlockMode
     private let cipherBlockMode:CipherBlockMode
     public static let blockSize:Int = 16 // 128 /8
     public static let blockSize:Int = 16 // 128 /8
     
     
@@ -156,14 +108,6 @@ final public class AES: BlockCipher {
         }
         }
     }
     }
 
 
-    public func encryptor() -> Encryptor {
-        return Encryptor(aes: self)
-    }
-
-    public func decryptor() -> Decryptor {
-        return Decryptor(aes: self)
-    }
-
     /// Encrypt given bytes at once
     /// Encrypt given bytes at once
     ///
     ///
     /// - parameter bytes: Plaintext data
     /// - parameter bytes: Plaintext data
@@ -184,45 +128,67 @@ final public class AES: BlockCipher {
 
 
         return out
         return out
     }
     }
+    
+    /// Decrypt given bytes at once
+    ///
+    /// - parameter bytes: Ciphertext data
+    /// - returns: Plaintext data
+    public func decrypt(bytes:[UInt8]) throws -> [UInt8] {
+        if cipherBlockMode.options.contains(.PaddingRequired) && (bytes.count % AES.blockSize != 0) {
+            throw Error.DataPaddingRequired
+        }
+
+        var oneTimeCryptor = Decryptor(aes: self)
+        let chunks = bytes.chunks(AES.blockSize)
+        var out = [UInt8]()
+        out.reserveCapacity(bytes.count)
+        for (idx,chunk) in chunks.enumerate() {
+            out.appendContentsOf(try oneTimeCryptor.update(chunk, isLast: idx == max(0,chunks.count - 1)))
+        }
+        return out
+    }
+}
 
 
+// MARK: Private
+extension AES {
     private func encryptBlock(block:[UInt8]) -> [UInt8]? {
     private func encryptBlock(block:[UInt8]) -> [UInt8]? {
         let rounds = self.variant.Nr
         let rounds = self.variant.Nr
         let rk = self.expandedKey
         let rk = self.expandedKey
         var b = toUInt32Array(block[block.startIndex..<block.endIndex])
         var b = toUInt32Array(block[block.startIndex..<block.endIndex])
 
 
         var t = [UInt32](count: 4, repeatedValue: 0)
         var t = [UInt32](count: 4, repeatedValue: 0)
-        
+
         for r in 0..<rounds - 1 {
         for r in 0..<rounds - 1 {
             t[0] = b[0] ^ rk[r][0]
             t[0] = b[0] ^ rk[r][0]
             t[1] = b[1] ^ rk[r][1]
             t[1] = b[1] ^ rk[r][1]
             t[2] = b[2] ^ rk[r][2]
             t[2] = b[2] ^ rk[r][2]
             t[3] = b[3] ^ rk[r][3]
             t[3] = b[3] ^ rk[r][3]
-            
+
             let lb00 = T0[Int(t[0] & 0xFF)]
             let lb00 = T0[Int(t[0] & 0xFF)]
             let lb01 = T1[Int((t[1] >> 8) & 0xFF)]
             let lb01 = T1[Int((t[1] >> 8) & 0xFF)]
             let lb02 = T2[Int((t[2] >> 16) & 0xFF)]
             let lb02 = T2[Int((t[2] >> 16) & 0xFF)]
             let lb03 = T3[Int(t[3] >> 24)]
             let lb03 = T3[Int(t[3] >> 24)]
             b[0] = lb00 ^ lb01 ^ lb02 ^ lb03
             b[0] = lb00 ^ lb01 ^ lb02 ^ lb03
-            
+
             let lb10 = T0[Int(t[1] & 0xFF)]
             let lb10 = T0[Int(t[1] & 0xFF)]
             let lb11 = T1[Int((t[2] >> 8) & 0xFF)]
             let lb11 = T1[Int((t[2] >> 8) & 0xFF)]
             let lb12 = T2[Int((t[3] >> 16) & 0xFF)]
             let lb12 = T2[Int((t[3] >> 16) & 0xFF)]
             let lb13 = T3[Int(t[0] >> 24)]
             let lb13 = T3[Int(t[0] >> 24)]
             b[1] = lb10 ^ lb11 ^ lb12 ^ lb13
             b[1] = lb10 ^ lb11 ^ lb12 ^ lb13
-            
+
             let lb20 = T0[Int(t[2] & 0xFF)]
             let lb20 = T0[Int(t[2] & 0xFF)]
             let lb21 = T1[Int((t[3] >> 8) & 0xFF)]
             let lb21 = T1[Int((t[3] >> 8) & 0xFF)]
             let lb22 = T2[Int((t[0] >> 16) & 0xFF)]
             let lb22 = T2[Int((t[0] >> 16) & 0xFF)]
             let lb23 = T3[Int(t[1] >> 24)]
             let lb23 = T3[Int(t[1] >> 24)]
             b[2] = lb20 ^ lb21 ^ lb22 ^ lb23
             b[2] = lb20 ^ lb21 ^ lb22 ^ lb23
-            
+
             let lb30 = T0[Int(t[3] & 0xFF)]
             let lb30 = T0[Int(t[3] & 0xFF)]
             let lb31 = T1[Int((t[0] >> 8) & 0xFF)]
             let lb31 = T1[Int((t[0] >> 8) & 0xFF)]
             let lb32 = T2[Int((t[1] >> 16) & 0xFF)]
             let lb32 = T2[Int((t[1] >> 16) & 0xFF)]
             let lb33 = T3[Int(t[2] >> 24)]
             let lb33 = T3[Int(t[2] >> 24)]
             b[3] = lb30 ^ lb31 ^ lb32 ^ lb33
             b[3] = lb30 ^ lb31 ^ lb32 ^ lb33
         }
         }
-        
+
         // last round
         // last round
         let r = rounds - 1
         let r = rounds - 1
 
 
@@ -236,7 +202,7 @@ final public class AES: BlockCipher {
         b[1] = F1(t[1], t[2], t[3], t[0]) ^ rk[rounds][1]
         b[1] = F1(t[1], t[2], t[3], t[0]) ^ rk[rounds][1]
         b[2] = F1(t[2], t[3], t[0], t[1]) ^ rk[rounds][2]
         b[2] = F1(t[2], t[3], t[0], t[1]) ^ rk[rounds][2]
         b[3] = F1(t[3], t[0], t[1], t[2]) ^ rk[rounds][3]
         b[3] = F1(t[3], t[0], t[1], t[2]) ^ rk[rounds][3]
-        
+
         var out = [UInt8]()
         var out = [UInt8]()
         out.reserveCapacity(b.count * 4)
         out.reserveCapacity(b.count * 4)
         for num in b {
         for num in b {
@@ -245,99 +211,80 @@ final public class AES: BlockCipher {
             out.append(UInt8((num >> 16) & 0xFF))
             out.append(UInt8((num >> 16) & 0xFF))
             out.append(UInt8((num >> 24) & 0xFF))
             out.append(UInt8((num >> 24) & 0xFF))
         }
         }
-        
-        return out
-    }
-    
-    /// Decrypt given bytes at once
-    ///
-    /// - parameter bytes: Ciphertext data
-    /// - returns: Plaintext data
-    public func decrypt(bytes:[UInt8]) throws -> [UInt8] {
-        if cipherBlockMode.options.contains(.PaddingRequired) && (bytes.count % AES.blockSize != 0) {
-            throw Error.DataPaddingRequired
-        }
 
 
-        var oneTimeCryptor = Decryptor(aes: self)
-        let chunks = bytes.chunks(AES.blockSize)
-        var out = [UInt8]()
-        out.reserveCapacity(bytes.count)
-        for (idx,chunk) in chunks.enumerate() {
-            out.appendContentsOf(try oneTimeCryptor.update(chunk, isLast: idx == max(0,chunks.count - 1)))
-        }
         return out
         return out
     }
     }
-    
+
     private func decryptBlock(block:[UInt8]) -> [UInt8]? {
     private func decryptBlock(block:[UInt8]) -> [UInt8]? {
         let rounds = self.variant.Nr
         let rounds = self.variant.Nr
         let rk = expandedKeyInv
         let rk = expandedKeyInv
         var b = toUInt32Array(block[block.startIndex..<block.endIndex])
         var b = toUInt32Array(block[block.startIndex..<block.endIndex])
 
 
         var t = [UInt32](count: 4, repeatedValue: 0)
         var t = [UInt32](count: 4, repeatedValue: 0)
-        
+
         for r in (2...rounds).reverse() {
         for r in (2...rounds).reverse() {
             t[0] = b[0] ^ rk[r][0]
             t[0] = b[0] ^ rk[r][0]
             t[1] = b[1] ^ rk[r][1]
             t[1] = b[1] ^ rk[r][1]
             t[2] = b[2] ^ rk[r][2]
             t[2] = b[2] ^ rk[r][2]
             t[3] = b[3] ^ rk[r][3]
             t[3] = b[3] ^ rk[r][3]
-            
+
             let b00 = T0_INV[Int(t[0] & 0xFF)]
             let b00 = T0_INV[Int(t[0] & 0xFF)]
             let b01 = T1_INV[Int((t[3] >> 8) & 0xFF)]
             let b01 = T1_INV[Int((t[3] >> 8) & 0xFF)]
             let b02 = T2_INV[Int((t[2] >> 16) & 0xFF)]
             let b02 = T2_INV[Int((t[2] >> 16) & 0xFF)]
             let b03 = T3_INV[Int(t[1] >> 24)]
             let b03 = T3_INV[Int(t[1] >> 24)]
             b[0] = b00 ^ b01 ^ b02 ^ b03
             b[0] = b00 ^ b01 ^ b02 ^ b03
-            
+
             let b10 = T0_INV[Int(t[1] & 0xFF)]
             let b10 = T0_INV[Int(t[1] & 0xFF)]
             let b11 = T1_INV[Int((t[0] >> 8) & 0xFF)]
             let b11 = T1_INV[Int((t[0] >> 8) & 0xFF)]
             let b12 = T2_INV[Int((t[3] >> 16) & 0xFF)]
             let b12 = T2_INV[Int((t[3] >> 16) & 0xFF)]
             let b13 = T3_INV[Int(t[2] >> 24)]
             let b13 = T3_INV[Int(t[2] >> 24)]
             b[1] = b10 ^ b11 ^ b12 ^ b13
             b[1] = b10 ^ b11 ^ b12 ^ b13
-            
+
             let b20 = T0_INV[Int(t[2] & 0xFF)]
             let b20 = T0_INV[Int(t[2] & 0xFF)]
             let b21 = T1_INV[Int((t[1] >> 8) & 0xFF)]
             let b21 = T1_INV[Int((t[1] >> 8) & 0xFF)]
             let b22 = T2_INV[Int((t[0] >> 16) & 0xFF)]
             let b22 = T2_INV[Int((t[0] >> 16) & 0xFF)]
             let b23 = T3_INV[Int(t[3] >> 24)]
             let b23 = T3_INV[Int(t[3] >> 24)]
             b[2] = b20 ^ b21 ^ b22 ^ b23
             b[2] = b20 ^ b21 ^ b22 ^ b23
-            
+
             let b30 = T0_INV[Int(t[3] & 0xFF)]
             let b30 = T0_INV[Int(t[3] & 0xFF)]
             let b31 = T1_INV[Int((t[2] >> 8) & 0xFF)]
             let b31 = T1_INV[Int((t[2] >> 8) & 0xFF)]
             let b32 = T2_INV[Int((t[1] >> 16) & 0xFF)]
             let b32 = T2_INV[Int((t[1] >> 16) & 0xFF)]
             let b33 = T3_INV[Int(t[0] >> 24)]
             let b33 = T3_INV[Int(t[0] >> 24)]
             b[3] = b30 ^ b31 ^ b32 ^ b33
             b[3] = b30 ^ b31 ^ b32 ^ b33
         }
         }
-        
+
         // last round
         // last round
         t[0] = b[0] ^ rk[1][0]
         t[0] = b[0] ^ rk[1][0]
         t[1] = b[1] ^ rk[1][1]
         t[1] = b[1] ^ rk[1][1]
         t[2] = b[2] ^ rk[1][2]
         t[2] = b[2] ^ rk[1][2]
         t[3] = b[3] ^ rk[1][3]
         t[3] = b[3] ^ rk[1][3]
-        
+
         // rounds
         // rounds
-        
+
         let lb00 = sBoxInv[Int(B0(t[0]))]
         let lb00 = sBoxInv[Int(B0(t[0]))]
         let lb01 = (sBoxInv[Int(B1(t[3]))] << 8)
         let lb01 = (sBoxInv[Int(B1(t[3]))] << 8)
         let lb02 = (sBoxInv[Int(B2(t[2]))] << 16)
         let lb02 = (sBoxInv[Int(B2(t[2]))] << 16)
         let lb03 = (sBoxInv[Int(B3(t[1]))] << 24)
         let lb03 = (sBoxInv[Int(B3(t[1]))] << 24)
         b[0] = lb00 | lb01 | lb02 | lb03 ^ rk[0][0]
         b[0] = lb00 | lb01 | lb02 | lb03 ^ rk[0][0]
-        
+
         let lb10 = sBoxInv[Int(B0(t[1]))]
         let lb10 = sBoxInv[Int(B0(t[1]))]
         let lb11 = (sBoxInv[Int(B1(t[0]))] << 8)
         let lb11 = (sBoxInv[Int(B1(t[0]))] << 8)
         let lb12 = (sBoxInv[Int(B2(t[3]))] << 16)
         let lb12 = (sBoxInv[Int(B2(t[3]))] << 16)
         let lb13 = (sBoxInv[Int(B3(t[2]))] << 24)
         let lb13 = (sBoxInv[Int(B3(t[2]))] << 24)
         b[1] = lb10 | lb11 | lb12 | lb13 ^ rk[0][1]
         b[1] = lb10 | lb11 | lb12 | lb13 ^ rk[0][1]
-        
+
         let lb20 = sBoxInv[Int(B0(t[2]))]
         let lb20 = sBoxInv[Int(B0(t[2]))]
         let lb21 = (sBoxInv[Int(B1(t[1]))] << 8)
         let lb21 = (sBoxInv[Int(B1(t[1]))] << 8)
         let lb22 = (sBoxInv[Int(B2(t[0]))] << 16)
         let lb22 = (sBoxInv[Int(B2(t[0]))] << 16)
         let lb23 = (sBoxInv[Int(B3(t[3]))] << 24)
         let lb23 = (sBoxInv[Int(B3(t[3]))] << 24)
         b[2] = lb20 | lb21 | lb22 | lb23 ^ rk[0][2]
         b[2] = lb20 | lb21 | lb22 | lb23 ^ rk[0][2]
-        
+
         let lb30 = sBoxInv[Int(B0(t[3]))]
         let lb30 = sBoxInv[Int(B0(t[3]))]
         let lb31 = (sBoxInv[Int(B1(t[2]))] << 8)
         let lb31 = (sBoxInv[Int(B1(t[2]))] << 8)
         let lb32 = (sBoxInv[Int(B2(t[1]))] << 16)
         let lb32 = (sBoxInv[Int(B2(t[1]))] << 16)
         let lb33 = (sBoxInv[Int(B3(t[0]))] << 24)
         let lb33 = (sBoxInv[Int(B3(t[0]))] << 24)
         b[3] = lb30 | lb31 | lb32 | lb33 ^ rk[0][3]
         b[3] = lb30 | lb31 | lb32 | lb33 ^ rk[0][3]
-        
+
         var out = [UInt8]()
         var out = [UInt8]()
         out.reserveCapacity(b.count * 4)
         out.reserveCapacity(b.count * 4)
         for num in b {
         for num in b {
@@ -346,35 +293,35 @@ final public class AES: BlockCipher {
             out.append(UInt8((num >> 16) & 0xFF))
             out.append(UInt8((num >> 16) & 0xFF))
             out.append(UInt8((num >> 24) & 0xFF))
             out.append(UInt8((num >> 24) & 0xFF))
         }
         }
-        
+
         return out
         return out
     }
     }
-    
+
     private func expandKeyInv(key: Key, variant: AESVariant) -> [[UInt32]] {
     private func expandKeyInv(key: Key, variant: AESVariant) -> [[UInt32]] {
         let rounds = variant.Nr
         let rounds = variant.Nr
         var rk2:[[UInt32]] = expandKey(key, variant: variant)
         var rk2:[[UInt32]] = expandKey(key, variant: variant)
-        
+
         for r in 1..<rounds {
         for r in 1..<rounds {
             var w:UInt32
             var w:UInt32
-            
+
             w = rk2[r][0];
             w = rk2[r][0];
             rk2[r][0] = U1[Int(B0(w))] ^ U2[Int(B1(w))] ^ U3[Int(B2(w))] ^ U4[Int(B3(w))]
             rk2[r][0] = U1[Int(B0(w))] ^ U2[Int(B1(w))] ^ U3[Int(B2(w))] ^ U4[Int(B3(w))]
-            
+
             w = rk2[r][1];
             w = rk2[r][1];
             rk2[r][1] = U1[Int(B0(w))] ^ U2[Int(B1(w))] ^ U3[Int(B2(w))] ^ U4[Int(B3(w))]
             rk2[r][1] = U1[Int(B0(w))] ^ U2[Int(B1(w))] ^ U3[Int(B2(w))] ^ U4[Int(B3(w))]
-            
+
             w = rk2[r][2];
             w = rk2[r][2];
             rk2[r][2] = U1[Int(B0(w))] ^ U2[Int(B1(w))] ^ U3[Int(B2(w))] ^ U4[Int(B3(w))]
             rk2[r][2] = U1[Int(B0(w))] ^ U2[Int(B1(w))] ^ U3[Int(B2(w))] ^ U4[Int(B3(w))]
-            
+
             w = rk2[r][3];
             w = rk2[r][3];
             rk2[r][3] = U1[Int(B0(w))] ^ U2[Int(B1(w))] ^ U3[Int(B2(w))] ^ U4[Int(B3(w))]
             rk2[r][3] = U1[Int(B0(w))] ^ U2[Int(B1(w))] ^ U3[Int(B2(w))] ^ U4[Int(B3(w))]
         }
         }
-        
+
         return rk2
         return rk2
     }
     }
-    
+
     private func expandKey(key:Key, variant:AESVariant) -> [[UInt32]] {
     private func expandKey(key:Key, variant:AESVariant) -> [[UInt32]] {
-        
+
         func convertExpandedKey(expanded:[UInt8]) -> [[UInt32]] {
         func convertExpandedKey(expanded:[UInt8]) -> [[UInt32]] {
             var arr = [UInt32]()
             var arr = [UInt32]()
             for idx in expanded.startIndex.stride(to: expanded.endIndex, by: 4) {
             for idx in expanded.startIndex.stride(to: expanded.endIndex, by: 4) {
@@ -382,19 +329,19 @@ final public class AES: BlockCipher {
                 let num = UInt32.withBytes(four)
                 let num = UInt32.withBytes(four)
                 arr.append(num)
                 arr.append(num)
             }
             }
-            
+
             var allarr = [[UInt32]]()
             var allarr = [[UInt32]]()
             for idx in arr.startIndex.stride(to: arr.endIndex, by: 4) {
             for idx in arr.startIndex.stride(to: arr.endIndex, by: 4) {
                 allarr.append(Array(arr[idx..<idx.advancedBy(4)]))
                 allarr.append(Array(arr[idx..<idx.advancedBy(4)]))
             }
             }
             return allarr
             return allarr
         }
         }
-        
+
         /*
         /*
-        * Function used in the Key Expansion routine that takes a four-byte
-        * input word and applies an S-box to each of the four bytes to
-        * produce an output word.
-        */
+         * Function used in the Key Expansion routine that takes a four-byte
+         * input word and applies an S-box to each of the four bytes to
+         * produce an output word.
+         */
         func subWord(word:[UInt8]) -> [UInt8] {
         func subWord(word:[UInt8]) -> [UInt8] {
             var result = word
             var result = word
             for i in 0..<4 {
             for i in 0..<4 {
@@ -402,19 +349,19 @@ final public class AES: BlockCipher {
             }
             }
             return result
             return result
         }
         }
-        
+
         var w = [UInt8](count: variant.Nb * (variant.Nr + 1) * 4, repeatedValue: 0)
         var w = [UInt8](count: variant.Nb * (variant.Nr + 1) * 4, repeatedValue: 0)
         for i in 0..<variant.Nk {
         for i in 0..<variant.Nk {
             for wordIdx in 0..<4 {
             for wordIdx in 0..<4 {
                 w[(4*i)+wordIdx] = key[(4*i)+wordIdx]
                 w[(4*i)+wordIdx] = key[(4*i)+wordIdx]
             }
             }
         }
         }
-        
+
         var tmp:[UInt8]
         var tmp:[UInt8]
 
 
         for i in variant.Nk..<variant.Nb * (variant.Nr + 1) {
         for i in variant.Nk..<variant.Nb * (variant.Nr + 1) {
             tmp = [UInt8](count: 4, repeatedValue: 0)
             tmp = [UInt8](count: 4, repeatedValue: 0)
-            
+
             for wordIdx in 0..<4 {
             for wordIdx in 0..<4 {
                 tmp[wordIdx] = w[4*(i-1)+wordIdx]
                 tmp[wordIdx] = w[4*(i-1)+wordIdx]
             }
             }
@@ -424,7 +371,7 @@ final public class AES: BlockCipher {
             } else if (variant.Nk > 6 && (i % variant.Nk) == 4) {
             } else if (variant.Nk > 6 && (i % variant.Nk) == 4) {
                 tmp = subWord(tmp)
                 tmp = subWord(tmp)
             }
             }
-            
+
             // xor array of bytes
             // xor array of bytes
             for wordIdx in 0..<4 {
             for wordIdx in 0..<4 {
                 w[4*i+wordIdx] = w[4*(i-variant.Nk)+wordIdx]^tmp[wordIdx];
                 w[4*i+wordIdx] = w[4*(i-variant.Nk)+wordIdx]^tmp[wordIdx];
@@ -432,10 +379,7 @@ final public class AES: BlockCipher {
         }
         }
         return convertExpandedKey(w)
         return convertExpandedKey(w)
     }
     }
-}
 
 
-extension AES {
-    
     private func B0(x: UInt32) -> UInt32 {
     private func B0(x: UInt32) -> UInt32 {
         return x & 0xFF
         return x & 0xFF
     }
     }
@@ -485,8 +429,69 @@ extension AES {
     }
     }
 }
 }
 
 
+// MARK: Encryptor
+extension AES {
+    public struct Encryptor: Cryptor {
+        private var worker: BlockModeWorker
+        let padding: Padding
+
+        init(aes: AES) {
+            self.padding = aes.padding;
+            self.worker = aes.cipherBlockMode.worker(aes.iv, cipherOperation: aes.encryptBlock)
+        }
+
+        mutating public func update(bytes:[UInt8], isLast: Bool) throws -> [UInt8] {
+            if isLast {
+                let paddedBytes = padding.add(bytes, blockSize: AES.blockSize)
+                var result = [UInt8]()
+                for chunk in paddedBytes.chunks(AES.blockSize) ?? [] {
+                    result.appendContentsOf(worker.encrypt(chunk))
+                }
+                return result
+            }
+
+            return worker.encrypt(bytes)
+        }
+    }
+}
+
+// MARK: Decryptor
+extension AES {
+    public struct Decryptor: Cryptor {
+        private var worker: BlockModeWorker
+        let padding: Padding
+
+        init(aes: AES) {
+            self.padding = aes.padding;
+
+            switch (aes.cipherBlockMode) {
+            case .CFB, .OFB, .CTR:
+                // CFB, OFB, CTR uses encryptBlock to decrypt
+                self.worker = aes.cipherBlockMode.worker(aes.iv, cipherOperation: aes.encryptBlock)
+            default:
+                self.worker = aes.cipherBlockMode.worker(aes.iv, cipherOperation: aes.decryptBlock)
+            }
+        }
+
+        mutating public func update(bytes:[UInt8], isLast: Bool) throws -> [UInt8] {
+            let plaintext = worker.decrypt(bytes)
+            if isLast {
+                return padding.remove(plaintext, blockSize: AES.blockSize)
+            }
+            return plaintext
+        }
+    }
+}
+
+// MARK: CipherProtocol
 extension AES: CipherProtocol {
 extension AES: CipherProtocol {
-    // MARK: - Cipher
+    public func encryptor() -> Cryptor {
+        return Encryptor(aes: self)
+    }
+
+    public func decryptor() -> Cryptor {
+        return Decryptor(aes: self)
+    }
     
     
     public func cipherEncrypt(bytes:[UInt8]) throws -> [UInt8] {
     public func cipherEncrypt(bytes:[UInt8]) throws -> [UInt8] {
         return try self.encrypt(bytes)
         return try self.encrypt(bytes)

+ 39 - 1
Sources/CryptoSwift/ChaCha20.swift

@@ -174,9 +174,46 @@ final public class ChaCha20: BlockCipher {
     }
     }
 }
 }
 
 
+extension ChaCha20 {
+    public class Encryptor: Cryptor {
+        let chacha20: ChaCha20
+
+        init(chacha20: ChaCha20) {
+            self.chacha20 = chacha20
+        }
+
+        public func update(bytes: [UInt8], isLast: Bool) throws -> [UInt8] {
+            return try chacha20.encrypt(bytes)
+        }
+    }
+}
+
+extension ChaCha20 {
+    public class Decryptor: Cryptor {
+        let chacha20: ChaCha20
+
+        init(chacha20: ChaCha20) {
+            self.chacha20 = chacha20
+        }
+
+        public func update(bytes: [UInt8], isLast: Bool) throws -> [UInt8] {
+            return try chacha20.decrypt(bytes)
+        }
+    }
+}
+
 // MARK: - Cipher
 // MARK: - Cipher
 
 
 extension ChaCha20: CipherProtocol {
 extension ChaCha20: CipherProtocol {
+
+    public func encryptor() -> Cryptor {
+        return Encryptor(chacha20: self)
+    }
+
+    public func decryptor() -> Cryptor {
+        return Decryptor(chacha20: self)
+    }
+
     public func cipherEncrypt(bytes:[UInt8]) throws -> [UInt8] {
     public func cipherEncrypt(bytes:[UInt8]) throws -> [UInt8] {
         return try self.encrypt(bytes)
         return try self.encrypt(bytes)
     }
     }
@@ -196,5 +233,6 @@ private func wordNumber(bytes:ArraySlice<UInt8>) -> UInt32 {
         value = value | UInt32(bytes[j]) << (8 * i)
         value = value | UInt32(bytes[j]) << (8 * i)
     }
     }
 
 
-    return value}
+    return value
+}
 
 

+ 4 - 0
Sources/CryptoSwift/CipherProtocol.swift

@@ -18,6 +18,10 @@ public enum CipherError: ErrorType {
 }
 }
 
 
 public protocol CipherProtocol {
 public protocol CipherProtocol {
+
+    func encryptor() -> Cryptor;
+    func decryptor() -> Cryptor;
+
     func cipherEncrypt(bytes: [UInt8]) throws -> [UInt8]
     func cipherEncrypt(bytes: [UInt8]) throws -> [UInt8]
     func cipherDecrypt(bytes: [UInt8]) throws -> [UInt8]
     func cipherDecrypt(bytes: [UInt8]) throws -> [UInt8]
     
     

+ 11 - 0
Sources/CryptoSwift/Cryptor.swift

@@ -0,0 +1,11 @@
+//
+//  Cryptor.swift
+//  CryptoSwift
+//
+//  Created by Marcin Krzyzanowski on 06/05/16.
+//  Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
+//
+
+public protocol Cryptor {
+    mutating func update(bytes:[UInt8], isLast: Bool) throws -> [UInt8]
+}

+ 37 - 1
Sources/CryptoSwift/Rabbit.swift

@@ -199,10 +199,46 @@ final public class Rabbit: BlockCipher {
     }
     }
 }
 }
 
 
+extension Rabbit {
+    public class Encryptor: Cryptor {
+        let rabbit: Rabbit
 
 
-// MARK: - CipherType
+        init(rabbit: Rabbit) {
+            self.rabbit = rabbit
+        }
+
+        public func update(bytes: [UInt8], isLast: Bool) throws -> [UInt8] {
+            return rabbit.encrypt(bytes)
+        }
+    }
+}
+
+extension Rabbit {
+    public class Decryptor: Cryptor {
+        let rabbit: Rabbit
+
+        init(rabbit: Rabbit) {
+            self.rabbit = rabbit
+        }
+
+        public func update(bytes: [UInt8], isLast: Bool) throws -> [UInt8] {
+            return rabbit.decrypt(bytes)
+        }
+    }
+}
 
 
+
+// MARK: CipherType
 extension Rabbit: CipherProtocol {
 extension Rabbit: CipherProtocol {
+
+    public func encryptor() -> Cryptor {
+        return Encryptor(rabbit: self)
+    }
+
+    public func decryptor() -> Cryptor {
+        return Decryptor(rabbit: self)
+    }
+    
     public func cipherEncrypt(bytes:[UInt8]) -> [UInt8] {
     public func cipherEncrypt(bytes:[UInt8]) -> [UInt8] {
         return self.encrypt(bytes)
         return self.encrypt(bytes)
     }
     }