Poly1305.swift 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. //
  2. // Poly1305.swift
  3. // CryptoSwift
  4. //
  5. // Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
  6. // This software is provided 'as-is', without any express or implied warranty.
  7. //
  8. // In no event will the authors be held liable for any damages arising from the use of this software.
  9. //
  10. // 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:
  11. //
  12. // - 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.
  13. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  14. // - This notice may not be removed or altered from any source or binary distribution.
  15. //
  16. // http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-4
  17. // nacl/crypto_onetimeauth/poly1305/ref/auth.c
  18. //
  19. /// Poly1305 takes a 32-byte, one-time key and a message and produces a 16-byte tag that authenticates the
  20. /// message such that an attacker has a negligible chance of producing a valid tag for an inauthentic message.
  21. public final class Poly1305: Authenticator {
  22. public enum Error: Swift.Error {
  23. case authenticateError
  24. }
  25. public static let blockSize: Int = 16
  26. private let key: SecureBytes
  27. /// - parameter key: 32-byte key
  28. public init(key: Array<UInt8>) {
  29. self.key = SecureBytes(bytes: key)
  30. }
  31. private func squeeze(h: inout Array<UInt32>) {
  32. assert(h.count == 17)
  33. var u: UInt32 = 0
  34. for j in 0..<16 {
  35. u = u &+ h[j]
  36. h[j] = u & 255
  37. u = u >> 8
  38. }
  39. u = u &+ h[16]
  40. h[16] = u & 3
  41. u = 5 * (u >> 2)
  42. for j in 0..<16 {
  43. u = u &+ h[j]
  44. h[j] = u & 255
  45. u = u >> 8
  46. }
  47. u = u &+ h[16]
  48. h[16] = u
  49. }
  50. private func add(h: inout Array<UInt32>, c: Array<UInt32>) {
  51. assert(h.count == 17 && c.count == 17)
  52. var u: UInt32 = 0
  53. for j in 0..<17 {
  54. u = u &+ (h[j] &+ c[j])
  55. h[j] = u & 255
  56. u = u >> 8
  57. }
  58. }
  59. private func mulmod(h: inout Array<UInt32>, r: Array<UInt32>) {
  60. var hr = Array<UInt32>(repeating: 0, count: 17)
  61. var u: UInt32 = 0
  62. for i in 0..<17 {
  63. u = 0
  64. for j in 0...i {
  65. u = u &+ (h[j] * r[i &- j])
  66. }
  67. for j in (i + 1)..<17 {
  68. u = u &+ (320 * h[j] * r[i &+ 17 &- j])
  69. }
  70. hr[i] = u
  71. }
  72. h = hr
  73. squeeze(h: &h)
  74. }
  75. private func freeze(h: inout Array<UInt32>) {
  76. let horig = h
  77. add(h: &h, c: [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252])
  78. let negative = UInt32(bitPattern: -Int32(h[16] >> 7))
  79. for j in 0..<17 {
  80. h[j] ^= negative & (horig[j] ^ h[j])
  81. }
  82. }
  83. /// the key is partitioned into two parts, called "r" and "s"
  84. fileprivate func onetimeauth(message input: Array<UInt8>, key k: Array<UInt8>) -> Array<UInt8> {
  85. // clamp
  86. var r = Array<UInt32>(repeating: 0, count: 17)
  87. var h = Array<UInt32>(repeating: 0, count: 17)
  88. var c = Array<UInt32>(repeating: 0, count: 17)
  89. r[0] = UInt32(k[0])
  90. r[1] = UInt32(k[1])
  91. r[2] = UInt32(k[2])
  92. r[3] = UInt32(k[3] & 15)
  93. r[4] = UInt32(k[4] & 252)
  94. r[5] = UInt32(k[5])
  95. r[6] = UInt32(k[6])
  96. r[7] = UInt32(k[7] & 15)
  97. r[8] = UInt32(k[8] & 252)
  98. r[9] = UInt32(k[9])
  99. r[10] = UInt32(k[10])
  100. r[11] = UInt32(k[11] & 15)
  101. r[12] = UInt32(k[12] & 252)
  102. r[13] = UInt32(k[13])
  103. r[14] = UInt32(k[14])
  104. r[15] = UInt32(k[15] & 15)
  105. r[16] = 0
  106. var inlen = input.count
  107. var inpos = 0
  108. while inlen > 0 {
  109. for j in 0..<c.count {
  110. c[j] = 0
  111. }
  112. let maxj = min(inlen, 16)
  113. for j in 0..<maxj {
  114. c[j] = UInt32(input[inpos + j])
  115. }
  116. c[maxj] = 1
  117. inpos = inpos + maxj
  118. inlen = inlen - maxj
  119. add(h: &h, c: c)
  120. mulmod(h: &h, r: r)
  121. }
  122. freeze(h: &h)
  123. for j in 0..<16 {
  124. c[j] = UInt32(k[j + 16])
  125. }
  126. c[16] = 0
  127. add(h: &h, c: c)
  128. return h[0..<16].map {
  129. UInt8($0 & 0xff)
  130. }
  131. }
  132. // MARK: - Authenticator
  133. /**
  134. Calculate Message Authentication Code (MAC) for message.
  135. Calculation context is discarder on instance deallocation.
  136. - parameter bytes: Message
  137. - returns: 16-byte tag that authenticates the message
  138. */
  139. public func authenticate(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
  140. return onetimeauth(message: bytes, key: Array(key))
  141. }
  142. }