CipherBlockMode.swift 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. //
  2. // CipherBlockMode.swift
  3. // CryptoSwift
  4. //
  5. // Created by Marcin Krzyzanowski on 27/12/14.
  6. // Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
  7. //
  8. // I have no better name for that
  9. typealias CipherOperationOnBlock = (block: [UInt8]) -> [UInt8]?
  10. enum BlockError: ErrorType {
  11. case MissingInitializationVector
  12. }
  13. struct BlockModeOptions: OptionSetType {
  14. let rawValue: Int
  15. static let None = BlockModeOptions(rawValue: 0)
  16. static let InitializationVectorRequired = BlockModeOptions(rawValue: 1)
  17. static let PaddingRequired = BlockModeOptions(rawValue: 2)
  18. }
  19. private protocol BlockMode {
  20. var options: BlockModeOptions { get }
  21. func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8]
  22. func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8]
  23. }
  24. public enum CipherBlockMode {
  25. case ECB, CBC, CFB, CTR
  26. private var mode:BlockMode {
  27. switch (self) {
  28. case CBC:
  29. return CBCMode()
  30. case CFB:
  31. return CFBMode()
  32. case ECB:
  33. return ECBMode()
  34. case CTR:
  35. return CTRMode()
  36. }
  37. }
  38. var options: BlockModeOptions { return mode.options }
  39. /**
  40. Process input blocks with given block cipher mode. With fallback to plain mode.
  41. - parameter blocks: cipher block size blocks
  42. - parameter iv: IV
  43. - parameter cipher: single block encryption closure
  44. - returns: encrypted bytes
  45. */
  46. func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
  47. // if IV is not available, fallback to plain
  48. var finalBlockMode:CipherBlockMode = self
  49. if (iv == nil) {
  50. finalBlockMode = .ECB
  51. }
  52. return try finalBlockMode.mode.encryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
  53. }
  54. func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
  55. // if IV is not available, fallback to plain
  56. var finalBlockMode:CipherBlockMode = self
  57. if (iv == nil) {
  58. finalBlockMode = .ECB
  59. }
  60. return try finalBlockMode.mode.decryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
  61. }
  62. }
  63. /**
  64. Cipher-block chaining (CBC)
  65. */
  66. private struct CBCMode: BlockMode {
  67. let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
  68. func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
  69. precondition(blocks.count > 0)
  70. guard let iv = iv else {
  71. throw BlockError.MissingInitializationVector
  72. }
  73. var out:[UInt8] = [UInt8]()
  74. out.reserveCapacity(blocks.count * blocks[blocks.startIndex].count)
  75. var prevCiphertext = iv // for the first time prevCiphertext = iv
  76. for plaintext in blocks {
  77. if let encrypted = cipherOperation(block: xor(prevCiphertext, plaintext)) {
  78. out.appendContentsOf(encrypted)
  79. prevCiphertext = encrypted
  80. }
  81. }
  82. return out
  83. }
  84. func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
  85. precondition(blocks.count > 0)
  86. guard let iv = iv else {
  87. throw BlockError.MissingInitializationVector
  88. }
  89. var out:[UInt8] = [UInt8]()
  90. out.reserveCapacity(blocks.count * blocks[blocks.startIndex].count)
  91. var prevCiphertext = iv // for the first time prevCiphertext = iv
  92. for ciphertext in blocks {
  93. if let decrypted = cipherOperation(block: ciphertext) { // decrypt
  94. out.appendContentsOf(xor(prevCiphertext, decrypted)) //FIXME: b:
  95. }
  96. prevCiphertext = ciphertext
  97. }
  98. return out
  99. }
  100. }
  101. /**
  102. Cipher feedback (CFB)
  103. */
  104. private struct CFBMode: BlockMode {
  105. let options: BlockModeOptions = [.InitializationVectorRequired]
  106. func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
  107. guard let iv = iv else {
  108. throw BlockError.MissingInitializationVector
  109. }
  110. var out:[UInt8] = [UInt8]()
  111. out.reserveCapacity(blocks.count * blocks[blocks.startIndex].count)
  112. var lastCiphertext = iv
  113. for plaintext in blocks {
  114. if let ciphertext = cipherOperation(block: lastCiphertext) {
  115. lastCiphertext = xor(plaintext, ciphertext)
  116. out.appendContentsOf(lastCiphertext)
  117. }
  118. }
  119. return out
  120. }
  121. func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
  122. guard let iv = iv else {
  123. throw BlockError.MissingInitializationVector
  124. }
  125. var out:[UInt8] = [UInt8]()
  126. out.reserveCapacity(blocks.count * blocks[blocks.startIndex].count)
  127. var lastCiphertext = iv
  128. for ciphertext in blocks {
  129. if let decrypted = cipherOperation(block: lastCiphertext) {
  130. out.appendContentsOf(xor(decrypted, ciphertext))
  131. }
  132. lastCiphertext = ciphertext
  133. }
  134. return out
  135. }
  136. }
  137. /**
  138. Electronic codebook (ECB)
  139. */
  140. private struct ECBMode: BlockMode {
  141. let options: BlockModeOptions = [.PaddingRequired]
  142. func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) -> [UInt8] {
  143. var out:[UInt8] = [UInt8]()
  144. out.reserveCapacity(blocks.count * blocks[blocks.startIndex].count)
  145. for plaintext in blocks {
  146. if let encrypted = cipherOperation(block: plaintext) {
  147. out.appendContentsOf(encrypted)
  148. }
  149. }
  150. return out
  151. }
  152. func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) -> [UInt8] {
  153. return encryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
  154. }
  155. }
  156. /**
  157. Counter (CTR)
  158. */
  159. private struct CTRMode: BlockMode {
  160. let options = BlockModeOptions.InitializationVectorRequired
  161. private func buildNonce(iv: [UInt8], counter: UInt64) -> [UInt8] {
  162. let noncePartLen = AES.blockSize / 2
  163. let noncePrefix = Array(iv[0..<noncePartLen])
  164. let nonceSuffix = Array(iv[noncePartLen..<iv.count])
  165. let c = UInt64.withBytes(nonceSuffix) + counter
  166. return noncePrefix + arrayOfBytes(c)
  167. }
  168. func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
  169. //var counter:UInt = 17940646550795321087
  170. guard let iv = iv else {
  171. throw BlockError.MissingInitializationVector
  172. }
  173. var counter:UInt = 0
  174. var out:[UInt8] = [UInt8]()
  175. out.reserveCapacity(blocks.count * blocks[blocks.startIndex].count)
  176. for plaintext in blocks {
  177. let nonce = buildNonce(iv, counter: UInt64(counter++))
  178. if let encrypted = cipherOperation(block: nonce) {
  179. out.appendContentsOf(xor(plaintext, encrypted))
  180. }
  181. }
  182. return out
  183. }
  184. func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
  185. guard let iv = iv else {
  186. throw BlockError.MissingInitializationVector
  187. }
  188. var counter:UInt = 0
  189. var out = [UInt8]()
  190. out.reserveCapacity(blocks.count * blocks[blocks.startIndex].count)
  191. for ciphertext in blocks {
  192. let nonce = buildNonce(iv, counter: UInt64(counter++))
  193. if let decrypted = cipherOperation(block: nonce) {
  194. out.appendContentsOf(xor(decrypted, ciphertext))
  195. }
  196. }
  197. return out
  198. }
  199. }