GCM.swift 13 KB

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