Scrypt.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. //
  2. // CryptoSwift
  3. //
  4. // Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
  5. // This software is provided 'as-is', without any express or implied warranty.
  6. //
  7. // In no event will the authors be held liable for any damages arising from the use of this software.
  8. //
  9. // Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
  10. //
  11. // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
  12. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  13. // - This notice may not be removed or altered from any source or binary distribution.
  14. //
  15. //
  16. // https://tools.ietf.org/html/rfc7914
  17. //
  18. /// Implementation of the scrypt key derivation function.
  19. public final class Scrypt {
  20. enum Error: Swift.Error {
  21. case nIsTooLarge
  22. case rIsTooLarge
  23. case nMustBeAPowerOf2GreaterThan1
  24. case invalidInput
  25. }
  26. /// Configuration parameters.
  27. private let salt: SecureBytes
  28. private let password: SecureBytes
  29. fileprivate let blocksize: Int // 128 * r
  30. fileprivate let salsaBlock = UnsafeMutableRawPointer.allocate(byteCount: 64, alignment: 64)
  31. private let dkLen: Int
  32. private let N: Int
  33. private let r: Int
  34. private let p: Int
  35. /// - parameters:
  36. /// - password: password
  37. /// - salt: salt
  38. /// - dkLen: output length
  39. /// - N: determines extra memory used
  40. /// - r: determines a block size
  41. /// - p: determines parallelicity degree
  42. public init(password: Array<UInt8>, salt: Array<UInt8>, dkLen: Int, N: Int, r: Int, p: Int) throws {
  43. precondition(dkLen > 0)
  44. precondition(N > 0)
  45. precondition(r > 0)
  46. precondition(p > 0)
  47. guard !(N < 2 || (N & (N - 1)) != 0) else { throw Error.nMustBeAPowerOf2GreaterThan1 }
  48. guard N <= .max / 128 / r else { throw Error.nIsTooLarge }
  49. guard r <= .max / 128 / p else { throw Error.rIsTooLarge }
  50. guard !salt.isEmpty else {
  51. throw Error.invalidInput
  52. }
  53. blocksize = 128 * r
  54. self.N = N
  55. self.r = r
  56. self.p = p
  57. self.password = SecureBytes.init(bytes: password)
  58. self.salt = SecureBytes.init(bytes: salt)
  59. self.dkLen = dkLen
  60. }
  61. /// Runs the key derivation function with a specific password.
  62. public func calculate() throws -> [UInt8] {
  63. // Allocate memory (as bytes for now) for further use in mixing steps
  64. let B = UnsafeMutableRawPointer.allocate(byteCount: 128 * r * p, alignment: 64)
  65. let XY = UnsafeMutableRawPointer.allocate(byteCount: 256 * r + 64, alignment: 64)
  66. let V = UnsafeMutableRawPointer.allocate(byteCount: 128 * r * N, alignment: 64)
  67. // Deallocate memory when done
  68. defer {
  69. B.deallocate()
  70. XY.deallocate()
  71. V.deallocate()
  72. }
  73. /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
  74. // Expand the initial key
  75. let barray = try PKCS5.PBKDF2(password: Array(password), salt: Array(salt), iterations: 1, keyLength: p * 128 * r, variant: .sha256).calculate()
  76. barray.withUnsafeBytes { p in
  77. B.copyMemory(from: p.baseAddress!, byteCount: barray.count)
  78. }
  79. /* 2: for i = 0 to p - 1 do */
  80. // do the mixing
  81. for i in 0 ..< p {
  82. /* 3: B_i <-- MF(B_i, N) */
  83. smix(B + i * 128 * r, V.assumingMemoryBound(to: UInt32.self), XY.assumingMemoryBound(to: UInt32.self))
  84. }
  85. /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
  86. let pointer = B.assumingMemoryBound(to: UInt8.self)
  87. let bufferPointer = UnsafeBufferPointer(start: pointer, count: p * 128 * r)
  88. let block = [UInt8](bufferPointer)
  89. return try PKCS5.PBKDF2(password: Array(password), salt: block, iterations: 1, keyLength: dkLen, variant: .sha256).calculate()
  90. }
  91. }
  92. private extension Scrypt {
  93. /// Computes `B = SMix_r(B, N)`.
  94. ///
  95. /// The input `block` must be `128*r` bytes in length; the temporary storage `v` must be `128*r*n` bytes in length;
  96. /// the temporary storage `xy` must be `256*r + 64` bytes in length. The arrays `block`, `v`, and `xy` must be
  97. /// aligned to a multiple of 64 bytes.
  98. @inline(__always) func smix(_ block: UnsafeMutableRawPointer, _ v: UnsafeMutablePointer<UInt32>, _ xy: UnsafeMutablePointer<UInt32>) {
  99. let X = xy
  100. let Y = xy + 32 * r
  101. let Z = xy + 64 * r
  102. /* 1: X <-- B */
  103. let typedBlock = block.assumingMemoryBound(to: UInt32.self)
  104. X.assign(from: typedBlock, count: 32 * r)
  105. /* 2: for i = 0 to N - 1 do */
  106. for i in stride(from: 0, to: N, by: 2) {
  107. /* 3: V_i <-- X */
  108. UnsafeMutableRawPointer(v + i * (32 * r)).copyMemory(from: X, byteCount: 128 * r)
  109. /* 4: X <-- H(X) */
  110. blockMixSalsa8(X, Y, Z)
  111. /* 3: V_i <-- X */
  112. UnsafeMutableRawPointer(v + (i + 1) * (32 * r)).copyMemory(from: Y, byteCount: 128 * r)
  113. /* 4: X <-- H(X) */
  114. blockMixSalsa8(Y, X, Z)
  115. }
  116. /* 6: for i = 0 to N - 1 do */
  117. for _ in stride(from: 0, to: N, by: 2) {
  118. /*
  119. 7: j <-- Integerify (X) mod N
  120. where Integerify (B[0] ... B[2 * r - 1]) is defined
  121. as the result of interpreting B[2 * r - 1] as a little-endian integer.
  122. */
  123. var j = Int(integerify(X) & UInt64(N - 1))
  124. /* 8: X <-- H(X \xor V_j) */
  125. blockXor(X, v + j * 32 * r, 128 * r)
  126. blockMixSalsa8(X, Y, Z)
  127. /* 7: j <-- Integerify(X) mod N */
  128. j = Int(integerify(Y) & UInt64(N - 1))
  129. /* 8: X <-- H(X \xor V_j) */
  130. blockXor(Y, v + j * 32 * r, 128 * r)
  131. blockMixSalsa8(Y, X, Z)
  132. }
  133. /* 10: B' <-- X */
  134. for k in 0 ..< 32 * r {
  135. UnsafeMutableRawPointer(block + 4 * k).storeBytes(of: X[k], as: UInt32.self)
  136. }
  137. }
  138. /// Returns the result of parsing `B_{2r-1}` as a little-endian integer.
  139. @inline(__always) func integerify(_ block: UnsafeRawPointer) -> UInt64 {
  140. let bi = block + (2 * r - 1) * 64
  141. return bi.load(as: UInt64.self).littleEndian
  142. }
  143. /// Compute `bout = BlockMix_{salsa20/8, r}(bin)`.
  144. ///
  145. /// The input `bin` must be `128*r` bytes in length; the output `bout` must also be the same size. The temporary
  146. /// space `x` must be 64 bytes.
  147. @inline(__always) func blockMixSalsa8(_ bin: UnsafePointer<UInt32>, _ bout: UnsafeMutablePointer<UInt32>, _ x: UnsafeMutablePointer<UInt32>) {
  148. /* 1: X <-- B_{2r - 1} */
  149. UnsafeMutableRawPointer(x).copyMemory(from: bin + (2 * r - 1) * 16, byteCount: 64)
  150. /* 2: for i = 0 to 2r - 1 do */
  151. for i in stride(from: 0, to: 2 * r, by: 2) {
  152. /* 3: X <-- H(X \xor B_i) */
  153. blockXor(x, bin + i * 16, 64)
  154. salsa20_8_typed(x)
  155. /* 4: Y_i <-- X */
  156. /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
  157. UnsafeMutableRawPointer(bout + i * 8).copyMemory(from: x, byteCount: 64)
  158. /* 3: X <-- H(X \xor B_i) */
  159. blockXor(x, bin + i * 16 + 16, 64)
  160. salsa20_8_typed(x)
  161. /* 4: Y_i <-- X */
  162. /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
  163. UnsafeMutableRawPointer(bout + i * 8 + r * 16).copyMemory(from: x, byteCount: 64)
  164. }
  165. }
  166. @inline(__always) func salsa20_8_typed(_ block: UnsafeMutablePointer<UInt32>) {
  167. salsaBlock.copyMemory(from: UnsafeRawPointer(block), byteCount: 64)
  168. let salsaBlockTyped = salsaBlock.assumingMemoryBound(to: UInt32.self)
  169. for _ in stride(from: 0, to: 8, by: 2) {
  170. salsaBlockTyped[4] ^= rotateLeft(salsaBlockTyped[0] &+ salsaBlockTyped[12], by: 7)
  171. salsaBlockTyped[8] ^= rotateLeft(salsaBlockTyped[4] &+ salsaBlockTyped[0], by: 9)
  172. salsaBlockTyped[12] ^= rotateLeft(salsaBlockTyped[8] &+ salsaBlockTyped[4], by: 13)
  173. salsaBlockTyped[0] ^= rotateLeft(salsaBlockTyped[12] &+ salsaBlockTyped[8], by: 18)
  174. salsaBlockTyped[9] ^= rotateLeft(salsaBlockTyped[5] &+ salsaBlockTyped[1], by: 7)
  175. salsaBlockTyped[13] ^= rotateLeft(salsaBlockTyped[9] &+ salsaBlockTyped[5], by: 9)
  176. salsaBlockTyped[1] ^= rotateLeft(salsaBlockTyped[13] &+ salsaBlockTyped[9], by: 13)
  177. salsaBlockTyped[5] ^= rotateLeft(salsaBlockTyped[1] &+ salsaBlockTyped[13], by: 18)
  178. salsaBlockTyped[14] ^= rotateLeft(salsaBlockTyped[10] &+ salsaBlockTyped[6], by: 7)
  179. salsaBlockTyped[2] ^= rotateLeft(salsaBlockTyped[14] &+ salsaBlockTyped[10], by: 9)
  180. salsaBlockTyped[6] ^= rotateLeft(salsaBlockTyped[2] &+ salsaBlockTyped[14], by: 13)
  181. salsaBlockTyped[10] ^= rotateLeft(salsaBlockTyped[6] &+ salsaBlockTyped[2], by: 18)
  182. salsaBlockTyped[3] ^= rotateLeft(salsaBlockTyped[15] &+ salsaBlockTyped[11], by: 7)
  183. salsaBlockTyped[7] ^= rotateLeft(salsaBlockTyped[3] &+ salsaBlockTyped[15], by: 9)
  184. salsaBlockTyped[11] ^= rotateLeft(salsaBlockTyped[7] &+ salsaBlockTyped[3], by: 13)
  185. salsaBlockTyped[15] ^= rotateLeft(salsaBlockTyped[11] &+ salsaBlockTyped[7], by: 18)
  186. salsaBlockTyped[1] ^= rotateLeft(salsaBlockTyped[0] &+ salsaBlockTyped[3], by: 7)
  187. salsaBlockTyped[2] ^= rotateLeft(salsaBlockTyped[1] &+ salsaBlockTyped[0], by: 9)
  188. salsaBlockTyped[3] ^= rotateLeft(salsaBlockTyped[2] &+ salsaBlockTyped[1], by: 13)
  189. salsaBlockTyped[0] ^= rotateLeft(salsaBlockTyped[3] &+ salsaBlockTyped[2], by: 18)
  190. salsaBlockTyped[6] ^= rotateLeft(salsaBlockTyped[5] &+ salsaBlockTyped[4], by: 7)
  191. salsaBlockTyped[7] ^= rotateLeft(salsaBlockTyped[6] &+ salsaBlockTyped[5], by: 9)
  192. salsaBlockTyped[4] ^= rotateLeft(salsaBlockTyped[7] &+ salsaBlockTyped[6], by: 13)
  193. salsaBlockTyped[5] ^= rotateLeft(salsaBlockTyped[4] &+ salsaBlockTyped[7], by: 18)
  194. salsaBlockTyped[11] ^= rotateLeft(salsaBlockTyped[10] &+ salsaBlockTyped[9], by: 7)
  195. salsaBlockTyped[8] ^= rotateLeft(salsaBlockTyped[11] &+ salsaBlockTyped[10], by: 9)
  196. salsaBlockTyped[9] ^= rotateLeft(salsaBlockTyped[8] &+ salsaBlockTyped[11], by: 13)
  197. salsaBlockTyped[10] ^= rotateLeft(salsaBlockTyped[9] &+ salsaBlockTyped[8], by: 18)
  198. salsaBlockTyped[12] ^= rotateLeft(salsaBlockTyped[15] &+ salsaBlockTyped[14], by: 7)
  199. salsaBlockTyped[13] ^= rotateLeft(salsaBlockTyped[12] &+ salsaBlockTyped[15], by: 9)
  200. salsaBlockTyped[14] ^= rotateLeft(salsaBlockTyped[13] &+ salsaBlockTyped[12], by: 13)
  201. salsaBlockTyped[15] ^= rotateLeft(salsaBlockTyped[14] &+ salsaBlockTyped[13], by: 18)
  202. }
  203. for i in 0 ..< 16 {
  204. block[i] = block[i] &+ salsaBlockTyped[i]
  205. }
  206. }
  207. @inline(__always) func blockXor(_ dest: UnsafeMutableRawPointer, _ src: UnsafeRawPointer, _ len: Int) {
  208. let D = dest.assumingMemoryBound(to: UInt64.self)
  209. let S = src.assumingMemoryBound(to: UInt64.self)
  210. let L = len / MemoryLayout<UInt64>.size
  211. for i in 0 ..< L {
  212. D[i] ^= S[i]
  213. }
  214. }
  215. }