String+SHA1.swift 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. //
  2. // String+SHA1.swift
  3. // Swifter
  4. //
  5. // Copyright 2014-2016 Damian Kołakowski. All rights reserved.
  6. //
  7. #if os(Linux)
  8. import Glibc
  9. #else
  10. import Foundation
  11. #endif
  12. extension String {
  13. public func SHA1() -> String {
  14. return SHA1().reduce("") { $0 + String(format: "%02x", $1) }
  15. }
  16. public func SHA1() -> [UInt8] {
  17. // Alghorithm from: https://en.wikipedia.org/wiki/SHA-1
  18. var message = [UInt8](self.utf8)
  19. var h0 = UInt32(0x67452301)
  20. var h1 = UInt32(0xEFCDAB89)
  21. var h2 = UInt32(0x98BADCFE)
  22. var h3 = UInt32(0x10325476)
  23. var h4 = UInt32(0xC3D2E1F0)
  24. // ml = message length in bits (always a multiple of the number of bits in a character).
  25. let ml = UInt64(message.count * 8)
  26. // append the bit '1' to the message e.g. by adding 0x80 if message length is a multiple of 8 bits.
  27. message.append(0x80)
  28. // append 0 ≤ k < 512 bits '0', such that the resulting message length in bits is congruent to −64 ≡ 448 (mod 512)
  29. let padBytesCount = ( message.count + 8 ) % 64
  30. message.appendContentsOf([UInt8](count: 64 - padBytesCount, repeatedValue: 0))
  31. // append ml, in a 64-bit big-endian integer. Thus, the total length is a multiple of 512 bits.
  32. var mlBigEndian = ml.bigEndian
  33. let bytePtr = withUnsafePointer(&mlBigEndian) { UnsafeBufferPointer<UInt8>(start: UnsafePointer($0), count: sizeofValue(mlBigEndian)) }
  34. message.appendContentsOf(Array(bytePtr))
  35. // Process the message in successive 512-bit chunks ( 64 bytes chunks ):
  36. for chunkStart in 0..<message.count/64 {
  37. var words = [UInt32]()
  38. let chunk = message[chunkStart*64..<chunkStart*64+64]
  39. // break chunk into sixteen 32-bit big-endian words w[i], 0 ≤ i ≤ 15
  40. for i in 0...15 {
  41. let value = chunk.withUnsafeBufferPointer({ UnsafePointer<UInt32>($0.baseAddress + (i*4)).memory })
  42. words.append(value.bigEndian)
  43. }
  44. // Extend the sixteen 32-bit words into eighty 32-bit words:
  45. for i in 16...79 {
  46. let value = words[i-3] ^ words[i-8] ^ words[i-14] ^ words[i-16]
  47. words.append(rotateLeft(value, 1))
  48. }
  49. // Initialize hash value for this chunk:
  50. var a = h0
  51. var b = h1
  52. var c = h2
  53. var d = h3
  54. var e = h4
  55. for i in 0..<80 {
  56. var f = UInt32(0)
  57. var k = UInt32(0)
  58. switch i {
  59. case 0...19:
  60. f = (b & c) | ((~b) & d)
  61. k = 0x5A827999
  62. case 20...39:
  63. f = b ^ c ^ d
  64. k = 0x6ED9EBA1
  65. case 40...59:
  66. f = (b & c) | (b & d) | (c & d)
  67. k = 0x8F1BBCDC
  68. case 60...79:
  69. f = b ^ c ^ d
  70. k = 0xCA62C1D6
  71. default: break
  72. }
  73. let temp = (rotateLeft(a, 5) &+ f &+ e &+ k &+ words[i]) & 0xFFFFFFFF
  74. e = d
  75. d = c
  76. c = rotateLeft(b, 30)
  77. b = a
  78. a = temp
  79. }
  80. // Add this chunk's hash to result so far:
  81. h0 = ( h0 &+ a ) & 0xFFFFFFFF
  82. h1 = ( h1 &+ b ) & 0xFFFFFFFF
  83. h2 = ( h2 &+ c ) & 0xFFFFFFFF
  84. h3 = ( h3 &+ d ) & 0xFFFFFFFF
  85. h4 = ( h4 &+ e ) & 0xFFFFFFFF
  86. }
  87. // Produce the final hash value (big-endian) as a 160 bit number:
  88. var result = [UInt8]()
  89. let h0Big = h0.bigEndian
  90. let h1Big = h1.bigEndian
  91. let h2Big = h2.bigEndian
  92. let h3Big = h3.bigEndian
  93. let h4Big = h4.bigEndian
  94. result += ([UInt8(h0Big & 0xFF), UInt8((h0Big >> 8) & 0xFF), UInt8((h0Big >> 16) & 0xFF), UInt8((h0Big >> 24) & 0xFF)]);
  95. result += ([UInt8(h1Big & 0xFF), UInt8((h1Big >> 8) & 0xFF), UInt8((h1Big >> 16) & 0xFF), UInt8((h1Big >> 24) & 0xFF)]);
  96. result += ([UInt8(h2Big & 0xFF), UInt8((h2Big >> 8) & 0xFF), UInt8((h2Big >> 16) & 0xFF), UInt8((h2Big >> 24) & 0xFF)]);
  97. result += ([UInt8(h3Big & 0xFF), UInt8((h3Big >> 8) & 0xFF), UInt8((h3Big >> 16) & 0xFF), UInt8((h3Big >> 24) & 0xFF)]);
  98. result += ([UInt8(h4Big & 0xff), UInt8((h4Big >> 8) & 0xFF), UInt8((h4Big >> 16) & 0xFF), UInt8((h4Big >> 24) & 0xFF)]);
  99. return result;
  100. }
  101. func rotateLeft(v: UInt32, _ n: UInt32) -> UInt32 {
  102. return ((v << n) & 0xFFFFFFFF) | (v >> (32 - n))
  103. }
  104. }