GCM.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. //
  2. // CryptoSwift
  3. //
  4. // Copyright (C) 2014-2021 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
  5. // This software is provided 'as-is', without any express or implied warranty.
  6. //
  7. // In no event will the authors be held liable for any damages arising from the use of this software.
  8. //
  9. // 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:
  10. //
  11. // - 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.
  12. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  13. // - This notice may not be removed or altered from any source or binary distribution.
  14. //
  15. // Galois/Counter Mode (GCM)
  16. // https://csrc.nist.gov/publications/detail/sp/800-38d/final
  17. // ref: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.694.695&rep=rep1&type=pdf
  18. //
  19. public final class GCM: BlockMode {
  20. public enum Mode {
  21. /// In combined mode, the authentication tag is directly appended to the encrypted message. This is usually what you want.
  22. case combined
  23. /// Some applications may need to store the authentication tag and the encrypted message at different locations.
  24. case detached
  25. }
  26. public let options: BlockModeOption = [.initializationVectorRequired, .useEncryptToDecrypt]
  27. public enum Error: Swift.Error {
  28. /// Invalid IV
  29. case invalidInitializationVector
  30. /// Special symbol FAIL that indicates that the inputs are not authentic.
  31. case fail
  32. }
  33. private let iv: Array<UInt8>
  34. private let additionalAuthenticatedData: Array<UInt8>?
  35. private let mode: Mode
  36. public let customBlockSize: Int? = nil
  37. /// Length of authentication tag, in bytes.
  38. /// For encryption, the value is given as init parameter.
  39. /// For decryption, the length of given authentication tag is used.
  40. private let tagLength: Int
  41. // `authenticationTag` nil for encryption, known tag for decryption
  42. /// For encryption, the value is set at the end of the encryption.
  43. /// For decryption, this is a known Tag to validate against.
  44. public var authenticationTag: Array<UInt8>?
  45. // encrypt
  46. /// Possible tag lengths: 4,8,12,13,14,15,16
  47. public init(iv: Array<UInt8>, additionalAuthenticatedData: Array<UInt8>? = nil, tagLength: Int = 16, mode: Mode = .detached) {
  48. self.iv = iv
  49. self.additionalAuthenticatedData = additionalAuthenticatedData
  50. self.mode = mode
  51. self.tagLength = tagLength
  52. }
  53. // decrypt
  54. public convenience init(iv: Array<UInt8>, authenticationTag: Array<UInt8>, additionalAuthenticatedData: Array<UInt8>? = nil, mode: Mode = .detached) {
  55. self.init(iv: iv, additionalAuthenticatedData: additionalAuthenticatedData, tagLength: authenticationTag.count, mode: mode)
  56. self.authenticationTag = authenticationTag
  57. }
  58. public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker {
  59. if self.iv.isEmpty {
  60. throw Error.invalidInitializationVector
  61. }
  62. let worker = GCMModeWorker(iv: iv.slice, aad: self.additionalAuthenticatedData?.slice, expectedTag: self.authenticationTag, tagLength: self.tagLength, mode: self.mode, cipherOperation: cipherOperation)
  63. worker.didCalculateTag = { [weak self] tag in
  64. self?.authenticationTag = tag
  65. }
  66. return worker
  67. }
  68. }
  69. // MARK: - Worker
  70. final class GCMModeWorker: BlockModeWorker, FinalizingEncryptModeWorker, FinalizingDecryptModeWorker {
  71. let cipherOperation: CipherOperationOnBlock
  72. // Callback called when authenticationTag is ready
  73. var didCalculateTag: ((Array<UInt8>) -> Void)?
  74. private let tagLength: Int
  75. // GCM nonce is 96-bits by default. It's the most effective length for the IV
  76. private static let nonceSize = 12
  77. // GCM is designed for 128-bit ciphers like AES (but not really for Blowfish). 64-bit mode is not implemented.
  78. let blockSize = 16 // 128 bit
  79. let additionalBufferSize: Int
  80. private let iv: ArraySlice<UInt8>
  81. private let mode: GCM.Mode
  82. private var counter: UInt128
  83. private let eky0: UInt128 // move to GF?
  84. private let h: UInt128
  85. // Additional authenticated data
  86. private let aad: ArraySlice<UInt8>?
  87. // Known Tag used to validate during decryption
  88. private var expectedTag: Array<UInt8>?
  89. // Note: need new worker to reset instance
  90. // Use empty aad if not specified. AAD is optional.
  91. private lazy var gf: GF = {
  92. if let aad = aad {
  93. return GF(aad: Array(aad), h: h, blockSize: blockSize)
  94. }
  95. return GF(aad: [UInt8](), h: h, blockSize: blockSize)
  96. }()
  97. init(iv: ArraySlice<UInt8>, aad: ArraySlice<UInt8>? = nil, expectedTag: Array<UInt8>? = nil, tagLength: Int, mode: GCM.Mode, cipherOperation: @escaping CipherOperationOnBlock) {
  98. self.cipherOperation = cipherOperation
  99. self.iv = iv
  100. self.mode = mode
  101. self.aad = aad
  102. self.expectedTag = expectedTag
  103. self.tagLength = tagLength
  104. self.h = UInt128(cipherOperation(Array<UInt8>(repeating: 0, count: self.blockSize).slice)!) // empty block
  105. if mode == .combined {
  106. self.additionalBufferSize = tagLength
  107. } else {
  108. self.additionalBufferSize = 0
  109. }
  110. // Assume nonce is 12 bytes long, otherwise initial counter would be calulated from GHASH
  111. // counter = GF.ghash(aad: [UInt8](), ciphertext: nonce)
  112. if iv.count == GCMModeWorker.nonceSize {
  113. self.counter = makeCounter(nonce: Array(self.iv))
  114. } else {
  115. self.counter = GF.ghash(h: self.h, aad: [UInt8](), ciphertext: Array(iv), blockSize: self.blockSize)
  116. }
  117. // Set constants
  118. self.eky0 = UInt128(cipherOperation(self.counter.bytes.slice)!)
  119. }
  120. func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
  121. self.counter = incrementCounter(self.counter)
  122. guard let ekyN = cipherOperation(counter.bytes.slice) else {
  123. return Array(plaintext)
  124. }
  125. // plaintext block ^ ek1
  126. let ciphertext = xor(plaintext, ekyN) as Array<UInt8>
  127. // update ghash incrementally
  128. gf.ghashUpdate(block: ciphertext)
  129. return Array(ciphertext)
  130. }
  131. @inlinable
  132. func finalize(encrypt ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
  133. // Calculate MAC tag.
  134. let ghash = self.gf.ghashFinish()
  135. let tag = Array((ghash ^ self.eky0).bytes.prefix(self.tagLength))
  136. // Notify handler
  137. self.didCalculateTag?(tag)
  138. switch self.mode {
  139. case .combined:
  140. return (ciphertext + tag).slice
  141. case .detached:
  142. return ciphertext
  143. }
  144. }
  145. @inlinable
  146. func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
  147. self.counter = incrementCounter(self.counter)
  148. // update ghash incrementally
  149. self.gf.ghashUpdate(block: Array(ciphertext))
  150. guard let ekN = cipherOperation(counter.bytes.slice) else {
  151. return Array(ciphertext)
  152. }
  153. // ciphertext block ^ ek1
  154. let plaintext = xor(ciphertext, ekN) as Array<UInt8>
  155. return plaintext
  156. }
  157. // The authenticated decryption operation has five inputs: K, IV , C, A, and T. It has only a single
  158. // output, either the plaintext value P or a special symbol FAIL that indicates that the inputs are not
  159. // authentic.
  160. @discardableResult
  161. func willDecryptLast(bytes ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
  162. // Validate tag
  163. switch self.mode {
  164. case .combined:
  165. // overwrite expectedTag property used later for verification
  166. self.expectedTag = Array(ciphertext.suffix(self.tagLength))
  167. return ciphertext[ciphertext.startIndex..<ciphertext.endIndex.advanced(by: -Swift.min(tagLength, ciphertext.count))]
  168. case .detached:
  169. return ciphertext
  170. }
  171. }
  172. @inlinable
  173. func didDecryptLast(bytes plaintext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
  174. // Calculate MAC tag.
  175. let ghash = self.gf.ghashFinish()
  176. let computedTag = Array((ghash ^ self.eky0).bytes.prefix(self.tagLength))
  177. // Validate tag
  178. guard let expectedTag = self.expectedTag, computedTag == expectedTag else {
  179. throw GCM.Error.fail
  180. }
  181. return plaintext
  182. }
  183. func finalize(decrypt plaintext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
  184. // do nothing
  185. plaintext
  186. }
  187. }
  188. // MARK: - Local utils
  189. private func makeCounter(nonce: Array<UInt8>) -> UInt128 {
  190. UInt128(nonce + [0, 0, 0, 1])
  191. }
  192. // Successive counter values are generated using the function incr(), which treats the rightmost 32
  193. // bits of its argument as a nonnegative integer with the least significant bit on the right
  194. private func incrementCounter(_ counter: UInt128) -> UInt128 {
  195. let b = counter.i.b + 1
  196. let a = (b == 0 ? counter.i.a + 1 : counter.i.a)
  197. return UInt128((a, b))
  198. }
  199. // If data is not a multiple of block size bytes long then the remainder is zero padded
  200. // Note: It's similar to ZeroPadding, but it's not the same.
  201. private func addPadding(_ bytes: Array<UInt8>, blockSize: Int) -> Array<UInt8> {
  202. if bytes.isEmpty {
  203. return Array<UInt8>(repeating: 0, count: blockSize)
  204. }
  205. let remainder = bytes.count % blockSize
  206. if remainder == 0 {
  207. return bytes
  208. }
  209. let paddingCount = blockSize - remainder
  210. if paddingCount > 0 {
  211. return bytes + Array<UInt8>(repeating: 0, count: paddingCount)
  212. }
  213. return bytes
  214. }
  215. // MARK: - GF
  216. /// The Field GF(2^128)
  217. private final class GF {
  218. static let r = UInt128(a: 0xE100000000000000, b: 0)
  219. let blockSize: Int
  220. let h: UInt128
  221. // AAD won't change
  222. let aadLength: Int
  223. // Updated for every consumed block
  224. var ciphertextLength: Int
  225. // Start with 0
  226. var x: UInt128
  227. init(aad: [UInt8], h: UInt128, blockSize: Int) {
  228. self.blockSize = blockSize
  229. self.aadLength = aad.count
  230. self.ciphertextLength = 0
  231. self.h = h
  232. self.x = 0
  233. // Calculate for AAD at the begining
  234. self.x = GF.calculateX(aad: aad, x: self.x, h: h, blockSize: blockSize)
  235. }
  236. @discardableResult
  237. func ghashUpdate(block ciphertextBlock: Array<UInt8>) -> UInt128 {
  238. self.ciphertextLength += ciphertextBlock.count
  239. self.x = GF.calculateX(block: addPadding(ciphertextBlock, blockSize: self.blockSize), x: self.x, h: self.h, blockSize: self.blockSize)
  240. return self.x
  241. }
  242. func ghashFinish() -> UInt128 {
  243. // len(A) || len(C)
  244. let len = UInt128(a: UInt64(aadLength * 8), b: UInt64(ciphertextLength * 8))
  245. x = GF.multiply(self.x ^ len, self.h)
  246. return self.x
  247. }
  248. // GHASH. One-time calculation
  249. static func ghash(x startx: UInt128 = 0, h: UInt128, aad: Array<UInt8>, ciphertext: Array<UInt8>, blockSize: Int) -> UInt128 {
  250. var x = self.calculateX(aad: aad, x: startx, h: h, blockSize: blockSize)
  251. x = self.calculateX(ciphertext: ciphertext, x: x, h: h, blockSize: blockSize)
  252. // len(aad) || len(ciphertext)
  253. let len = UInt128(a: UInt64(aad.count * 8), b: UInt64(ciphertext.count * 8))
  254. x = self.multiply(x ^ len, h)
  255. return x
  256. }
  257. // Calculate Ciphertext part, for all blocks
  258. // Not used with incremental calculation.
  259. private static func calculateX(ciphertext: [UInt8], x startx: UInt128, h: UInt128, blockSize: Int) -> UInt128 {
  260. let pciphertext = addPadding(ciphertext, blockSize: blockSize)
  261. let blocksCount = pciphertext.count / blockSize
  262. var x = startx
  263. for i in 0..<blocksCount {
  264. let cpos = i * blockSize
  265. let block = pciphertext[pciphertext.startIndex.advanced(by: cpos)..<pciphertext.startIndex.advanced(by: cpos + blockSize)]
  266. x = self.calculateX(block: Array(block), x: x, h: h, blockSize: blockSize)
  267. }
  268. return x
  269. }
  270. // block is expected to be padded with addPadding
  271. private static func calculateX(block ciphertextBlock: Array<UInt8>, x: UInt128, h: UInt128, blockSize: Int) -> UInt128 {
  272. let k = x ^ UInt128(ciphertextBlock)
  273. return self.multiply(k, h)
  274. }
  275. // Calculate AAD part, for all blocks
  276. private static func calculateX(aad: [UInt8], x startx: UInt128, h: UInt128, blockSize: Int) -> UInt128 {
  277. let paad = addPadding(aad, blockSize: blockSize)
  278. let blocksCount = paad.count / blockSize
  279. var x = startx
  280. for i in 0..<blocksCount {
  281. let apos = i * blockSize
  282. let k = x ^ UInt128(paad[paad.startIndex.advanced(by: apos)..<paad.startIndex.advanced(by: apos + blockSize)])
  283. x = self.multiply(k, h)
  284. }
  285. return x
  286. }
  287. // Multiplication GF(2^128).
  288. private static func multiply(_ x: UInt128, _ y: UInt128) -> UInt128 {
  289. var z: UInt128 = 0
  290. var v = x
  291. var k = UInt128(a: 1 << 63, b: 0)
  292. for _ in 0..<128 {
  293. if y & k == k {
  294. z = z ^ v
  295. }
  296. if v & 1 != 1 {
  297. v = v >> 1
  298. } else {
  299. v = (v >> 1) ^ self.r
  300. }
  301. k = k >> 1
  302. }
  303. return z
  304. }
  305. }