HMAC.swift 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  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. import Foundation
  9. public class HMAC {
  10. public enum Variant {
  11. case sha1, sha256, sha384, sha512, md5
  12. var size:Int {
  13. switch (self) {
  14. case .sha1:
  15. return SHA1(NSData()).size
  16. case .sha256:
  17. return SHA2.Variant.sha256.size
  18. case .sha384:
  19. return SHA2.Variant.sha384.size
  20. case .sha512:
  21. return SHA2.Variant.sha512.size
  22. case .md5:
  23. return MD5(NSData()).size
  24. }
  25. }
  26. func calculateHash(# bytes:[UInt8]) -> [UInt8]? {
  27. switch (self) {
  28. case .sha1:
  29. return NSData.withBytes(bytes).sha1()?.arrayOfBytes()
  30. case .sha256:
  31. return NSData.withBytes(bytes).sha256()?.arrayOfBytes()
  32. case .sha384:
  33. return NSData.withBytes(bytes).sha384()?.arrayOfBytes()
  34. case .sha512:
  35. return NSData.withBytes(bytes).sha512()?.arrayOfBytes()
  36. case .md5:
  37. return NSData.withBytes(bytes).md5()?.arrayOfBytes();
  38. }
  39. }
  40. func blockSize() -> Int {
  41. switch self {
  42. case .md5, .sha1, .sha256:
  43. return 64
  44. case .sha384, .sha512:
  45. return 128
  46. }
  47. }
  48. }
  49. var key:[UInt8]
  50. let variant:Variant
  51. class internal func authenticate(# key: [UInt8], message: [UInt8], variant:HMAC.Variant = .md5) -> [UInt8]? {
  52. return HMAC(key, variant: variant)?.authenticate(message: message)
  53. }
  54. // MARK: - Private
  55. internal init? (_ key: [UInt8], variant:HMAC.Variant = .md5) {
  56. self.variant = variant
  57. self.key = key
  58. if (key.count > variant.blockSize()) {
  59. if let hash = variant.calculateHash(bytes: key) {
  60. self.key = hash
  61. }
  62. }
  63. if (key.count < variant.blockSize()) { // keys shorter than blocksize are zero-padded
  64. self.key = key + [UInt8](count: variant.blockSize() - key.count, repeatedValue: 0)
  65. }
  66. }
  67. internal func authenticate(# message:[UInt8]) -> [UInt8]? {
  68. var opad = [UInt8](count: variant.blockSize(), repeatedValue: 0x5c)
  69. for (idx, val) in enumerate(key) {
  70. opad[idx] = key[idx] ^ opad[idx]
  71. }
  72. var ipad = [UInt8](count: variant.blockSize(), repeatedValue: 0x36)
  73. for (idx, val) in enumerate(key) {
  74. ipad[idx] = key[idx] ^ ipad[idx]
  75. }
  76. var finalHash:[UInt8]? = nil;
  77. if let ipadAndMessageHash = variant.calculateHash(bytes: ipad + message) {
  78. finalHash = variant.calculateHash(bytes: opad + ipadAndMessageHash);
  79. }
  80. return finalHash
  81. }
  82. }