Poly1305.swift 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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. // nacl/crypto_onetimeauth/poly1305/ref/auth.c
  10. //
  11. /// Poly1305 takes a 32-byte, one-time key and a message and produces a 16-byte tag that authenticates the
  12. /// message such that an attacker has a negligible chance of producing a valid tag for an inauthentic message.
  13. public final class Poly1305: Authenticator {
  14. public enum Error: Swift.Error {
  15. case authenticateError
  16. }
  17. public static let blockSize: Int = 16
  18. private let key: SecureBytes
  19. /// - parameter key: 32-byte key
  20. public init(key: Array<UInt8>) {
  21. self.key = SecureBytes(bytes: key)
  22. }
  23. private func squeeze(h: inout Array<UInt32>) {
  24. assert(h.count == 17)
  25. var u: UInt32 = 0
  26. for j in 0..<16 {
  27. u = u &+ h[j]
  28. h[j] = u & 255
  29. u = u >> 8
  30. }
  31. u = u &+ h[16]
  32. h[16] = u & 3
  33. u = 5 * (u >> 2)
  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
  41. }
  42. private func add(h: inout Array<UInt32>, c: Array<UInt32>) {
  43. assert(h.count == 17 && c.count == 17)
  44. var u: UInt32 = 0
  45. for j in 0..<17 {
  46. u = u &+ (h[j] &+ c[j])
  47. h[j] = u & 255
  48. u = u >> 8
  49. }
  50. }
  51. private func mulmod(h: inout Array<UInt32>, r: Array<UInt32>) {
  52. var hr = Array<UInt32>(repeating: 0, count: 17)
  53. var u: UInt32 = 0
  54. for i in 0..<17 {
  55. u = 0
  56. for j in 0...i {
  57. u = u &+ (h[j] * r[i &- j])
  58. }
  59. for j in (i + 1)..<17 {
  60. u = u &+ (320 * h[j] * r[i &+ 17 &- j])
  61. }
  62. hr[i] = u
  63. }
  64. h = hr
  65. self.squeeze(h: &h)
  66. }
  67. private func freeze(h: inout Array<UInt32>) {
  68. let horig = h
  69. add(h: &h, c: [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252])
  70. let negative = UInt32(bitPattern: -Int32(h[16] >> 7))
  71. for j in 0..<17 {
  72. h[j] ^= negative & (horig[j] ^ h[j])
  73. }
  74. }
  75. /// the key is partitioned into two parts, called "r" and "s"
  76. fileprivate func onetimeauth(message input: Array<UInt8>, key k: Array<UInt8>) -> Array<UInt8> {
  77. // clamp
  78. var r = Array<UInt32>(repeating: 0, count: 17)
  79. var h = Array<UInt32>(repeating: 0, count: 17)
  80. var c = Array<UInt32>(repeating: 0, count: 17)
  81. r[0] = UInt32(k[0])
  82. r[1] = UInt32(k[1])
  83. r[2] = UInt32(k[2])
  84. r[3] = UInt32(k[3] & 15)
  85. r[4] = UInt32(k[4] & 252)
  86. r[5] = UInt32(k[5])
  87. r[6] = UInt32(k[6])
  88. r[7] = UInt32(k[7] & 15)
  89. r[8] = UInt32(k[8] & 252)
  90. r[9] = UInt32(k[9])
  91. r[10] = UInt32(k[10])
  92. r[11] = UInt32(k[11] & 15)
  93. r[12] = UInt32(k[12] & 252)
  94. r[13] = UInt32(k[13])
  95. r[14] = UInt32(k[14])
  96. r[15] = UInt32(k[15] & 15)
  97. r[16] = 0
  98. var inlen = input.count
  99. var inpos = 0
  100. while inlen > 0 {
  101. for j in 0..<c.count {
  102. c[j] = 0
  103. }
  104. let maxj = min(inlen, 16)
  105. for j in 0..<maxj {
  106. c[j] = UInt32(input[inpos + j])
  107. }
  108. c[maxj] = 1
  109. inpos = inpos + maxj
  110. inlen = inlen - maxj
  111. self.add(h: &h, c: c)
  112. self.mulmod(h: &h, r: r)
  113. }
  114. self.freeze(h: &h)
  115. for j in 0..<16 {
  116. c[j] = UInt32(k[j + 16])
  117. }
  118. c[16] = 0
  119. add(h: &h, c: c)
  120. return h[0..<16].map {
  121. UInt8($0 & 0xFF)
  122. }
  123. }
  124. // MARK: - Authenticator
  125. /**
  126. Calculate Message Authentication Code (MAC) for message.
  127. Calculation context is discarder on instance deallocation.
  128. - parameter bytes: Message
  129. - returns: 16-byte tag that authenticates the message
  130. */
  131. public func authenticate(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
  132. return onetimeauth(message: bytes, key: Array(self.key))
  133. }
  134. }