Poly1305.swift 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. //
  2. // Poly1305.swift
  3. // CryptoSwift
  4. //
  5. // Created by Marcin Krzyzanowski on 30/08/14.
  6. // Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
  7. //
  8. // http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-4
  9. //
  10. /// Poly1305 takes a 32-byte, one-time key and a message and produces a 16-byte tag that authenticates the
  11. /// message such that an attacker has a negligible chance of producing a valid tag for an inauthentic message.
  12. final public class Poly1305: Authenticator {
  13. public enum Error: Swift.Error {
  14. case authenticateError
  15. }
  16. let blockSize = 16
  17. private var ctx:Context?
  18. private final class Context {
  19. var r = Array<UInt8>(repeating: 0, count: 17)
  20. var h = Array<UInt8>(repeating: 0, count: 17)
  21. var pad = Array<UInt8>(repeating: 0, count: 17)
  22. var buffer = Array<UInt8>(repeating: 0, count: 16)
  23. var final:UInt8 = 0
  24. var leftover:Int = 0
  25. init(_ key: Array<UInt8>) {
  26. precondition(key.count == 32, "Invalid key length")
  27. for i in 0..<17 {
  28. h[i] = 0
  29. }
  30. r[0] = key[0] & 0xff;
  31. r[1] = key[1] & 0xff;
  32. r[2] = key[2] & 0xff;
  33. r[3] = key[3] & 0x0f;
  34. r[4] = key[4] & 0xfc;
  35. r[5] = key[5] & 0xff;
  36. r[6] = key[6] & 0xff;
  37. r[7] = key[7] & 0x0f;
  38. r[8] = key[8] & 0xfc;
  39. r[9] = key[9] & 0xff;
  40. r[10] = key[10] & 0xff;
  41. r[11] = key[11] & 0x0f;
  42. r[12] = key[12] & 0xfc;
  43. r[13] = key[13] & 0xff;
  44. r[14] = key[14] & 0xff;
  45. r[15] = key[15] & 0x0f;
  46. r[16] = 0
  47. for i in 0..<16 {
  48. pad[i] = key[i + 16]
  49. }
  50. pad[16] = 0
  51. leftover = 0
  52. final = 0
  53. }
  54. deinit {
  55. for i in 0..<buffer.count {
  56. buffer[i] = 0
  57. }
  58. for i in 0..<r.count {
  59. r[i] = 0
  60. h[i] = 0
  61. pad[i] = 0
  62. final = 0
  63. leftover = 0
  64. }
  65. }
  66. }
  67. /// - parameter key: 32-byte key
  68. public init (key: Array<UInt8>) {
  69. ctx = Context(key)
  70. }
  71. // MARK: - Private
  72. /**
  73. Add message to be processed
  74. - parameter context: Context
  75. - parameter message: message
  76. - parameter bytes: length of the message fragment to be processed
  77. */
  78. private func update(_ context:Context, message:Array<UInt8>, bytes:Int? = nil) {
  79. var bytes = bytes ?? message.count
  80. var mPos = 0
  81. /* handle leftover */
  82. if (context.leftover > 0) {
  83. var want = blockSize - context.leftover
  84. if (want > bytes) {
  85. want = bytes
  86. }
  87. for i in 0..<want {
  88. context.buffer[context.leftover + i] = message[mPos + i]
  89. }
  90. bytes -= want
  91. mPos += want
  92. context.leftover += want
  93. if (context.leftover < blockSize) {
  94. return
  95. }
  96. blocks(context, m: context.buffer)
  97. context.leftover = 0
  98. }
  99. /* process full blocks */
  100. if (bytes >= blockSize) {
  101. let want = bytes & ~(blockSize - 1)
  102. blocks(context, m: message, startPos: mPos)
  103. mPos += want
  104. bytes -= want;
  105. }
  106. /* store leftover */
  107. if (bytes > 0) {
  108. for i in 0..<bytes {
  109. context.buffer[context.leftover + i] = message[mPos + i]
  110. }
  111. context.leftover += bytes
  112. }
  113. }
  114. private func finish(_ context:Context) -> Array<UInt8>? {
  115. var mac = Array<UInt8>(repeating: 0, count: 16);
  116. /* process the remaining block */
  117. if (context.leftover > 0) {
  118. context.buffer[context.leftover] = 1
  119. for i in (context.leftover + 1)..<blockSize {
  120. context.buffer[i] = 0
  121. }
  122. context.final = 1
  123. blocks(context, m: context.buffer)
  124. }
  125. /* fully reduce h */
  126. freeze(context)
  127. /* h = (h + pad) % (1 << 128) */
  128. add(context, c: context.pad)
  129. for i in 0..<mac.count {
  130. mac[i] = context.h[i]
  131. }
  132. return mac
  133. }
  134. // MARK: - Utils
  135. private func add(_ context:Context, c:Array<UInt8>) {
  136. if (context.h.count != 17 && c.count != 17) {
  137. assertionFailure()
  138. return
  139. }
  140. var u:UInt16 = 0
  141. for i in 0..<17 {
  142. u += UInt16(context.h[i]) + UInt16(c[i])
  143. context.h[i] = UInt8.with(value: u)
  144. u = u >> 8
  145. }
  146. return
  147. }
  148. private func squeeze(_ context:Context, hr:Array<UInt32>) {
  149. if (context.h.count != 17 && hr.count != 17) {
  150. assertionFailure()
  151. return
  152. }
  153. var u:UInt32 = 0
  154. for i in 0..<16 {
  155. u += hr[i];
  156. context.h[i] = UInt8.with(value: u) // crash! h[i] = UInt8(u) & 0xff
  157. u >>= 8;
  158. }
  159. u += hr[16]
  160. context.h[16] = UInt8.with(value: u) & 0x03
  161. u >>= 2
  162. u += (u << 2); /* u *= 5; */
  163. for i in 0..<16 {
  164. u += UInt32(context.h[i])
  165. context.h[i] = UInt8.with(value: u) // crash! h[i] = UInt8(u) & 0xff
  166. u >>= 8
  167. }
  168. context.h[16] += UInt8.with(value: u);
  169. }
  170. private func freeze(_ context:Context) {
  171. assert(context.h.count == 17,"Invalid length")
  172. if (context.h.count != 17) {
  173. return
  174. }
  175. let minusp:Array<UInt8> = [0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc]
  176. var horig:Array<UInt8> = Array<UInt8>(repeating: 0, count: 17)
  177. /* compute h + -p */
  178. for i in 0..<17 {
  179. horig[i] = context.h[i]
  180. }
  181. add(context, c: minusp)
  182. /* select h if h < p, or h + -p if h >= p */
  183. let bits:[Bit] = (context.h[16] >> 7).bits()
  184. let invertedBits = bits.map({ (bit) -> Bit in
  185. return bit.inverted()
  186. })
  187. let negative = UInt8(bits: invertedBits)
  188. for i in 0..<17 {
  189. context.h[i] ^= negative & (horig[i] ^ context.h[i]);
  190. }
  191. }
  192. private func blocks(_ context:Context, m:Array<UInt8>, startPos:Int = 0) {
  193. var bytes = m.count
  194. let hibit = context.final ^ 1 // 1 <<128
  195. var mPos = startPos
  196. while (bytes >= Int(blockSize)) {
  197. var hr:Array<UInt32> = Array<UInt32>(repeating: 0, count: 17)
  198. var u:UInt32 = 0
  199. var c:Array<UInt8> = Array<UInt8>(repeating: 0, count: 17)
  200. /* h += m */
  201. for i in 0..<16 {
  202. c[i] = m[mPos + i]
  203. }
  204. c[16] = hibit
  205. add(context, c: c)
  206. /* h *= r */
  207. for i in 0..<17 {
  208. u = 0
  209. for j in 0...i {
  210. u = u + UInt32(UInt16(context.h[j])) * UInt32(context.r[i - j]) // u += (unsigned short)st->h[j] * st->r[i - j];
  211. }
  212. for j in (i+1)..<17 {
  213. var v:UInt32 = UInt32(UInt16(context.h[j])) * UInt32(context.r[i + 17 - j]) // unsigned long v = (unsigned short)st->h[j] * st->r[i + 17 - j];
  214. v = ((v << 8) &+ (v << 6))
  215. u = u &+ v
  216. }
  217. hr[i] = u
  218. }
  219. squeeze(context, hr: hr)
  220. mPos += blockSize
  221. bytes -= blockSize
  222. }
  223. }
  224. //MARK: - Authenticator
  225. /**
  226. Calculate Message Authentication Code (MAC) for message.
  227. Calculation context is discarder on instance deallocation.
  228. - parameter bytes: Message
  229. - returns: 16-byte tag that authenticates the message
  230. */
  231. public func authenticate(_ bytes:Array<UInt8>) throws -> Array<UInt8> {
  232. guard let ctx = self.ctx else {
  233. throw Error.authenticateError
  234. }
  235. update(ctx, message: bytes)
  236. guard let result = finish(ctx) else {
  237. throw Error.authenticateError
  238. }
  239. return result
  240. }
  241. }