Эх сурвалжийг харах

BlockMode takes IV parameter when needed (and do the validation).
AES init no longer gets IV as separate parameter

Marcin Krzyżanowski 7 жил өмнө
parent
commit
ac8f669212

+ 6 - 6
README.md

@@ -312,8 +312,8 @@ let decrypted = try Rabbit(key: key, iv: iv).decrypt(encrypted)
 ##### Blowfish
 
 ```swift
-let encrypted = try Blowfish(key: key, iv: iv, blockMode: .CBC, padding: .pkcs7).encrypt(message)
-let decrypted = try Blowfish(key: key, iv: iv, blockMode: .CBC, padding: .pkcs7).decrypt(encrypted)
+let encrypted = try Blowfish(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7).encrypt(message)
+let decrypted = try Blowfish(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7).decrypt(encrypted)
 ```
 
 ##### AES
@@ -328,7 +328,7 @@ Variant of AES encryption (AES-128, AES-192, AES-256) depends on given key lengt
 
 AES-256 example
 ```swift
-try AES(key: [1,2,3,...,32], iv: [1,2,3,...,16], blockMode: .CBC, padding: .pkcs7)
+try AES(key: [1,2,3,...,32], blockMode: .CBC(iv: [1,2,3,...,16]), padding: .pkcs7)
 ```
  
 ###### All at once
@@ -371,8 +371,8 @@ let key: Array<UInt8> = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 let iv: Array<UInt8> = AES.randomIV(AES.blockSize)
 
 do {
-    let encrypted = try AES(key: key, iv: iv, blockMode: .CBC, padding: .pkcs7).encrypt(input)
-    let decrypted = try AES(key: key, iv: iv, blockMode: .CBC, padding: .pkcs7).decrypt(encrypted)
+    let encrypted = try AES(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7).encrypt(input)
+    let decrypted = try AES(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7).decrypt(encrypted)
 } catch {
     print(error)
 }    
@@ -382,7 +382,7 @@ AES without data padding
 
 ```swift
 let input: Array<UInt8> = [0,1,2,3,4,5,6,7,8,9]
-let encrypted: Array<UInt8> = try! AES(key: "secret0key000000", iv:"0123456789012345", blockMode: .CBC, padding: .noPadding).encrypt(input)
+let encrypted: Array<UInt8> = try! AES(key: Array("secret0key000000".utf8), blockMode: .CBC(iv: Array("0123456789012345".utf8)), padding: .noPadding).encrypt(input)
 ```
 
 Using convenience extensions

+ 10 - 10
Sources/CryptoSwift/AES.Cryptors.swift

@@ -16,12 +16,12 @@
 
 // MARK: Cryptors
 extension AES: Cryptors {
-    public func makeEncryptor() -> AES.Encryptor {
-        return AES.Encryptor(aes: self)
+    public func makeEncryptor() throws -> AES.Encryptor {
+        return try AES.Encryptor(aes: self)
     }
 
-    public func makeDecryptor() -> AES.Decryptor {
-        return AES.Decryptor(aes: self)
+    public func makeDecryptor() throws -> AES.Decryptor {
+        return try AES.Decryptor(aes: self)
     }
 }
 
@@ -35,9 +35,9 @@ extension AES {
         private var processedBytesTotalCount: Int = 0
         private let paddingRequired: Bool
 
-        init(aes: AES) {
+        init(aes: AES) throws {
             self.padding = aes.padding
-            self.worker = aes.blockMode.worker(aes.iv.slice, cipherOperation: aes.encrypt)
+            self.worker = try aes.blockMode.worker(blockSize: AES.blockSize, cipherOperation: aes.encrypt)
             self.paddingRequired = aes.blockMode.options.contains(.paddingRequired)
         }
 
@@ -76,18 +76,18 @@ extension AES {
         private var offset: Int = 0
         private var offsetToRemove: Int = 0
 
-        init(aes: AES) {
+        init(aes: AES) throws {
             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)
+                self.worker = try aes.blockMode.worker(blockSize: AES.blockSize, cipherOperation: aes.encrypt)
             default:
-                self.worker = aes.blockMode.worker(aes.iv.slice, cipherOperation: aes.decrypt)
+                self.worker = try aes.blockMode.worker(blockSize: AES.blockSize, cipherOperation: aes.decrypt)
             }
 
-            self.paddingRequired = aes.blockMode.options.contains(.paddingRequired)
+            self.paddingRequired = try aes.blockMode.options.contains(.paddingRequired)
         }
 
         public mutating func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = false) throws -> Array<UInt8> {

+ 3 - 20
Sources/CryptoSwift/AES.swift

@@ -23,10 +23,6 @@ public final class AES: BlockCipher {
     public enum Error: Swift.Error {
         /// Data padding is required
         case dataPaddingRequired
-        /// Invalid key or IV
-        case invalidKeyOrInitializationVector
-        /// Invalid IV
-        case invalidInitializationVector
         /// Invalid Data
         case invalidData
     }
@@ -69,7 +65,6 @@ public final class AES: BlockCipher {
     // Parameters
     let key: Key
     let blockMode: BlockMode
-    let iv: Array<UInt8>
     let padding: Padding
 
     //
@@ -126,22 +121,10 @@ public final class AES: BlockCipher {
     /// - throws: AES.Error
     ///
     /// - returns: Instance
-    public init(key: Array<UInt8>, iv: Array<UInt8>? = nil, blockMode: BlockMode = .CBC, padding: Padding = .pkcs7) throws {
+    public init(key: Array<UInt8>, blockMode: BlockMode, padding: Padding = .pkcs7) throws {
         self.key = Key(bytes: key)
         self.blockMode = blockMode
         self.padding = padding
-
-        if let iv = iv, !iv.isEmpty {
-            self.iv = iv
-        } else {
-            let defaultIV = Array<UInt8>(repeating: 0, count: AES.blockSize)
-            self.iv = defaultIV
-        }
-
-        if blockMode.options.contains(.initializationVectorRequired) && self.iv.count != AES.blockSize {
-            assert(false, "Block size and Initialization Vector must be the same length!")
-            throw Error.invalidInitializationVector
-        }
     }
 
     internal func encrypt(block: ArraySlice<UInt8>) -> Array<UInt8>? {
@@ -458,7 +441,7 @@ extension AES: Cipher {
     public func encrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
         let chunks = bytes.batched(by: AES.blockSize)
 
-        var oneTimeCryptor = self.makeEncryptor()
+        var oneTimeCryptor = try self.makeEncryptor()
         var out = Array<UInt8>(reserveCapacity: bytes.count)
         for chunk in chunks {
             out += try oneTimeCryptor.update(withBytes: chunk, isLast: false)
@@ -478,7 +461,7 @@ extension AES: Cipher {
             throw Error.dataPaddingRequired
         }
 
-        var oneTimeCryptor = self.makeDecryptor()
+        var oneTimeCryptor = try self.makeDecryptor()
         let chunks = bytes.batched(by: AES.blockSize)
         if chunks.count == 0 {
             throw Error.invalidData

+ 36 - 13
Sources/CryptoSwift/BlockMode/BlockMode.swift

@@ -17,22 +17,44 @@
 typealias CipherOperationOnBlock = (_ block: ArraySlice<UInt8>) -> Array<UInt8>?
 
 public enum BlockMode {
-    case ECB, CBC, PCBC, CFB, OFB, CTR
+    case ECB, CBC(iv: Array<UInt8>), PCBC(iv: Array<UInt8>), CFB(iv: Array<UInt8>), OFB(iv: Array<UInt8>), CTR(iv: Array<UInt8>)
 
-    func worker(_ iv: ArraySlice<UInt8>?, cipherOperation: @escaping CipherOperationOnBlock) -> BlockModeWorker {
+    public enum Error: Swift.Error {
+        /// Invalid key or IV
+        case invalidKeyOrInitializationVector
+        /// Invalid IV
+        case invalidInitializationVector
+    }
+
+    func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) throws -> BlockModeWorker {
         switch self {
         case .ECB:
-            return ECBModeWorker(iv: iv ?? [], cipherOperation: cipherOperation)
-        case .CBC:
-            return CBCModeWorker(iv: iv ?? [], cipherOperation: cipherOperation)
-        case .PCBC:
-            return PCBCModeWorker(iv: iv ?? [], cipherOperation: cipherOperation)
-        case .CFB:
-            return CFBModeWorker(iv: iv ?? [], cipherOperation: cipherOperation)
-        case .OFB:
-            return OFBModeWorker(iv: iv ?? [], cipherOperation: cipherOperation)
-        case .CTR:
-            return CTRModeWorker(iv: iv ?? [], cipherOperation: cipherOperation)
+            return ECBModeWorker(cipherOperation: cipherOperation)
+        case .CBC(let iv):
+            if (iv.count != blockSize) {
+                throw Error.invalidInitializationVector
+            }
+            return CBCModeWorker(iv: iv.slice, cipherOperation: cipherOperation)
+        case .PCBC(let iv):
+            if (iv.count != blockSize) {
+                throw Error.invalidInitializationVector
+            }
+            return PCBCModeWorker(iv: iv.slice, cipherOperation: cipherOperation)
+        case .CFB(let iv):
+            if (iv.count != blockSize) {
+                throw Error.invalidInitializationVector
+            }
+            return CFBModeWorker(iv: iv.slice, cipherOperation: cipherOperation)
+        case .OFB(let iv):
+            if (iv.count != blockSize) {
+                throw Error.invalidInitializationVector
+            }
+            return OFBModeWorker(iv: iv.slice, cipherOperation: cipherOperation)
+        case .CTR(let iv):
+            if (iv.count != blockSize) {
+                throw Error.invalidInitializationVector
+            }
+            return CTRModeWorker(iv: iv.slice, cipherOperation: cipherOperation)
         }
     }
 
@@ -53,3 +75,4 @@ public enum BlockMode {
         }
     }
 }
+

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

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

+ 14 - 24
Sources/CryptoSwift/Blowfish.swift

@@ -30,21 +30,10 @@ public final class Blowfish {
     }
 
     public static let blockSize: Int = 8 // 64 bit
-    fileprivate let iv: Array<UInt8>
     fileprivate let blockMode: BlockMode
     fileprivate let padding: Padding
-    fileprivate lazy var decryptWorker: BlockModeWorker = {
-        switch self.blockMode {
-        case .CFB, .OFB, .CTR:
-            return self.blockMode.worker(self.iv.slice, cipherOperation: self.encrypt)
-        default:
-            return self.blockMode.worker(self.iv.slice, cipherOperation: self.decrypt)
-        }
-    }()
-
-    fileprivate lazy var encryptWorker: BlockModeWorker = {
-        self.blockMode.worker(self.iv.slice, cipherOperation: self.encrypt)
-    }()
+    private var decryptWorker: BlockModeWorker!
+    private var encryptWorker: BlockModeWorker!
 
     private let N = 16 // rounds
     private var P: Array<UInt32>
@@ -323,7 +312,7 @@ public final class Blowfish {
         ],
     ]
 
-    public init(key: Array<UInt8>, iv: Array<UInt8>? = nil, blockMode: BlockMode = .CBC, padding: Padding) throws {
+    public init(key: Array<UInt8>, iv: Array<UInt8>? = nil, blockMode: BlockMode = .CBC(iv: Array<UInt8>(repeating: 0, count: Blowfish.blockSize)), padding: Padding) throws {
         precondition(key.count >= 8 && key.count <= 56)
 
         self.blockMode = blockMode
@@ -332,18 +321,19 @@ public final class Blowfish {
         S = origS
         P = origP
 
-        if let iv = iv, !iv.isEmpty {
-            self.iv = iv
-        } else {
-            self.iv = Array<UInt8>(repeating: 0, count: Blowfish.blockSize)
-        }
+        expandKey(key: key)
+        try setupBlockModeWorkers()
+    }
 
-        if blockMode.options.contains(.initializationVectorRequired) && self.iv.count != Blowfish.blockSize {
-            assert(false, "Block size and Initialization Vector must be the same length!")
-            throw Error.invalidInitializationVector
-        }
+    private func setupBlockModeWorkers() throws {
+        encryptWorker = try self.blockMode.worker(blockSize: Blowfish.blockSize, cipherOperation: self.encrypt)
 
-        expandKey(key: key)
+        switch self.blockMode {
+            case .CFB, .OFB, .CTR:
+                decryptWorker = try self.blockMode.worker(blockSize: Blowfish.blockSize, cipherOperation: self.encrypt)
+            default:
+                decryptWorker = try self.blockMode.worker(blockSize: Blowfish.blockSize, cipherOperation: self.decrypt)
+        }
     }
 
     private func reset() {

+ 2 - 2
Sources/CryptoSwift/Cryptors.swift

@@ -26,10 +26,10 @@ public protocol Cryptors: class {
     associatedtype DecryptorType: Updatable
 
     /// Cryptor suitable for encryption
-    func makeEncryptor() -> EncryptorType
+    func makeEncryptor() throws -> EncryptorType
 
     /// Cryptor suitable for decryption
-    func makeDecryptor() -> DecryptorType
+    func makeDecryptor() throws -> DecryptorType
 
     /// Generate array of random bytes. Helper function.
     static func randomIV(_ blockSize: Int) -> Array<UInt8>

+ 3 - 6
Sources/CryptoSwift/Foundation/AES+Foundation.swift

@@ -18,11 +18,8 @@ import Foundation
 
 extension AES {
 
-    public convenience init(key: String, iv: String, blockMode: BlockMode = .CBC, padding: Padding = .pkcs7) throws {
-        guard let kkey = key.data(using: String.Encoding.utf8, allowLossyConversion: false)?.bytes, let iiv = iv.data(using: String.Encoding.utf8, allowLossyConversion: false)?.bytes else {
-            throw Error.invalidKeyOrInitializationVector
-        }
-
-        try self.init(key: kkey, iv: iiv, blockMode: blockMode, padding: padding)
+    /// Initialize with CBC block mode.
+    public convenience init(key: String, iv: String, padding: Padding = .pkcs7) throws {
+        try self.init(key: Array(key.utf8), blockMode: .CBC(iv: Array(iv.utf8)), padding: padding)
     }
 }

+ 1 - 1
Sources/CryptoSwift/Foundation/Blowfish+Foundation.swift

@@ -18,7 +18,7 @@ import Foundation
 
 extension Blowfish {
 
-    public convenience init(key: String, iv: String, blockMode: BlockMode = .CBC, padding: Padding = .pkcs7) throws {
+    public convenience init(key: String, iv: String, blockMode: BlockMode = .CBC(iv: Array<UInt8>(repeating: 0, count: Blowfish.blockSize)), padding: Padding = .pkcs7) throws {
         guard let kkey = key.data(using: String.Encoding.utf8, allowLossyConversion: false)?.bytes, let iiv = iv.data(using: String.Encoding.utf8, allowLossyConversion: false)?.bytes else {
             throw Error.invalidKeyOrInitializationVector
         }

+ 39 - 35
Tests/CryptoSwiftTests/AESTests.swift

@@ -31,11 +31,15 @@ final class AESTests: XCTestCase {
 
         let expected: Array<UInt8> = [0xae, 0x8c, 0x59, 0x95, 0xb2, 0x6f, 0x8e, 0x3d, 0xb0, 0x6f, 0x0a, 0xa5, 0xfe, 0xc4, 0xf0, 0xc2]
 
-        let aes = try! AES(key: key, iv: iv, blockMode: .CBC, padding: .noPadding)
-        let encrypted = try! aes.encrypt(input)
-        XCTAssertEqual(encrypted, expected, "encryption failed")
-        let decrypted = try! aes.decrypt(encrypted)
-        XCTAssertEqual(decrypted, input, "decryption failed")
+        let aes = try! AES(key: key, blockMode: .CBC(iv: iv), padding: .noPadding)
+        do {
+            let encrypted = try aes.encrypt(input)
+            XCTAssertEqual(encrypted, expected, "encryption failed")
+            let decrypted = try aes.decrypt(encrypted)
+            XCTAssertEqual(decrypted, input, "decryption failed")
+        } catch {
+            XCTFail("\(error)")
+        }
     }
 
     func testAESEncrypt3() {
@@ -44,7 +48,7 @@ final class AESTests: XCTestCase {
         let input: Array<UInt8> = [0x62, 0x72, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
         let expected: Array<UInt8> = [0xae, 0x8c, 0x59, 0x95, 0xb2, 0x6f, 0x8e, 0x3d, 0xb0, 0x6f, 0x0a, 0xa5, 0xfe, 0xc4, 0xf0, 0xc2]
 
-        let aes = try! AES(key: key, iv: iv, blockMode: .CBC, padding: .noPadding)
+        let aes = try! AES(key: key, iv: iv, padding: .noPadding)
         let encrypted = try! aes.encrypt(input)
         XCTAssertEqual(encrypted, expected, "encryption failed")
         let decrypted = try! aes.decrypt(encrypted)
@@ -57,7 +61,7 @@ final class AESTests: XCTestCase {
         let plaintext: Array<UInt8> = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a]
         let expected: Array<UInt8> = [0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d]
 
-        let aes = try! AES(key: key, iv: iv, blockMode: .CBC, padding: .noPadding)
+        let aes = try! AES(key: key, blockMode: .CBC(iv: iv), padding: .noPadding)
         let encrypted = try! aes.encrypt(plaintext)
         XCTAssertEqual(encrypted, expected, "encryption failed")
         let decrypted = try! aes.decrypt(encrypted)
@@ -70,7 +74,7 @@ final class AESTests: XCTestCase {
         let plaintext: Array<UInt8> = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a]
         let expected: Array<UInt8> = [0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d, 0x89, 0x64, 0xe0, 0xb1, 0x49, 0xc1, 0x0b, 0x7b, 0x68, 0x2e, 0x6e, 0x39, 0xaa, 0xeb, 0x73, 0x1c]
 
-        let aes = try! AES(key: key, iv: iv, blockMode: .CBC, padding: .pkcs7)
+        let aes = try! AES(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7)
         let encrypted = try! aes.encrypt(plaintext)
         XCTAssertEqual(encrypted, expected, "encryption failed")
         let decrypted = try! aes.decrypt(encrypted)
@@ -82,10 +86,10 @@ final class AESTests: XCTestCase {
         let iv: Array<UInt8> = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]
         let plaintext: Array<UInt8> = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a]
 
-        let aes = try! AES(key: key, iv: iv, blockMode: .CBC, padding: .pkcs7)
+        let aes = try! AES(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7)
 
         var ciphertext = Array<UInt8>()
-        var encryptor = aes.makeEncryptor()
+        var encryptor = try! aes.makeEncryptor()
         ciphertext += try! encryptor.update(withBytes: plaintext[0..<8])
         ciphertext += try! encryptor.update(withBytes: plaintext[8..<16])
         ciphertext += try! encryptor.update(withBytes: plaintext[16..<32])
@@ -97,8 +101,8 @@ final class AESTests: XCTestCase {
         do {
             var ciphertext = Array<UInt8>()
             let plaintext = "Today Apple launched the open source Swift community, as well as amazing new tools and resources."
-            let aes = try AES(key: Array("passwordpassword".utf8), iv: Array("drowssapdrowssap".utf8))
-            var encryptor = aes.makeEncryptor()
+            let aes = try AES(key: Array("passwordpassword".utf8), blockMode: .CBC(iv: Array("drowssapdrowssap".utf8)))
+            var encryptor = try! aes.makeEncryptor()
 
             ciphertext += try encryptor.update(withBytes: Array(plaintext.utf8))
             ciphertext += try encryptor.finish()
@@ -113,9 +117,9 @@ final class AESTests: XCTestCase {
         let iv: Array<UInt8> = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]
         let ciphertext: Array<UInt8> = [118, 73, 171, 172, 129, 25, 178, 70, 206, 233, 142, 155, 18, 233, 25, 125, 76, 187, 200, 88, 117, 107, 53, 129, 37, 82, 158, 150, 152, 163, 143, 68, 169, 105, 137, 234, 93, 98, 239, 215, 41, 45, 51, 254, 138, 92, 251, 17]
 
-        let aes = try! AES(key: key, iv: iv, blockMode: .CBC, padding: .pkcs7)
+        let aes = try! AES(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7)
         var plaintext = Array<UInt8>()
-        var decryptor = aes.makeDecryptor()
+        var decryptor = try! aes.makeDecryptor()
         plaintext += try! decryptor.update(withBytes: ciphertext[0..<8])
         plaintext += try! decryptor.update(withBytes: ciphertext[8..<16])
         plaintext += try! decryptor.update(withBytes: ciphertext[16..<32])
@@ -129,7 +133,7 @@ final class AESTests: XCTestCase {
         let plaintext: Array<UInt8> = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a]
         let expected: Array<UInt8> = [0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a]
 
-        let aes = try! AES(key: key, iv: iv, blockMode: .CFB, padding: .noPadding)
+        let aes = try! AES(key: key, blockMode: .CFB(iv: iv), padding: .noPadding)
         let encrypted = try! aes.encrypt(plaintext)
         XCTAssertEqual(encrypted, expected, "encryption failed")
         let decrypted = try! aes.decrypt(encrypted)
@@ -141,8 +145,8 @@ final class AESTests: XCTestCase {
         let key: Array<UInt8> = [56, 118, 37, 51, 125, 78, 103, 107, 119, 40, 74, 88, 117, 112, 123, 75, 122, 89, 72, 36, 46, 91, 106, 60, 54, 110, 34, 126, 69, 126, 61, 87]
         let iv: Array<UInt8> = [69, 122, 99, 87, 83, 112, 110, 65, 54, 109, 107, 89, 73, 122, 74, 49]
         let plaintext: Array<UInt8> = [123, 10, 32, 32, 34, 67, 111, 110, 102, 105, 114, 109, 34, 32, 58, 32, 34, 116, 101, 115, 116, 105, 110, 103, 34, 44, 10, 32, 32, 34, 70, 105, 114, 115, 116, 78, 97, 109, 101, 34, 32, 58, 32, 34, 84, 101, 115, 116, 34, 44, 10, 32, 32, 34, 69, 109, 97, 105, 108, 34, 32, 58, 32, 34, 116, 101, 115, 116, 64, 116, 101, 115, 116, 46, 99, 111, 109, 34, 44, 10, 32, 32, 34, 76, 97, 115, 116, 78, 97, 109, 101, 34, 32, 58, 32, 34, 84, 101, 115, 116, 101, 114, 34, 44, 10, 32, 32, 34, 80, 97, 115, 115, 119, 111, 114, 100, 34, 32, 58, 32, 34, 116, 101, 115, 116, 105, 110, 103, 34, 44, 10, 32, 32, 34, 85, 115, 101, 114, 110, 97, 109, 101, 34, 32, 58, 32, 34, 84, 101, 115, 116, 34, 10, 125]
-        let encrypted: Array<UInt8> = try! AES(key: key, iv: iv, blockMode: .CFB).encrypt(plaintext)
-        let decrypted: Array<UInt8> = try! AES(key: key, iv: iv, blockMode: .CFB).decrypt(encrypted)
+        let encrypted: Array<UInt8> = try! AES(key: key, blockMode: .CFB(iv: iv)).encrypt(plaintext)
+        let decrypted: Array<UInt8> = try! AES(key: key, blockMode: .CFB(iv: iv)).decrypt(encrypted)
         XCTAssert(decrypted == plaintext, "decryption failed")
     }
 
@@ -152,7 +156,7 @@ final class AESTests: XCTestCase {
         let plaintext: Array<UInt8> = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a]
         let expected: Array<UInt8> = [0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a]
 
-        let aes = try! AES(key: key, iv: iv, blockMode: .OFB, padding: .noPadding)
+        let aes = try! AES(key: key, blockMode: .OFB(iv: iv), padding: .noPadding)
         let encrypted = try! aes.encrypt(plaintext)
         XCTAssertEqual(encrypted, expected, "encryption failed")
         let decrypted = try! aes.decrypt(encrypted)
@@ -165,7 +169,7 @@ final class AESTests: XCTestCase {
         let plaintext: Array<UInt8> = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a]
         let expected: Array<UInt8> = [0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60]
 
-        let aes = try! AES(key: key, iv: iv, blockMode: .OFB, padding: .noPadding)
+        let aes = try! AES(key: key, blockMode: .OFB(iv: iv), padding: .noPadding)
         let encrypted = try! aes.encrypt(plaintext)
         XCTAssertEqual(encrypted, expected, "encryption failed")
         let decrypted = try! aes.decrypt(encrypted)
@@ -178,7 +182,7 @@ final class AESTests: XCTestCase {
         let plaintext: Array<UInt8> = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a]
         let expected: Array<UInt8> = [0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6]
 
-        let aes = try! AES(key: key, iv: iv, blockMode: .PCBC, padding: .noPadding)
+        let aes = try! AES(key: key, blockMode: .PCBC(iv: iv), padding: .noPadding)
         let encrypted = try! aes.encrypt(plaintext)
         print(encrypted.toHexString())
         XCTAssertEqual(encrypted, expected, "encryption failed")
@@ -192,7 +196,7 @@ final class AESTests: XCTestCase {
         let plaintext: Array<UInt8> = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a]
         let expected: Array<UInt8> = [0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce]
 
-        let aes = try! AES(key: key, iv: iv, blockMode: .CTR, padding: .noPadding)
+        let aes = try! AES(key: key, blockMode: .CTR(iv: iv), padding: .noPadding)
         let encrypted = try! aes.encrypt(plaintext)
         XCTAssertEqual(encrypted.count, plaintext.count)
         XCTAssertEqual(encrypted, expected, "encryption failed")
@@ -207,7 +211,7 @@ final class AESTests: XCTestCase {
         let iv: Array<UInt8> = [0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff]
         let plaintext: Array<UInt8> = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xfd]
 
-        let aes = try! AES(key: key, iv: iv, blockMode: .CTR, padding: .zeroPadding)
+        let aes = try! AES(key: key, blockMode: .CTR(iv: iv), padding: .zeroPadding)
         let encrypted = try! aes.encrypt(plaintext)
 
         XCTAssertEqual(plaintext.count, 17)
@@ -220,7 +224,7 @@ final class AESTests: XCTestCase {
         let plaintext: Array<UInt8> = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0x01]
         let expected: Array<UInt8> = [0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce, 0x37]
 
-        let aes = try! AES(key: key, iv: iv, blockMode: .CTR, padding: .noPadding)
+        let aes = try! AES(key: key, blockMode: .CTR(iv: iv), padding: .noPadding)
         let encrypted = try! aes.encrypt(plaintext)
         XCTAssertEqual(encrypted, expected, "encryption failed")
         let decrypted = try! aes.decrypt(encrypted)
@@ -243,10 +247,10 @@ final class AESTests: XCTestCase {
             plaintext[i * 6 + 5] = "|".utf8.first!
         }
 
-        let aes = try! AES(key: key, iv: iv, blockMode: .CTR, padding: .noPadding)
+        let aes = try! AES(key: key, blockMode: .CTR(iv: iv), padding: .noPadding)
         let encrypted = try! aes.encrypt(plaintext)
 
-        var decryptor = aes.makeDecryptor()
+        var decryptor = try! aes.makeDecryptor()
         decryptor.seek(to: 2)
         var part1 = try! decryptor.update(withBytes: Array(encrypted[2..<5]))
         part1 += try! decryptor.finish()
@@ -275,8 +279,8 @@ final class AESTests: XCTestCase {
         let plaintext: Array<UInt8> = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0x01, 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0x01]
         let expected: Array<UInt8> = [0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0xd, 0xb6, 0xce, 0x37, 0x40, 0xbd, 0x82, 0x85, 0x5d, 0x11, 0xfc, 0x8e, 0x49, 0x4a, 0xa9, 0xed, 0x23, 0xe0, 0xb9, 0x40, 0x2d]
 
-        let aes = try! AES(key: key, iv: iv, blockMode: .CTR, padding: .noPadding)
-        var encryptor = aes.makeEncryptor()
+        let aes = try! AES(key: key, blockMode: .CTR(iv: iv), padding: .noPadding)
+        var encryptor = try! aes.makeEncryptor()
         var encrypted = Array<UInt8>()
         encrypted += try! encryptor.update(withBytes: plaintext[0..<5])
         encrypted += try! encryptor.update(withBytes: plaintext[5..<15])
@@ -284,7 +288,7 @@ final class AESTests: XCTestCase {
         encrypted += try! encryptor.finish()
         XCTAssertEqual(encrypted, expected, "encryption failed")
 
-        var decryptor = aes.makeDecryptor()
+        var decryptor = try! aes.makeDecryptor()
         var decrypted = Array<UInt8>()
         decrypted += try! decryptor.update(withBytes: expected[0..<5])
         decrypted += try! decryptor.update(withBytes: expected[5..<15])
@@ -299,8 +303,8 @@ final class AESTests: XCTestCase {
         let iv: Array<UInt8> = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]
         let plaintext: Array<UInt8> = [49, 46, 50, 50, 50, 51, 51, 51, 51]
 
-        let aes = try! AES(key: key, iv: iv, blockMode: .CBC, padding: .pkcs7)
-        let aes2 = try! AES(key: key2, iv: iv, blockMode: .CBC, padding: .pkcs7)
+        let aes = try! AES(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7)
+        let aes2 = try! AES(key: key2, blockMode: .CBC(iv: iv), padding: .pkcs7)
         let encrypted = try! aes.encrypt(plaintext)
         let decrypted = try? aes2.decrypt(encrypted)
         XCTAssertTrue(decrypted! != plaintext, "failed")
@@ -314,7 +318,7 @@ final class AESTests: XCTestCase {
         let iv = "fedcba9876543210"
 
         do {
-            let aes = try AES(key: key, iv: iv, blockMode: .CBC, padding: .noPadding)
+            let aes = try AES(key: key, iv: iv, padding: .noPadding)
             let ciphertext = try aes.decrypt(Array<UInt8>(hex: encryptedValue))
             XCTAssertEqual(ciphertext, expected)
         } catch {
@@ -327,7 +331,7 @@ final class AESTests: XCTestCase {
         let plaintext = Array("Nullam quis risus eget urna mollis ornare vel eu leo.".utf8)
         let key = Array("passwordpassword".utf8).md5() // -md md5
         let iv = Array("drowssapdrowssap".utf8) // -iv 64726f777373617064726f7773736170
-        let aes = try! AES(key: key, iv: iv, blockMode: .CBC, padding: .pkcs7) // -aes-128-cbc
+        let aes = try! AES(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7) // -aes-128-cbc
         let ciphertext = try! aes.encrypt(plaintext) // enc
 
         // $ echo -n "Nullam quis risus eget urna mollis ornare vel eu leo." | openssl enc -aes-128-cbc -md md5 -nosalt -iv 64726f777373617064726f7773736170 -pass pass:passwordpassword -base64
@@ -341,7 +345,7 @@ final class AESTests: XCTestCase {
         let ciphertext: Array<UInt8> = [0x2a, 0x3a, 0x80, 0x05, 0xaf, 0x46, 0x58, 0x2d, 0x66, 0x52, 0x10, 0xae, 0x86, 0xd3, 0x8e, 0x8f] // test
         let key = Array("passwordpassword".utf8).md5() // -md md5
         let iv = Array("drowssapdrowssap".utf8) // -iv 64726f777373617064726f7773736170
-        let aes = try! AES(key: key, iv: iv, blockMode: .CBC, padding: .pkcs7) // -aes-128-cbc
+        let aes = try! AES(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7) // -aes-128-cbc
         let plaintext = try! ciphertext.decrypt(cipher: aes)
         XCTAssertEqual("74657374", plaintext.toHexString())
     }
@@ -355,7 +359,7 @@ final class AESTests: XCTestCase {
             let key: Array<UInt8> = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c]
             let iv: Array<UInt8> = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]
             let message = Array<UInt8>(repeating: 7, count: 1024 * 1024)
-            let aes = try! AES(key: key, iv: iv, blockMode: .CBC, padding: .pkcs7)
+            let aes = try! AES(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7)
             measureMetrics([XCTPerformanceMetric.wallClockTime], automaticallyStartMeasuring: true, for: { () -> Void in
                 _ = try! aes.encrypt(message)
             })
@@ -365,7 +369,7 @@ final class AESTests: XCTestCase {
             let key: Array<UInt8> = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c]
             let iv: Array<UInt8> = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]
             let message = Array<UInt8>(repeating: 7, count: 1024 * 1024)
-            let aes = try! AES(key: key, iv: iv, blockMode: .CBC, padding: .pkcs7)
+            let aes = try! AES(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7)
             measureMetrics([XCTPerformanceMetric.wallClockTime], automaticallyStartMeasuring: true, for: { () -> Void in
                 _ = try! aes.decrypt(message)
             })

+ 5 - 5
Tests/CryptoSwiftTests/Access.swift

@@ -183,23 +183,23 @@ class Access: XCTestCase {
     func testAES() {
         do {
             let cipher = try AES(key: "secret0key000000", iv: "0123456789012345")
-            var encryptor = cipher.makeEncryptor()
+            var encryptor = try cipher.makeEncryptor()
             _ = try encryptor.update(withBytes: [1, 2, 3])
             _ = try encryptor.finish()
 
-            var decryptor = cipher.makeDecryptor()
+            var decryptor = try cipher.makeDecryptor()
             _ = try decryptor.update(withBytes: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
             _ = try decryptor.finish()
 
             let enc = try cipher.encrypt([1, 2, 3])
             _ = try cipher.decrypt(enc)
 
-            _ = try AES(key: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6], iv: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6], blockMode: .CBC, padding: .noPadding)
+            _ = try AES(key: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6], blockMode: .CBC(iv: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6]), padding: .noPadding)
 
             _ = AES.Variant.aes128
             _ = AES.blockSize
         } catch {
-            XCTFail(error.localizedDescription)
+            XCTFail("\(error)")
         }
     }
 
@@ -209,7 +209,7 @@ class Access: XCTestCase {
             let enc = try cipher.encrypt([1, 2, 3])
             _ = try cipher.decrypt(enc)
 
-            _ = try Blowfish(key: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6], iv: [1, 2, 3, 4, 5, 6, 7, 8], blockMode: .CBC, padding: .noPadding)
+            _ = try Blowfish(key: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6], iv: [1, 2, 3, 4, 5, 6, 7, 8], padding: .noPadding)
 
             _ = Blowfish.blockSize
         } catch {

+ 4 - 4
Tests/CryptoSwiftTests/BlowfishTests.swift

@@ -170,7 +170,7 @@ class BlowfishTests: XCTestCase {
         let key = Array<UInt8>.init(hex: "0123456789ABCDEFF0E1D2C3B4A59687")
         let iv = Array<UInt8>.init(hex: "FEDCBA9876543210")
         let input = Array<UInt8>.init(hex: "37363534333231204E6F77206973207468652074696D6520666F722000")
-        XCTAssertEqual(try Blowfish(key: key, iv: iv, blockMode: .CBC, padding: .zeroPadding).encrypt(input), Array<UInt8>(hex: "6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC"))
+        XCTAssertEqual(try Blowfish(key: key, blockMode: .CBC(iv: iv), padding: .zeroPadding).encrypt(input), Array<UInt8>(hex: "6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC"))
     }
 
     func testEncryptDecrypt() {
@@ -179,7 +179,7 @@ class BlowfishTests: XCTestCase {
         let input = Array<UInt8>.init(hex: "37363534333231204E6F77206973207468652074696D6520666F722000")
 
         do {
-            let cipher = try Blowfish(key: key, iv: iv, blockMode: .CBC, padding: .pkcs7)
+            let cipher = try Blowfish(key: key, blockMode: .CBC(iv: iv), padding: .pkcs7)
             let ciphertext = try cipher.encrypt(input)
             let plaintext = try cipher.decrypt(ciphertext)
             XCTAssertEqual(plaintext, input)
@@ -192,8 +192,8 @@ class BlowfishTests: XCTestCase {
     func testDecryptCFB415() {
         do {
             let plaintext = Array("secret12".utf8)
-            let encrypted = try Blowfish(key: "passwordpassword", iv: "12345678", blockMode: .CFB, padding: .noPadding).encrypt(plaintext)
-            let decrypted = try Blowfish(key: "passwordpassword", iv: "12345678", blockMode: .CFB, padding: .noPadding).decrypt(encrypted)
+            let encrypted = try Blowfish(key: Array("passwordpassword".utf8), blockMode: .CFB(iv: Array("12345678".utf8)), padding: .noPadding).encrypt(plaintext)
+            let decrypted = try Blowfish(key: Array("passwordpassword".utf8), blockMode: .CFB(iv: Array("12345678".utf8)), padding: .noPadding).decrypt(encrypted)
             XCTAssertEqual(plaintext, decrypted)
         } catch {
             XCTFail(error.localizedDescription)

+ 1 - 1
Tests/CryptoSwiftTests/ExtensionsTest.swift

@@ -49,7 +49,7 @@ final class ExtensionsTest: XCTestCase {
 
     func testEmptyStringEncrypt() {
         do {
-            let cipher = try AES(key: Array("secret0key000000".utf8).md5(), iv: Array("secret0key000000".utf8).md5(), blockMode: .ECB)
+            let cipher = try AES(key: Array("secret0key000000".utf8).md5(), blockMode: .ECB)
             let encrypted = try "".encryptToBase64(cipher: cipher)
             let decrypted = try encrypted?.decryptBase64ToString(cipher: cipher)
             XCTAssertEqual("", decrypted)