PBKDF1.swift 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. //
  2. // PBKDF1.swift
  3. // CryptoSwift
  4. //
  5. // Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
  6. // This software is provided 'as-is', without any express or implied warranty.
  7. //
  8. // In no event will the authors be held liable for any damages arising from the use of this software.
  9. //
  10. // 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:
  11. //
  12. // - 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.
  13. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  14. // - This notice may not be removed or altered from any source or binary distribution.
  15. //
  16. public extension PKCS5 {
  17. /// A key derivation function.
  18. ///
  19. /// PBKDF1 is recommended only for compatibility with existing
  20. /// applications since the keys it produces may not be large enough for
  21. /// some applications.
  22. public struct PBKDF1 {
  23. public enum Error: Swift.Error {
  24. case invalidInput
  25. case derivedKeyTooLong
  26. }
  27. public enum Variant {
  28. case md5, sha1
  29. var size: Int {
  30. switch self {
  31. case .md5:
  32. return MD5.digestLength
  33. case .sha1:
  34. return SHA1.digestLength
  35. }
  36. }
  37. fileprivate func calculateHash(_ bytes: Array<UInt8>) -> Array<UInt8>? {
  38. switch self {
  39. case .sha1:
  40. return Digest.sha1(bytes)
  41. case .md5:
  42. return Digest.md5(bytes)
  43. }
  44. }
  45. }
  46. private let iterations: Int // c
  47. private let variant: Variant
  48. private let keyLength: Int
  49. private let t1: Array<UInt8>
  50. /// - parameters:
  51. /// - salt: salt, an eight-bytes
  52. /// - variant: hash variant
  53. /// - iterations: iteration count, a positive integer
  54. /// - keyLength: intended length of derived key
  55. public init(password: Array<UInt8>, salt: Array<UInt8>, variant: Variant = .sha1, iterations: Int = 4096 /* c */, keyLength: Int? = nil /* dkLen */ ) throws {
  56. precondition(iterations > 0)
  57. precondition(salt.count == 8)
  58. let keyLength = keyLength ?? variant.size
  59. if keyLength > variant.size {
  60. throw Error.derivedKeyTooLong
  61. }
  62. guard let t1 = variant.calculateHash(password + salt) else {
  63. throw Error.invalidInput
  64. }
  65. self.iterations = iterations
  66. self.variant = variant
  67. self.keyLength = keyLength
  68. self.t1 = t1
  69. }
  70. /// Apply the underlying hash function Hash for c iterations
  71. public func calculate() -> Array<UInt8> {
  72. var t = t1
  73. for _ in 2...iterations {
  74. t = variant.calculateHash(t)!
  75. }
  76. return Array(t[0..<self.keyLength])
  77. }
  78. }
  79. }