PBKDF2.swift 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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. // https://www.ietf.org/rfc/rfc2898.txt
  16. //
  17. #if canImport(Darwin)
  18. import Darwin
  19. #else
  20. import Glibc
  21. #endif
  22. public extension PKCS5 {
  23. /// A key derivation function.
  24. ///
  25. /// PBKDF2 - Password-Based Key Derivation Function 2. Key stretching technique.
  26. /// DK = PBKDF2(PRF, Password, Salt, c, dkLen)
  27. public struct PBKDF2 {
  28. public enum Error: Swift.Error {
  29. case invalidInput
  30. case derivedKeyTooLong
  31. }
  32. private let salt: Array<UInt8> // S
  33. fileprivate let iterations: Int // c
  34. private let numBlocks: Int // l
  35. private let dkLen: Int
  36. fileprivate let prf: HMAC
  37. /// - parameters:
  38. /// - salt: salt
  39. /// - variant: hash variant
  40. /// - iterations: iteration count, a positive integer
  41. /// - keyLength: intended length of derived key
  42. /// - variant: MAC variant. Defaults to SHA256
  43. public init(password: Array<UInt8>, salt: Array<UInt8>, iterations: Int = 4096 /* c */, keyLength: Int? = nil /* dkLen */, variant: HMAC.Variant = .sha256) throws {
  44. precondition(iterations > 0)
  45. let prf = HMAC(key: password, variant: variant)
  46. guard iterations > 0 && !salt.isEmpty else {
  47. throw Error.invalidInput
  48. }
  49. dkLen = keyLength ?? variant.digestLength
  50. let keyLengthFinal = Double(dkLen)
  51. let hLen = Double(prf.variant.digestLength)
  52. if keyLengthFinal > (pow(2, 32) - 1) * hLen {
  53. throw Error.derivedKeyTooLong
  54. }
  55. self.salt = salt
  56. self.iterations = iterations
  57. self.prf = prf
  58. numBlocks = Int(ceil(Double(keyLengthFinal) / hLen)) // l = ceil(keyLength / hLen)
  59. }
  60. public func calculate() throws -> Array<UInt8> {
  61. var ret = Array<UInt8>()
  62. ret.reserveCapacity(numBlocks * prf.variant.digestLength)
  63. for i in 1...numBlocks {
  64. // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
  65. if let value = try calculateBlock(self.salt, blockNum: i) {
  66. ret.append(contentsOf: value)
  67. }
  68. }
  69. return Array(ret.prefix(dkLen))
  70. }
  71. }
  72. }
  73. fileprivate extension PKCS5.PBKDF2 {
  74. func ARR(_ i: Int) -> Array<UInt8> {
  75. var inti = Array<UInt8>(repeating: 0, count: 4)
  76. inti[0] = UInt8((i >> 24) & 0xff)
  77. inti[1] = UInt8((i >> 16) & 0xff)
  78. inti[2] = UInt8((i >> 8) & 0xff)
  79. inti[3] = UInt8(i & 0xff)
  80. return inti
  81. }
  82. // F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
  83. // U_1 = PRF (P, S || INT (i))
  84. func calculateBlock(_ salt: Array<UInt8>, blockNum: Int) throws -> Array<UInt8>? {
  85. guard let u1 = try? prf.authenticate(salt + ARR(blockNum)) else { // blockNum.bytes() is slower
  86. return nil
  87. }
  88. var u = u1
  89. var ret = u
  90. if iterations > 1 {
  91. // U_2 = PRF (P, U_1) ,
  92. // U_c = PRF (P, U_{c-1}) .
  93. for _ in 2...iterations {
  94. u = try prf.authenticate(u)
  95. for x in 0..<ret.count {
  96. ret[x] = ret[x] ^ u[x]
  97. }
  98. }
  99. }
  100. return ret
  101. }
  102. }