1
0

SHA256.swift 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. //
  2. // SHA256.swift
  3. // Swifter
  4. //
  5. // Copyright © 2016 Damian Kołakowski. All rights reserved.
  6. //
  7. #if os(Linux)
  8. import Glibc
  9. #else
  10. import Foundation
  11. #endif
  12. public struct SHA256 {
  13. public static func hash(_ input: [UInt8]) -> [UInt8] {
  14. // Alghorithm from: https://en.wikipedia.org/wiki/SHA-2
  15. // http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
  16. var message = input
  17. var h0 = UInt32(littleEndian: 0x6a09e667)
  18. var h1 = UInt32(littleEndian: 0xbb67ae85)
  19. var h2 = UInt32(littleEndian: 0x3c6ef372)
  20. var h3 = UInt32(littleEndian: 0xa54ff53a)
  21. var h4 = UInt32(littleEndian: 0x510e527f)
  22. var h5 = UInt32(littleEndian: 0x9b05688c)
  23. var h6 = UInt32(littleEndian: 0x1f83d9ab)
  24. var h7 = UInt32(littleEndian: 0x5be0cd19)
  25. // ml = message length in bits (always a multiple of the number of bits in a character).
  26. let ml = UInt64(message.count * 8)
  27. // append the bit '1' to the message e.g. by adding 0x80 if message length is a multiple of 8 bits.
  28. message.append(0x80)
  29. // append 0 ≤ k < 512 bits '0', such that the resulting message length in bits is congruent to −64 ≡ 448 (mod 512)
  30. let padBytesCount = ( message.count + 8 ) % 64
  31. message.append(contentsOf: [UInt8](repeating: 0, count: 64 - padBytesCount))
  32. // append ml, in a 64-bit big-endian integer. Thus, the total length is a multiple of 512 bits.
  33. var mlBigEndian = ml.bigEndian
  34. withUnsafePointer(to: &mlBigEndian) {
  35. message.append(contentsOf: Array(UnsafeBufferPointer<UInt8>(start: UnsafePointer(OpaquePointer($0)), count: 8)))
  36. }
  37. // Process the message in successive 512-bit chunks ( 64 bytes chunks ):
  38. for chunkStart in 0..<message.count/64 {
  39. var words = [UInt32](repeating: 0, count: 64)
  40. let chunk = message[chunkStart*64..<chunkStart*64+64]
  41. // Break chunk into sixteen 32-bit big-endian words w[i], 0 ≤ i ≤ 15
  42. for i in 0...15 {
  43. let value = chunk.withUnsafeBufferPointer({ UnsafePointer<UInt32>(OpaquePointer($0.baseAddress! + (i*4))).pointee})
  44. words[i] = value.bigEndian
  45. }
  46. // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array:
  47. for i in 16..<words.count {
  48. let s0 = (rotateRight(words[i-15], 7)) ^ (rotateRight(words[i-15], 18)) ^ (words[i-15] >> 3 )
  49. let s1 = (rotateRight(words[i-2 ], 17)) ^ (rotateRight(words[i-2 ], 19)) ^ (words[i-2 ] >> 10)
  50. words[i] = words[i-16] &+ s0 &+ words[i-7] &+ s1
  51. }
  52. // Initialize hash value for this chunk:
  53. var a = h0
  54. var b = h1
  55. var c = h2
  56. var d = h3
  57. var e = h4
  58. var f = h5
  59. var g = h6
  60. var h = h7
  61. for i in 0...63 {
  62. let S0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22)
  63. let S1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25)
  64. let ch = (e & f) ^ ((~e) & g)
  65. let maj = (a & b) ^ (a & c) ^ (b & c)
  66. let temp1 = h &+ S1 &+ ch &+ K[i] &+ words[i]
  67. let temp2 = S0 &+ maj
  68. h = g
  69. g = f
  70. f = e
  71. e = d &+ temp1
  72. d = c
  73. c = b
  74. b = a
  75. a = temp1 &+ temp2
  76. }
  77. // Add this chunk's hash to result so far:
  78. h0 = ( h0 &+ a )
  79. h1 = ( h1 &+ b )
  80. h2 = ( h2 &+ c )
  81. h3 = ( h3 &+ d )
  82. h4 = ( h4 &+ e )
  83. h5 = ( h5 &+ f )
  84. h6 = ( h6 &+ g )
  85. h7 = ( h7 &+ h )
  86. }
  87. // Produce the final hash value (big-endian):
  88. var digest = [UInt8]()
  89. [h0, h1, h2, h3, h4, h5, h6, h7].forEach { value in
  90. var bigEndianVersion = value.bigEndian
  91. withUnsafePointer(to: &bigEndianVersion) {
  92. digest.append(contentsOf: Array(UnsafeBufferPointer<UInt8>(start: UnsafePointer(OpaquePointer($0)), count: 4)))
  93. }
  94. }
  95. return digest
  96. }
  97. private static func rotateRight(_ v : UInt32, _ n: UInt32) -> UInt32 {
  98. return (v >> n) | (v << (32 - n))
  99. }
  100. private static func rotateLeft(_ v: UInt32, _ n: UInt32) -> UInt32 {
  101. return ((v << n) & 0xFFFFFFFF) | (v >> (32 - n))
  102. }
  103. private static var K: [UInt32] = [
  104. 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
  105. 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
  106. 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
  107. 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
  108. 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
  109. 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
  110. 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
  111. 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
  112. ]
  113. }
  114. extension String {
  115. public func sha256() -> String {
  116. return self.sha256().hex()
  117. }
  118. public func sha256() -> [UInt8] {
  119. return SHA256.hash([UInt8](self.utf8))
  120. }
  121. }