|
@@ -8,20 +8,32 @@
|
|
|
|
|
|
import Foundation
|
|
|
|
|
|
-typealias CipherWorker = (block: [UInt8]) -> [UInt8]?
|
|
|
+// I have no better name for that
|
|
|
+typealias CipherOperationOnBlock = (block: [UInt8]) -> [UInt8]?
|
|
|
+
|
|
|
+private protocol BlockMode {
|
|
|
+ var needIV:Bool { get }
|
|
|
+ func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) -> [UInt8]?
|
|
|
+ func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) -> [UInt8]?
|
|
|
+}
|
|
|
|
|
|
public enum CipherBlockMode {
|
|
|
case ECB, CBC, CFB
|
|
|
|
|
|
- func requireIV() -> Bool {
|
|
|
+ private var mode:BlockMode {
|
|
|
switch (self) {
|
|
|
- case CBC, CFB:
|
|
|
- return true
|
|
|
- default:
|
|
|
- return false
|
|
|
+ case CBC:
|
|
|
+ return CBCMode()
|
|
|
+ case CFB:
|
|
|
+ return CFBMode()
|
|
|
+ case ECB:
|
|
|
+ return ECBMode()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ var needIV: Bool {
|
|
|
+ return mode.needIV
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
Process input blocks with given block cipher mode. With fallback to plain mode.
|
|
@@ -32,7 +44,7 @@ public enum CipherBlockMode {
|
|
|
|
|
|
:returns: encrypted bytes
|
|
|
*/
|
|
|
- func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipher:CipherWorker) -> [UInt8]? {
|
|
|
+ func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) -> [UInt8]? {
|
|
|
|
|
|
// if IV is not available, fallback to plain
|
|
|
var finalBlockMode:CipherBlockMode = self
|
|
@@ -40,39 +52,31 @@ public enum CipherBlockMode {
|
|
|
finalBlockMode = .ECB
|
|
|
}
|
|
|
|
|
|
- switch (finalBlockMode) {
|
|
|
- case CBC:
|
|
|
- return CBCMode.encryptBlocks(blocks, iv: iv, cipher: cipher)
|
|
|
- case CFB:
|
|
|
- return CFBMode.encryptBlocks(blocks, iv: iv, cipher: cipher)
|
|
|
- case ECB:
|
|
|
- return ECBMode.encryptBlocks(blocks, cipher: cipher)
|
|
|
- }
|
|
|
+ return finalBlockMode.mode.encryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
|
|
|
}
|
|
|
|
|
|
- func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipher:(block:[UInt8]) -> [UInt8]?) -> [UInt8]? {
|
|
|
+ func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:(block:[UInt8]) -> [UInt8]?) -> [UInt8]? {
|
|
|
// if IV is not available, fallback to plain
|
|
|
var finalBlockMode:CipherBlockMode = self
|
|
|
if (iv == nil) {
|
|
|
finalBlockMode = .ECB
|
|
|
}
|
|
|
-
|
|
|
- switch (finalBlockMode) {
|
|
|
- case CBC:
|
|
|
- return CBCMode.decryptBlocks(blocks, iv: iv, cipher: cipher)
|
|
|
- case CFB:
|
|
|
- return CFBMode.decryptBlocks(blocks, iv: iv, cipher: cipher)
|
|
|
- case ECB:
|
|
|
- return ECBMode.decryptBlocks(blocks, cipher: cipher)
|
|
|
- }
|
|
|
+
|
|
|
+ return finalBlockMode.mode.decryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Cipher-block chaining (CBC)
|
|
|
*/
|
|
|
-private struct CBCMode {
|
|
|
- static func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipher:CipherWorker) -> [UInt8]? {
|
|
|
+private struct CBCMode: BlockMode {
|
|
|
+ var needIV:Bool = true
|
|
|
+
|
|
|
+ init() {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) -> [UInt8]? {
|
|
|
assert(iv != nil, "CFB require IV")
|
|
|
if (iv == nil) {
|
|
|
return nil;
|
|
@@ -89,7 +93,7 @@ private struct CBCMode {
|
|
|
}
|
|
|
|
|
|
// encrypt with cipher
|
|
|
- if let encrypted = cipher(block: xoredPlaintext) {
|
|
|
+ if let encrypted = cipherOperation(block: xoredPlaintext) {
|
|
|
lastCiphertext = encrypted
|
|
|
|
|
|
if (out == nil) {
|
|
@@ -102,7 +106,7 @@ private struct CBCMode {
|
|
|
return out;
|
|
|
}
|
|
|
|
|
|
- static func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipher:CipherWorker) -> [UInt8]? {
|
|
|
+ func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) -> [UInt8]? {
|
|
|
assert(iv != nil, "CFB require IV")
|
|
|
if (iv == nil) {
|
|
|
return nil
|
|
@@ -111,7 +115,7 @@ private struct CBCMode {
|
|
|
var out:[UInt8]?
|
|
|
var lastCiphertext:[UInt8] = iv!
|
|
|
for (idx,ciphertext) in enumerate(blocks) {
|
|
|
- if let decrypted = cipher(block: ciphertext) { // decrypt
|
|
|
+ if let decrypted = cipherOperation(block: ciphertext) { // decrypt
|
|
|
|
|
|
var xored:[UInt8] = [UInt8](count: ciphertext.count, repeatedValue: 0)
|
|
|
for i in 0..<ciphertext.count {
|
|
@@ -133,8 +137,9 @@ private struct CBCMode {
|
|
|
/**
|
|
|
* Cipher feedback (CFB)
|
|
|
*/
|
|
|
-private struct CFBMode {
|
|
|
- static func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipher:CipherWorker) -> [UInt8]? {
|
|
|
+private struct CFBMode: BlockMode {
|
|
|
+ var needIV:Bool = true
|
|
|
+ func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) -> [UInt8]? {
|
|
|
assert(iv != nil, "CFB require IV")
|
|
|
if (iv == nil) {
|
|
|
return nil
|
|
@@ -143,7 +148,7 @@ private struct CFBMode {
|
|
|
var out:[UInt8]?
|
|
|
var lastCiphertext:[UInt8] = iv!
|
|
|
for (idx,plaintext) in enumerate(blocks) {
|
|
|
- if let encrypted = cipher(block: lastCiphertext) {
|
|
|
+ if let encrypted = cipherOperation(block: lastCiphertext) {
|
|
|
var xoredPlaintext:[UInt8] = [UInt8](count: plaintext.count, repeatedValue: 0)
|
|
|
for i in 0..<plaintext.count {
|
|
|
xoredPlaintext[i] = plaintext[i] ^ encrypted[i]
|
|
@@ -161,7 +166,7 @@ private struct CFBMode {
|
|
|
return out;
|
|
|
}
|
|
|
|
|
|
- static func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipher:CipherWorker) -> [UInt8]? {
|
|
|
+ func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) -> [UInt8]? {
|
|
|
assert(iv != nil, "CFB require IV")
|
|
|
if (iv == nil) {
|
|
|
return nil
|
|
@@ -170,7 +175,7 @@ private struct CFBMode {
|
|
|
var out:[UInt8]?
|
|
|
var lastCiphertext:[UInt8] = iv!
|
|
|
for (idx,ciphertext) in enumerate(blocks) {
|
|
|
- if let decrypted = cipher(block: lastCiphertext) {
|
|
|
+ if let decrypted = cipherOperation(block: lastCiphertext) {
|
|
|
var xored:[UInt8] = [UInt8](count: ciphertext.count, repeatedValue: 0)
|
|
|
for i in 0..<ciphertext.count {
|
|
|
xored[i] = ciphertext[i] ^ decrypted[i]
|
|
@@ -194,11 +199,12 @@ private struct CFBMode {
|
|
|
/**
|
|
|
* Electronic codebook (ECB)
|
|
|
*/
|
|
|
-private struct ECBMode {
|
|
|
- static func encryptBlocks(blocks:[[UInt8]], cipher:CipherWorker) -> [UInt8]? {
|
|
|
+private struct ECBMode: BlockMode {
|
|
|
+ var needIV:Bool = false
|
|
|
+ func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) -> [UInt8]? {
|
|
|
var out:[UInt8]?
|
|
|
for (idx,plaintext) in enumerate(blocks) {
|
|
|
- if let encrypted = cipher(block: plaintext) {
|
|
|
+ if let encrypted = cipherOperation(block: plaintext) {
|
|
|
|
|
|
if (out == nil) {
|
|
|
out = [UInt8]()
|
|
@@ -210,7 +216,7 @@ private struct ECBMode {
|
|
|
return out
|
|
|
}
|
|
|
|
|
|
- static func decryptBlocks(blocks:[[UInt8]], cipher:CipherWorker) -> [UInt8]? {
|
|
|
- return encryptBlocks(blocks, cipher: cipher)
|
|
|
+ func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) -> [UInt8]? {
|
|
|
+ return encryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
|
|
|
}
|
|
|
}
|