HMAC.swift 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. //
  2. // HMAC.swift
  3. // CryptoSwift
  4. //
  5. // Created by Marcin Krzyzanowski on 13/01/15.
  6. // Copyright (c) 2015 Marcin Krzyzanowski. All rights reserved.
  7. //
  8. public final class HMAC: Authenticator {
  9. public enum Error: Swift.Error {
  10. case authenticateError
  11. case invalidInput
  12. }
  13. public enum Variant {
  14. case sha1, sha256, sha384, sha512, md5
  15. var digestLength: Int {
  16. switch (self) {
  17. case .sha1:
  18. return SHA1.digestLength
  19. case .sha256:
  20. return SHA2.Variant.sha256.digestLength
  21. case .sha384:
  22. return SHA2.Variant.sha384.digestLength
  23. case .sha512:
  24. return SHA2.Variant.sha512.digestLength
  25. case .md5:
  26. return MD5.digestLength
  27. }
  28. }
  29. func calculateHash(_ bytes: Array<UInt8>) -> Array<UInt8>? {
  30. switch (self) {
  31. case .sha1:
  32. return Digest.sha1(bytes)
  33. case .sha256:
  34. return Digest.sha256(bytes)
  35. case .sha384:
  36. return Digest.sha384(bytes)
  37. case .sha512:
  38. return Digest.sha512(bytes)
  39. case .md5:
  40. return Digest.md5(bytes)
  41. }
  42. }
  43. func blockSize() -> Int {
  44. switch self {
  45. case .md5:
  46. return MD5.blockSize
  47. case .sha1, .sha256:
  48. return 64
  49. case .sha384, .sha512:
  50. return 128
  51. }
  52. }
  53. }
  54. var key: Array<UInt8>
  55. let variant: Variant
  56. public init(key: Array<UInt8>, variant: HMAC.Variant = .md5) {
  57. self.variant = variant
  58. self.key = key
  59. if key.count > variant.blockSize() {
  60. if let hash = variant.calculateHash(key) {
  61. self.key = hash
  62. }
  63. }
  64. if key.count < variant.blockSize() {
  65. self.key = ZeroPadding().add(to: key, blockSize: variant.blockSize())
  66. }
  67. }
  68. // MARK: Authenticator
  69. public func authenticate(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
  70. var opad = Array<UInt8>(repeating: 0x5c, count: variant.blockSize())
  71. for idx in key.indices {
  72. opad[idx] = key[idx] ^ opad[idx]
  73. }
  74. var ipad = Array<UInt8>(repeating: 0x36, count: variant.blockSize())
  75. for idx in key.indices {
  76. ipad[idx] = key[idx] ^ ipad[idx]
  77. }
  78. guard let ipadAndMessageHash = variant.calculateHash(ipad + bytes),
  79. let result = variant.calculateHash(opad + ipadAndMessageHash) else {
  80. throw Error.authenticateError
  81. }
  82. // return Array(result[0..<10]) // 80 bits
  83. return result
  84. }
  85. }