Browse Source

Separate AES.Cryptors.
More ArraySlice in the internal interface.
Minor refactoring.

Marcin Krzyżanowski 7 years ago
parent
commit
1caafb35f8

+ 8 - 0
CryptoSwift.xcodeproj/project.pbxproj

@@ -11,6 +11,7 @@
 		750509991F6BEF2A00394A1B /* PKCS7.swift in Sources */ = {isa = PBXBuildFile; fileRef = 750509981F6BEF2A00394A1B /* PKCS7.swift */; };
 		750CC3EB1DC0CACE0096BE6E /* BlowfishTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 750CC3EA1DC0CACE0096BE6E /* BlowfishTests.swift */; };
 		75100F8F19B0BC890005C5F5 /* Poly1305Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75100F8E19B0BC890005C5F5 /* Poly1305Tests.swift */; };
+		751EE9781F93996100161FFC /* AES.Cryptors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 751EE9771F93996100161FFC /* AES.Cryptors.swift */; };
 		753B33011DAB84D600D06422 /* RandomBytesSequenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753B33001DAB84D600D06422 /* RandomBytesSequenceTests.swift */; };
 		75482EA41CB310B7001F66A5 /* PBKDF.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75482EA31CB310B7001F66A5 /* PBKDF.swift */; };
 		754BE46819693E190098E6F3 /* DigestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754BE46719693E190098E6F3 /* DigestTests.swift */; };
@@ -156,6 +157,7 @@
 		750509981F6BEF2A00394A1B /* PKCS7.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PKCS7.swift; sourceTree = "<group>"; };
 		750CC3EA1DC0CACE0096BE6E /* BlowfishTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlowfishTests.swift; sourceTree = "<group>"; };
 		75100F8E19B0BC890005C5F5 /* Poly1305Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Poly1305Tests.swift; sourceTree = "<group>"; };
+		751EE9771F93996100161FFC /* AES.Cryptors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AES.Cryptors.swift; sourceTree = "<group>"; };
 		753B33001DAB84D600D06422 /* RandomBytesSequenceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RandomBytesSequenceTests.swift; sourceTree = "<group>"; };
 		75482EA31CB310B7001F66A5 /* PBKDF.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBKDF.swift; sourceTree = "<group>"; };
 		754BE45519693E190098E6F3 /* CryptoSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CryptoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -327,6 +329,7 @@
 			isa = PBXGroup;
 			children = (
 				75EC52381EE8B6CA0048EB3B /* AES.swift */,
+				751EE9771F93996100161FFC /* AES.Cryptors.swift */,
 				75EC52391EE8B6CA0048EB3B /* Array+Extension.swift */,
 				75EC523A1EE8B6CA0048EB3B /* Authenticator.swift */,
 				75EC523B1EE8B6CA0048EB3B /* BatchedCollection.swift */,
@@ -578,6 +581,7 @@
 				75EC52891EE8B8170048EB3B /* OFB.swift in Sources */,
 				75EC52831EE8B8170048EB3B /* BlockModeOptions.swift in Sources */,
 				75EC52961EE8B8200048EB3B /* Blowfish+Foundation.swift in Sources */,
+				751EE9781F93996100161FFC /* AES.Cryptors.swift in Sources */,
 				75EC528B1EE8B8170048EB3B /* RandomAccessBlockModeWorker.swift in Sources */,
 				75EC527D1EE8B8130048EB3B /* Array+Extension.swift in Sources */,
 				75EC52B31EE8B83D0048EB3B /* UInt16+Extension.swift in Sources */,
@@ -792,9 +796,11 @@
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				OTHER_SWIFT_FLAGS = "-Xfrontend -debug-time-function-bodies";
 				PRODUCT_BUNDLE_IDENTIFIER = com.krzyzanowskim.CryptoSwift;
 				PRODUCT_NAME = CryptoSwift;
 				SKIP_INSTALL = YES;
+				SWIFT_SWIFT3_OBJC_INFERENCE = Off;
 				SWIFT_VERSION = 4.0;
 				TVOS_DEPLOYMENT_TARGET = 9.0;
 				WATCHOS_DEPLOYMENT_TARGET = 2.0;
@@ -824,6 +830,7 @@
 				SWIFT_DISABLE_SAFETY_CHECKS = YES;
 				SWIFT_ENFORCE_EXCLUSIVE_ACCESS = "compile-time";
 				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				SWIFT_SWIFT3_OBJC_INFERENCE = Off;
 				SWIFT_VERSION = 4.0;
 				TVOS_DEPLOYMENT_TARGET = 9.0;
 				WATCHOS_DEPLOYMENT_TARGET = 2.0;
@@ -952,6 +959,7 @@
 				SWIFT_DISABLE_SAFETY_CHECKS = YES;
 				SWIFT_ENFORCE_EXCLUSIVE_ACCESS = "compile-time";
 				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				SWIFT_SWIFT3_OBJC_INFERENCE = Off;
 				SWIFT_VERSION = 4.0;
 				TVOS_DEPLOYMENT_TARGET = 9.0;
 				WATCHOS_DEPLOYMENT_TARGET = 2.0;

+ 143 - 0
Sources/CryptoSwift/AES.Cryptors.swift

@@ -0,0 +1,143 @@
+//
+//  AES.swift
+//  CryptoSwift
+//
+//  Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
+//  This software is provided 'as-is', without any express or implied warranty.
+//
+//  In no event will the authors be held liable for any damages arising from the use of this software.
+//
+//  Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+//  - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+//  - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+//  - This notice may not be removed or altered from any source or binary distribution.
+//
+
+// MARK: Cryptors
+extension AES: Cryptors {
+    public func makeEncryptor() -> AES.Encryptor {
+        return AES.Encryptor(aes: self)
+    }
+
+    public func makeDecryptor() -> AES.Decryptor {
+        return AES.Decryptor(aes: self)
+    }
+}
+
+
+// MARK: Encryptor
+extension AES {
+    public struct Encryptor: Updatable {
+        private var worker: BlockModeWorker
+        private let padding: Padding
+        private var accumulated = Array<UInt8>()
+        private var processedBytesTotalCount: Int = 0
+        private let paddingRequired: Bool
+
+        init(aes: AES) {
+            self.padding = aes.padding
+            self.worker = aes.blockMode.worker(aes.iv.slice, cipherOperation: aes.encrypt)
+            self.paddingRequired = aes.blockMode.options.contains(.paddingRequired)
+        }
+
+        public mutating func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = false) throws -> Array<UInt8> {
+            self.accumulated += bytes
+
+            if isLast {
+                self.accumulated = padding.add(to: self.accumulated, blockSize: AES.blockSize)
+            }
+
+            var processedBytes = 0
+            var encrypted = Array<UInt8>(reserveCapacity: self.accumulated.count)
+            for chunk in self.accumulated.batched(by: AES.blockSize) {
+                if isLast || (self.accumulated.count - processedBytes) >= AES.blockSize {
+                    encrypted += worker.encrypt(chunk)
+                    processedBytes += chunk.count
+                }
+            }
+            self.accumulated.removeFirst(processedBytes)
+            self.processedBytesTotalCount += processedBytes
+            return encrypted
+        }
+    }
+}
+
+// MARK: Decryptor
+extension AES {
+
+    public struct Decryptor: RandomAccessCryptor {
+        private var worker: BlockModeWorker
+        private let padding: Padding
+        private var accumulated = Array<UInt8>()
+        private var processedBytesTotalCount: Int = 0
+        private let paddingRequired: Bool
+
+        private var offset: Int = 0
+        private var offsetToRemove: Int = 0
+
+        init(aes: AES) {
+            self.padding = aes.padding
+
+            switch aes.blockMode {
+            case .CFB, .OFB, .CTR:
+                // CFB, OFB, CTR uses encryptBlock to decrypt
+                self.worker = aes.blockMode.worker(aes.iv.slice, cipherOperation: aes.encrypt)
+            default:
+                self.worker = aes.blockMode.worker(aes.iv.slice, cipherOperation: aes.decrypt)
+            }
+
+            self.paddingRequired = aes.blockMode.options.contains(.paddingRequired)
+        }
+
+        public mutating func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = false) throws -> Array<UInt8> {
+            // prepend "offset" number of bytes at the begining
+            if self.offset > 0 {
+                self.accumulated += Array<UInt8>(repeating: 0, count: offset) + bytes
+                self.offsetToRemove = offset
+                self.offset = 0
+            } else {
+                self.accumulated += bytes
+            }
+
+            var processedBytes = 0
+            var plaintext = Array<UInt8>(reserveCapacity: self.accumulated.count)
+            for chunk in self.accumulated.batched(by: AES.blockSize) {
+                if isLast || (self.accumulated.count - processedBytes) >= AES.blockSize {
+                    plaintext += self.worker.decrypt(chunk)
+
+                    // remove "offset" from the beginning of first chunk
+                    if self.offsetToRemove > 0 {
+                        plaintext.removeFirst(self.offsetToRemove)
+                        self.offsetToRemove = 0
+                    }
+
+                    processedBytes += chunk.count
+                }
+            }
+            self.accumulated.removeFirst(processedBytes)
+            self.processedBytesTotalCount += processedBytes
+
+            if isLast {
+                plaintext = padding.remove(from: plaintext, blockSize: AES.blockSize)
+            }
+
+            return plaintext
+        }
+
+        @discardableResult public mutating func seek(to position: Int) -> Bool {
+            guard var worker = self.worker as? RandomAccessBlockModeWorker else {
+                return false
+            }
+
+            worker.counter = UInt(position / AES.blockSize)
+            self.worker = worker
+
+            self.offset = position % AES.blockSize
+
+            self.accumulated = []
+
+            return true
+        }
+    }
+}

+ 35 - 161
Sources/CryptoSwift/AES.swift

@@ -17,8 +17,6 @@
 //  Implementation of Gladman algorithm http://www.gladman.me.uk/AES
 //
 
-private typealias Key = SecureBytes
-
 /// The Advanced Encryption Standard (AES)
 public final class AES: BlockCipher {
 
@@ -49,6 +47,10 @@ public final class AES: BlockCipher {
         }
     }
 
+    private lazy var variantNr: Int = self.variant.Nr
+    private lazy var variantNb: Int = self.variant.Nb
+    private lazy var variantNk: Int = self.variant.Nk
+
     public static let blockSize: Int = 16 // 128 /8
 
     public var variant: Variant {
@@ -65,10 +67,10 @@ public final class AES: BlockCipher {
     }
 
     // Parameters
-    private let blockMode: BlockMode
-    private let key: Key
-    private let iv: Array<UInt8>
-    private let padding: Padding
+    let key: Key
+    let blockMode: BlockMode
+    let iv: Array<UInt8>
+    let padding: Padding
 
     //
     private lazy var expandedKey: Array<Array<UInt32>> = self.expandKey(self.key, variant: self.variant)
@@ -141,18 +143,13 @@ public final class AES: BlockCipher {
             throw Error.invalidInitializationVector
         }
     }
-}
-
-// MARK: Private
-private extension AES {
-
-    func encrypt(block: ArraySlice<UInt8>) -> Array<UInt8>? {
 
+    internal func encrypt(block: ArraySlice<UInt8>) -> Array<UInt8>? {
         if blockMode.options.contains(.paddingRequired) && block.count != AES.blockSize {
             return Array(block)
         }
 
-        let rounds = variant.Nr
+        let rounds = variantNr
         let rk = expandedKey
 
         let b00 = UInt32(block[block.startIndex.advanced(by: 0)])
@@ -242,13 +239,12 @@ private extension AES {
         return encrypted
     }
 
-    func decrypt(block: ArraySlice<UInt8>) -> Array<UInt8>? {
-
+    internal func decrypt(block: ArraySlice<UInt8>) -> Array<UInt8>? {
         if blockMode.options.contains(.paddingRequired) && block.count != AES.blockSize {
             return Array(block)
         }
 
-        let rounds = variant.Nr
+        let rounds = variantNr
         let rk = expandedKeyInv
         var b = block.toUInt32Array()
 
@@ -332,9 +328,11 @@ private extension AES {
 
         return out
     }
+}
 
-    func expandKeyInv(_ key: Key, variant: Variant) -> Array<Array<UInt32>> {
-        let rounds = variant.Nr
+private extension AES {
+    private func expandKeyInv(_ key: Key, variant: Variant) -> Array<Array<UInt32>> {
+        let rounds = variantNr
         var rk2: Array<Array<UInt32>> = self.expandKey(key, variant: variant)
 
         for r in 1..<rounds {
@@ -351,7 +349,7 @@ private extension AES {
         return rk2
     }
 
-    func expandKey(_ key: Key, variant: Variant) -> Array<Array<UInt32>> {
+    private func expandKey(_ key: Key, variant: Variant) -> Array<Array<UInt32>> {
 
         func convertExpandedKey(_ expanded: Array<UInt8>) -> Array<Array<UInt32>> {
             return expanded.batched(by: 4).map({ UInt32(bytes: $0.reversed()) }).batched(by: 4).map({ Array($0) })
@@ -370,8 +368,8 @@ private extension AES {
             return result
         }
 
-        var w = Array<UInt8>(repeating: 0, count: variant.Nb * (variant.Nr + 1) * 4)
-        for i in 0..<variant.Nk {
+        var w = Array<UInt8>(repeating: 0, count: variantNb * (variantNr + 1) * 4)
+        for i in 0..<variantNk {
             for wordIdx in 0..<4 {
                 w[(4 * i) + wordIdx] = key[(4 * i) + wordIdx]
             }
@@ -379,44 +377,49 @@ private extension AES {
 
         var tmp: Array<UInt8>
 
-        for i in variant.Nk..<variant.Nb * (variant.Nr + 1) {
+        for i in variantNk..<variantNb * (variantNr + 1) {
             tmp = Array<UInt8>(repeating: 0, count: 4)
 
             for wordIdx in 0..<4 {
                 tmp[wordIdx] = w[4 * (i - 1) + wordIdx]
             }
-            if (i % variant.Nk) == 0 {
+            if (i % variantNk) == 0 {
                 tmp = subWord(rotateLeft(UInt32(bytes: tmp), by: 8).bytes(totalBytes: MemoryLayout<UInt32>.size))
-                tmp[0] = tmp.first! ^ AES.Rcon[i / variant.Nk]
-            } else if variant.Nk > 6 && (i % variant.Nk) == 4 {
+                tmp[0] = tmp.first! ^ AES.Rcon[i / variantNk]
+            } else if variantNk > 6 && (i % variantNk) == 4 {
                 tmp = subWord(tmp)
             }
 
             // xor array of bytes
             for wordIdx in 0..<4 {
-                w[4 * i + wordIdx] = w[4 * (i - variant.Nk) + wordIdx] ^ tmp[wordIdx]
+                w[4 * i + wordIdx] = w[4 * (i - variantNk) + wordIdx] ^ tmp[wordIdx]
             }
         }
         return convertExpandedKey(w)
     }
 
-    func B0(_ x: UInt32) -> UInt32 {
+    @inline(__always)
+    private func B0(_ x: UInt32) -> UInt32 {
         return x & 0xff
     }
 
-    func B1(_ x: UInt32) -> UInt32 {
+    @inline(__always)
+    private func B1(_ x: UInt32) -> UInt32 {
         return (x >> 8) & 0xff
     }
 
-    func B2(_ x: UInt32) -> UInt32 {
+    @inline(__always)
+    private func B2(_ x: UInt32) -> UInt32 {
         return (x >> 16) & 0xff
     }
 
-    func B3(_ x: UInt32) -> UInt32 {
+    @inline(__always)
+    private func B3(_ x: UInt32) -> UInt32 {
         return (x >> 24) & 0xff
     }
 
-    func F1(_ x0: UInt32, _ x1: UInt32, _ x2: UInt32, _ x3: UInt32) -> UInt32 {
+    @inline(__always)
+    private func F1(_ x0: UInt32, _ x1: UInt32, _ x2: UInt32, _ x3: UInt32) -> UInt32 {
         var result: UInt32 = 0
         result |= UInt32(B1(AES.T0[Int(x0 & 255)]))
         result |= UInt32(B1(AES.T0[Int((x1 >> 8) & 255)])) << 8
@@ -425,7 +428,7 @@ private extension AES {
         return result
     }
 
-    func calculateSBox() -> (sBox: Array<UInt32>, invSBox: Array<UInt32>) {
+    private func calculateSBox() -> (sBox: Array<UInt32>, invSBox: Array<UInt32>) {
         var sbox = Array<UInt32>(repeating: 0, count: 256)
         var invsbox = sbox
         sbox[0] = 0x63
@@ -449,135 +452,6 @@ private extension AES {
     }
 }
 
-// MARK: Encryptor
-extension AES {
-
-    public struct Encryptor: Updatable {
-        private var worker: BlockModeWorker
-        private let padding: Padding
-        private var accumulated = Array<UInt8>()
-        private var processedBytesTotalCount: Int = 0
-        private let paddingRequired: Bool
-
-        init(aes: AES) {
-            self.padding = aes.padding
-            self.worker = aes.blockMode.worker(aes.iv, cipherOperation: aes.encrypt)
-            self.paddingRequired = aes.blockMode.options.contains(.paddingRequired)
-        }
-
-        public mutating func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = false) throws -> Array<UInt8> {
-            self.accumulated += bytes
-
-            if isLast {
-                self.accumulated = padding.add(to: self.accumulated, blockSize: AES.blockSize)
-            }
-
-            var processedBytes = 0
-            var encrypted = Array<UInt8>(reserveCapacity: self.accumulated.count)
-            for chunk in self.accumulated.batched(by: AES.blockSize) {
-                if isLast || (self.accumulated.count - processedBytes) >= AES.blockSize {
-                    encrypted += worker.encrypt(chunk)
-                    processedBytes += chunk.count
-                }
-            }
-            self.accumulated.removeFirst(processedBytes)
-            self.processedBytesTotalCount += processedBytes
-            return encrypted
-        }
-    }
-}
-
-// MARK: Decryptor
-extension AES {
-
-    public struct Decryptor: RandomAccessCryptor {
-        private var worker: BlockModeWorker
-        private let padding: Padding
-        private var accumulated = Array<UInt8>()
-        private var processedBytesTotalCount: Int = 0
-        private let paddingRequired: Bool
-
-        private var offset: Int = 0
-        private var offsetToRemove: Int = 0
-
-        init(aes: AES) {
-            self.padding = aes.padding
-
-            switch aes.blockMode {
-            case .CFB, .OFB, .CTR:
-                // CFB, OFB, CTR uses encryptBlock to decrypt
-                self.worker = aes.blockMode.worker(aes.iv, cipherOperation: aes.encrypt)
-            default:
-                self.worker = aes.blockMode.worker(aes.iv, cipherOperation: aes.decrypt)
-            }
-
-            self.paddingRequired = aes.blockMode.options.contains(.paddingRequired)
-        }
-
-        public mutating func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = false) throws -> Array<UInt8> {
-            // prepend "offset" number of bytes at the begining
-            if self.offset > 0 {
-                self.accumulated += Array<UInt8>(repeating: 0, count: offset) + bytes
-                self.offsetToRemove = offset
-                self.offset = 0
-            } else {
-                self.accumulated += bytes
-            }
-
-            var processedBytes = 0
-            var plaintext = Array<UInt8>(reserveCapacity: self.accumulated.count)
-            for chunk in self.accumulated.batched(by: AES.blockSize) {
-                if isLast || (self.accumulated.count - processedBytes) >= AES.blockSize {
-                    plaintext += self.worker.decrypt(chunk)
-
-                    // remove "offset" from the beginning of first chunk
-                    if self.offsetToRemove > 0 {
-                        plaintext.removeFirst(self.offsetToRemove)
-                        self.offsetToRemove = 0
-                    }
-
-                    processedBytes += chunk.count
-                }
-            }
-            self.accumulated.removeFirst(processedBytes)
-            self.processedBytesTotalCount += processedBytes
-
-            if isLast {
-                plaintext = padding.remove(from: plaintext, blockSize: AES.blockSize)
-            }
-
-            return plaintext
-        }
-
-        @discardableResult public mutating func seek(to position: Int) -> Bool {
-            guard var worker = self.worker as? RandomAccessBlockModeWorker else {
-                return false
-            }
-
-            worker.counter = UInt(position / AES.blockSize)
-            self.worker = worker
-
-            self.offset = position % AES.blockSize
-
-            self.accumulated = []
-
-            return true
-        }
-    }
-}
-
-// MARK: Cryptors
-extension AES: Cryptors {
-
-    public func makeEncryptor() -> AES.Encryptor {
-        return Encryptor(aes: self)
-    }
-
-    public func makeDecryptor() -> AES.Decryptor {
-        return Decryptor(aes: self)
-    }
-}
-
 // MARK: Cipher
 extension AES: Cipher {
 

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

@@ -19,7 +19,7 @@ typealias CipherOperationOnBlock = (_ block: ArraySlice<UInt8>) -> Array<UInt8>?
 public enum BlockMode {
     case ECB, CBC, PCBC, CFB, OFB, CTR
 
-    func worker(_ iv: Array<UInt8>?, cipherOperation: @escaping CipherOperationOnBlock) -> BlockModeWorker {
+    func worker(_ iv: ArraySlice<UInt8>?, cipherOperation: @escaping CipherOperationOnBlock) -> BlockModeWorker {
         switch self {
         case .ECB:
             return ECBModeWorker(iv: iv ?? [], cipherOperation: cipherOperation)

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

@@ -22,8 +22,8 @@ struct CBCModeWorker: BlockModeWorker {
     private let iv: ArraySlice<UInt8>
     private var prev: ArraySlice<UInt8>?
 
-    init(iv: Array<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
-        self.iv = iv.slice
+    init(iv: ArraySlice<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
+        self.iv = iv
         self.cipherOperation = cipherOperation
     }
 

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

@@ -22,8 +22,8 @@ struct CFBModeWorker: BlockModeWorker {
     private let iv: ArraySlice<UInt8>
     private var prev: ArraySlice<UInt8>?
 
-    init(iv: Array<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
-        self.iv = iv.slice
+    init(iv: ArraySlice<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
+        self.iv = iv
         self.cipherOperation = cipherOperation
     }
 

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

@@ -22,8 +22,8 @@ struct CTRModeWorker: RandomAccessBlockModeWorker {
     private let iv: ArraySlice<UInt8>
     var counter: UInt = 0
 
-    init(iv: Array<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
-        self.iv = iv.slice
+    init(iv: ArraySlice<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
+        self.iv = iv
         self.cipherOperation = cipherOperation
     }
 

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

@@ -21,7 +21,7 @@ struct ECBModeWorker: BlockModeWorker {
     typealias Element = Array<UInt8>
     let cipherOperation: CipherOperationOnBlock
 
-    init(iv _: Array<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
+    init(iv _: ArraySlice<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
         self.cipherOperation = cipherOperation
     }
 

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

@@ -19,16 +19,16 @@
 
 struct OFBModeWorker: BlockModeWorker {
     let cipherOperation: CipherOperationOnBlock
-    private let iv: Array<UInt8>
+    private let iv: ArraySlice<UInt8>
     private var prev: ArraySlice<UInt8>?
 
-    init(iv: Array<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
+    init(iv: ArraySlice<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
         self.iv = iv
         self.cipherOperation = cipherOperation
     }
 
     mutating func encrypt(_ plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
-        guard let ciphertext = cipherOperation(prev ?? iv.slice) else {
+        guard let ciphertext = cipherOperation(prev ?? iv) else {
             return Array(plaintext)
         }
         prev = ciphertext.slice
@@ -36,7 +36,7 @@ struct OFBModeWorker: BlockModeWorker {
     }
 
     mutating func decrypt(_ ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
-        guard let decrypted = cipherOperation(prev ?? iv.slice) else {
+        guard let decrypted = cipherOperation(prev ?? iv) else {
             return Array(ciphertext)
         }
         let plaintext: Array<UInt8> = xor(decrypted, ciphertext)

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

@@ -22,8 +22,8 @@ struct PCBCModeWorker: BlockModeWorker {
     private let iv: ArraySlice<UInt8>
     private var prev: ArraySlice<UInt8>?
 
-    init(iv: Array<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
-        self.iv = iv.slice
+    init(iv: ArraySlice<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
+        self.iv = iv
         self.cipherOperation = cipherOperation
     }
 

+ 3 - 3
Sources/CryptoSwift/Blowfish.swift

@@ -36,14 +36,14 @@ public final class Blowfish {
     fileprivate lazy var decryptWorker: BlockModeWorker = {
         switch self.blockMode {
         case .CFB, .OFB, .CTR:
-            return self.blockMode.worker(self.iv, cipherOperation: self.encrypt)
+            return self.blockMode.worker(self.iv.slice, cipherOperation: self.encrypt)
         default:
-            return self.blockMode.worker(self.iv, cipherOperation: self.decrypt)
+            return self.blockMode.worker(self.iv.slice, cipherOperation: self.decrypt)
         }
     }()
 
     fileprivate lazy var encryptWorker: BlockModeWorker = {
-        self.blockMode.worker(self.iv, cipherOperation: self.encrypt)
+        self.blockMode.worker(self.iv.slice, cipherOperation: self.encrypt)
     }()
 
     private let N = 16 // rounds

+ 0 - 2
Sources/CryptoSwift/ChaCha20.swift

@@ -17,8 +17,6 @@
 //  https://tools.ietf.org/html/rfc7539
 //
 
-private typealias Key = SecureBytes
-
 public final class ChaCha20: BlockCipher {
 
     public enum Error: Swift.Error {

+ 0 - 2
Sources/CryptoSwift/Rabbit.swift

@@ -14,8 +14,6 @@
 //  - This notice may not be removed or altered from any source or binary distribution.
 //
 
-private typealias Key = SecureBytes
-
 public final class Rabbit: BlockCipher {
 
     public enum Error: Swift.Error {

+ 2 - 0
Sources/CryptoSwift/SecureBytes.swift

@@ -20,6 +20,8 @@
     import Darwin
 #endif
 
+typealias Key = SecureBytes
+
 ///  Keeps bytes in memory. Because this is class, bytes are not copied
 ///  and memory area is locked as long as referenced, then unlocked on deinit
 final class SecureBytes {