PBKDF1.swift 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  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. public extension PKCS5 {
  16. /// A key derivation function.
  17. ///
  18. /// PBKDF1 is recommended only for compatibility with existing
  19. /// applications since the keys it produces may not be large enough for
  20. /// some applications.
  21. struct PBKDF1 {
  22. public enum Error: Swift.Error {
  23. case invalidInput
  24. case derivedKeyTooLong
  25. }
  26. public enum Variant {
  27. case md5, sha1
  28. var size: Int {
  29. switch self {
  30. case .md5:
  31. return MD5.digestLength
  32. case .sha1:
  33. return SHA1.digestLength
  34. }
  35. }
  36. fileprivate func calculateHash(_ bytes: Array<UInt8>) -> Array<UInt8> {
  37. switch self {
  38. case .sha1:
  39. return Digest.sha1(bytes)
  40. case .md5:
  41. return Digest.md5(bytes)
  42. }
  43. }
  44. }
  45. private let iterations: Int // c
  46. private let variant: Variant
  47. private let keyLength: Int
  48. private let t1: Array<UInt8>
  49. /// - parameters:
  50. /// - salt: salt, an eight-bytes
  51. /// - variant: hash variant
  52. /// - iterations: iteration count, a positive integer
  53. /// - keyLength: intended length of derived key
  54. public init(password: Array<UInt8>, salt: Array<UInt8>, variant: Variant = .sha1, iterations: Int = 4096 /* c */, keyLength: Int? = nil /* dkLen */ ) throws {
  55. precondition(iterations > 0)
  56. precondition(salt.count == 8)
  57. let keyLength = keyLength ?? variant.size
  58. if keyLength > variant.size {
  59. throw Error.derivedKeyTooLong
  60. }
  61. let t1 = variant.calculateHash(password + salt)
  62. self.iterations = iterations
  63. self.variant = variant
  64. self.keyLength = keyLength
  65. self.t1 = t1
  66. }
  67. /// Apply the underlying hash function Hash for c iterations
  68. public func calculate() -> Array<UInt8> {
  69. var t = self.t1
  70. for _ in 2...self.iterations {
  71. t = self.variant.calculateHash(t)
  72. }
  73. return Array(t[0..<self.keyLength])
  74. }
  75. }
  76. }