PBKDF1.swift 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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. @usableFromInline
  29. var size: Int {
  30. switch self {
  31. case .md5:
  32. return MD5.digestLength
  33. case .sha1:
  34. return SHA1.digestLength
  35. }
  36. }
  37. @usableFromInline
  38. func calculateHash(_ bytes: Array<UInt8>) -> Array<UInt8> {
  39. switch self {
  40. case .sha1:
  41. return Digest.sha1(bytes)
  42. case .md5:
  43. return Digest.md5(bytes)
  44. }
  45. }
  46. }
  47. @usableFromInline
  48. let iterations: Int // c
  49. @usableFromInline
  50. let variant: Variant
  51. @usableFromInline
  52. let keyLength: Int
  53. @usableFromInline
  54. let t1: Array<UInt8>
  55. /// - parameters:
  56. /// - salt: salt, an eight-bytes
  57. /// - variant: hash variant
  58. /// - iterations: iteration count, a positive integer
  59. /// - keyLength: intended length of derived key
  60. public init(password: Array<UInt8>, salt: Array<UInt8>, variant: Variant = .sha1, iterations: Int = 4096 /* c */, keyLength: Int? = nil /* dkLen */ ) throws {
  61. precondition(iterations > 0)
  62. precondition(salt.count == 8)
  63. let keyLength = keyLength ?? variant.size
  64. if keyLength > variant.size {
  65. throw Error.derivedKeyTooLong
  66. }
  67. let t1 = variant.calculateHash(password + salt)
  68. self.iterations = iterations
  69. self.variant = variant
  70. self.keyLength = keyLength
  71. self.t1 = t1
  72. }
  73. /// Apply the underlying hash function Hash for c iterations
  74. @inlinable
  75. public func calculate() -> Array<UInt8> {
  76. var t = self.t1
  77. for _ in 2...self.iterations {
  78. t = self.variant.calculateHash(t)
  79. }
  80. return Array(t[0..<self.keyLength])
  81. }
  82. }
  83. }