CCM.swift 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. //// CryptoSwift
  2. //
  3. // Copyright (C) 2014-2018 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
  4. // This software is provided 'as-is', without any express or implied warranty.
  5. //
  6. // In no event will the authors be held liable for any damages arising from the use of this software.
  7. //
  8. // 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:
  9. //
  10. // - 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.
  11. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  12. // - This notice may not be removed or altered from any source or binary distribution.
  13. //
  14. // CCM mode combines the well known CBC-MAC with the well known counter mode of encryption.
  15. // https://tools.ietf.org/html/rfc3610
  16. // https://csrc.nist.gov/publications/detail/sp/800-38c/final
  17. #if canImport(Darwin)
  18. import Darwin
  19. #else
  20. import Glibc
  21. #endif
  22. public struct CCM: StreamMode {
  23. public enum Error: Swift.Error {
  24. /// Invalid IV
  25. case invalidInitializationVector
  26. case invalidParameter
  27. }
  28. public let options: BlockModeOption = [.initializationVectorRequired]
  29. private let nonce: Array<UInt8>
  30. private let additionalAuthenticatedData: Array<UInt8>?
  31. private let tagLength: Int
  32. private let messageLength: Int // total message length. need to know in advance
  33. public init(nonce: Array<UInt8>, tagLength: Int, messageLength: Int, additionalAuthenticatedData: Array<UInt8>? = nil) {
  34. self.nonce = nonce
  35. self.tagLength = tagLength
  36. self.additionalAuthenticatedData = additionalAuthenticatedData
  37. self.messageLength = messageLength
  38. }
  39. public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker {
  40. if nonce.isEmpty {
  41. throw Error.invalidInitializationVector
  42. }
  43. return CCMModeWorker(blockSize: blockSize, nonce: nonce.slice, messageLength: messageLength, additionalAuthenticatedData: additionalAuthenticatedData, tagLength: tagLength, cipherOperation: cipherOperation)
  44. }
  45. }
  46. class CCMModeWorker: StreamModeWorker, SeekableModeWorker, CounterModeWorker, FinalizingEncryptModeWorker, FinalizingDecryptModeWorker {
  47. typealias Counter = Int
  48. var counter = 0
  49. let cipherOperation: CipherOperationOnBlock
  50. let blockSize: Int
  51. private let tagLength: Int
  52. private let messageLength: Int // total message length. need to know in advance
  53. private let q: UInt8
  54. let additionalBufferSize: Int
  55. private var keystreamPosIdx = 0
  56. private let nonce: Array<UInt8>
  57. private var last_y: ArraySlice<UInt8> = []
  58. private var keystream: Array<UInt8> = []
  59. // Known Tag used to validate during decryption
  60. private var expectedTag: Array<UInt8>?
  61. public enum Error: Swift.Error {
  62. case invalidParameter
  63. }
  64. init(blockSize: Int, nonce: ArraySlice<UInt8>, messageLength: Int, additionalAuthenticatedData: [UInt8]?, tagLength: Int, cipherOperation: @escaping CipherOperationOnBlock) {
  65. self.blockSize = blockSize
  66. self.tagLength = tagLength
  67. self.additionalBufferSize = tagLength
  68. self.messageLength = messageLength
  69. self.cipherOperation = cipherOperation
  70. self.nonce = Array(nonce)
  71. self.q = UInt8(15 - nonce.count) // n = 15-q
  72. let hasAssociatedData = additionalAuthenticatedData != nil && !additionalAuthenticatedData!.isEmpty
  73. processControlInformation(nonce: self.nonce, tagLength: tagLength, hasAssociatedData: hasAssociatedData)
  74. if let aad = additionalAuthenticatedData {
  75. process(aad: aad)
  76. }
  77. }
  78. // For the very first time setup new IV (aka y0) from the block0
  79. private func processControlInformation(nonce: [UInt8], tagLength: Int, hasAssociatedData: Bool) {
  80. let block0 = try! format(nonce: nonce, Q: UInt32(messageLength), q: q, t: UInt8(tagLength), hasAssociatedData: hasAssociatedData).slice
  81. let y0 = cipherOperation(block0)!.slice
  82. last_y = y0
  83. }
  84. private func process(aad: [UInt8]) {
  85. let encodedAAD = format(aad: aad)
  86. for block_i in encodedAAD.batched(by: 16) {
  87. let y_i = cipherOperation(xor(block_i, last_y))!.slice
  88. last_y = y_i
  89. }
  90. }
  91. private func S(i: Int) throws -> [UInt8] {
  92. let ctr = try format(counter: i, nonce: nonce, q: q)
  93. return cipherOperation(ctr.slice)!
  94. }
  95. func seek(to position: Int) throws {
  96. self.counter = position
  97. keystream = try S(i: position)
  98. let offset = position % blockSize
  99. keystreamPosIdx = offset
  100. }
  101. func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
  102. var result = Array<UInt8>(reserveCapacity: plaintext.count)
  103. var processed = 0
  104. while processed < plaintext.count {
  105. // Need a full block here to update keystream and do CBC
  106. if keystream.isEmpty || keystreamPosIdx == blockSize {
  107. // y[i], where i is the counter. Can encrypt 1 block at a time
  108. counter += 1
  109. guard let S = try? S(i: counter) else { return Array(plaintext) }
  110. let plaintextP = addPadding(Array(plaintext), blockSize: 16)
  111. guard let y = cipherOperation(xor(last_y, plaintextP)) else { return Array(plaintext) }
  112. last_y = y.slice
  113. keystream = S
  114. keystreamPosIdx = 0
  115. }
  116. let xored: Array<UInt8> = xor(plaintext[plaintext.startIndex.advanced(by: processed)...], keystream[keystreamPosIdx...])
  117. keystreamPosIdx += xored.count
  118. processed += xored.count
  119. result += xored
  120. }
  121. return result
  122. }
  123. func finalize(encrypt ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
  124. // concatenate T at the end
  125. guard let S0 = try? S(i: 0) else { return ciphertext }
  126. let tag = last_y.prefix(tagLength)
  127. return ciphertext + (xor(tag, S0) as ArraySlice<UInt8>)
  128. }
  129. // TODO
  130. func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
  131. guard let plaintext = cipherOperation(ciphertext) else {
  132. return Array(ciphertext)
  133. }
  134. let result: Array<UInt8> = xor(last_y, plaintext)
  135. last_y = ciphertext
  136. return result
  137. }
  138. func finalize(decrypt plaintext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
  139. return plaintext
  140. }
  141. func willDecryptLast(bytes ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
  142. // get tag of additionalBufferSize size
  143. // `ciphertext` contains at least additionalBufferSize bytes
  144. // overwrite expectedTag property used later for verification
  145. self.expectedTag = Array(ciphertext.suffix(tagLength))
  146. return ciphertext[ciphertext.startIndex..<ciphertext.endIndex.advanced(by: -Swift.min(tagLength,ciphertext.count))]
  147. }
  148. func didDecryptLast(bytes plaintext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
  149. return plaintext
  150. }
  151. }
  152. // Q - octet length of P
  153. // q - octet length of Q. Maximum length (in octets) of payload. An element of {2,3,4,5,6,7,8}
  154. // t - octet length of T (MAC length). An element of {4,6,8,10,12,14,16}
  155. private func format(nonce N: [UInt8], Q: UInt32, q: UInt8, t: UInt8, hasAssociatedData: Bool) throws -> [UInt8] {
  156. var flags0: UInt8 = 0
  157. if hasAssociatedData {
  158. // 7 bit
  159. flags0 |= (1 << 6)
  160. }
  161. // 6,5,4 bit is t in 3 bits
  162. flags0 |= (((t-2)/2) & 0x07) << 3
  163. // 3,2,1 bit is q in 3 bits
  164. flags0 |= ((q-1) & 0x07) << 0
  165. var block0: [UInt8] = Array<UInt8>(repeating: 0, count: 16)
  166. block0[0] = flags0
  167. // N in 1...(15-q) octets, n = 15-q
  168. // n is an element of {7,8,9,10,11,12,13}
  169. let n = 15-Int(q)
  170. guard (n + Int(q)) == 15 else {
  171. // n+q == 15
  172. throw CCMModeWorker.Error.invalidParameter
  173. }
  174. block0[1...n] = N[0...(n-1)]
  175. // Q in (16-q)...15 octets
  176. block0[(16-Int(q))...15] = Q.bytes(totalBytes: Int(q)).slice
  177. return block0
  178. }
  179. /// Formatting of the Counter Blocks. Ctr[i]
  180. /// The counter generation function.
  181. /// Q - octet length of P
  182. /// q - octet length of Q. Maximum length (in octets) of payload. An element of {2,3,4,5,6,7,8}
  183. private func format(counter i: Int, nonce N: [UInt8], q: UInt8) throws -> [UInt8] {
  184. var flags0: UInt8 = 0
  185. // bit 8,7 is Reserved
  186. // bit 4,5,6 shall be set to 0
  187. // 3,2,1 bit is q in 3 bits
  188. flags0 |= ((q-1) & 0x07) << 0
  189. var block = Array<UInt8>(repeating: 0, count: 16) // block[0]
  190. block[0] = flags0
  191. // N in 1...(15-q) octets, n = 15-q
  192. // n is an element of {7,8,9,10,11,12,13}
  193. let n = 15-Int(q)
  194. guard (n + Int(q)) == 15 else {
  195. // n+q == 15
  196. throw CCMModeWorker.Error.invalidParameter
  197. }
  198. block[1...n] = N[0...(n-1)]
  199. // [i]8q in (16-q)...15 octets
  200. block[(16-Int(q))...15] = i.bytes(totalBytes: Int(q)).slice
  201. return block
  202. }
  203. /// Resulting can be partitioned into 16-octet blocks
  204. private func format(aad: [UInt8]) -> [UInt8] {
  205. let a = aad.count
  206. switch Double(a) {
  207. case 0..<65280: // 2^16-2^8
  208. // [a]16
  209. return addPadding(a.bytes(totalBytes: 2) + aad, blockSize: 16)
  210. case 65280..<4_294_967_296: // 2^32
  211. // [a]32
  212. return addPadding([0xFF, 0xFE] + a.bytes(totalBytes: 4) + aad, blockSize: 16)
  213. case 4_294_967_296..<pow(2,64): // 2^64
  214. // [a]64
  215. return addPadding([0xFF, 0xFF] + a.bytes(totalBytes: 8) + aad, blockSize: 16)
  216. default:
  217. // Reserved
  218. return addPadding(aad, blockSize: 16)
  219. }
  220. }
  221. // If data is not a multiple of block size bytes long then the remainder is zero padded
  222. // Note: It's similar to ZeroPadding, but it's not the same.
  223. private func addPadding(_ bytes: Array<UInt8>, blockSize: Int) -> Array<UInt8> {
  224. if bytes.isEmpty {
  225. return Array<UInt8>(repeating: 0, count: blockSize)
  226. }
  227. let remainder = bytes.count % blockSize
  228. if remainder == 0 {
  229. return bytes
  230. }
  231. let paddingCount = blockSize - remainder
  232. if paddingCount > 0 {
  233. return bytes + Array<UInt8>(repeating: 0, count: paddingCount)
  234. }
  235. return bytes
  236. }