25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LessPassModule.swift 4.6 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import Foundation
  2. enum HMACAlgorithm {
  3. case MD5, SHA1, SHA224, SHA256, SHA384, SHA512
  4. func toCCHmacAlgorithm() -> CCHmacAlgorithm {
  5. var result: Int = 0
  6. switch self {
  7. case .MD5:
  8. result = kCCHmacAlgMD5
  9. case .SHA1:
  10. result = kCCHmacAlgSHA1
  11. case .SHA224:
  12. result = kCCHmacAlgSHA224
  13. case .SHA256:
  14. result = kCCHmacAlgSHA256
  15. case .SHA384:
  16. result = kCCHmacAlgSHA384
  17. case .SHA512:
  18. result = kCCHmacAlgSHA512
  19. }
  20. return CCHmacAlgorithm(result)
  21. }
  22. func digestLength() -> Int {
  23. var result: CInt = 0
  24. switch self {
  25. case .MD5:
  26. result = CC_MD5_DIGEST_LENGTH
  27. case .SHA1:
  28. result = CC_SHA1_DIGEST_LENGTH
  29. case .SHA224:
  30. result = CC_SHA224_DIGEST_LENGTH
  31. case .SHA256:
  32. result = CC_SHA256_DIGEST_LENGTH
  33. case .SHA384:
  34. result = CC_SHA384_DIGEST_LENGTH
  35. case .SHA512:
  36. result = CC_SHA512_DIGEST_LENGTH
  37. }
  38. return Int(result)
  39. }
  40. }
  41. extension String {
  42. func hmac(algorithm: HMACAlgorithm, key: String) -> String {
  43. let cKey = key.cString(using: String.Encoding.utf8)
  44. let cData = self.cString(using: String.Encoding.utf8)
  45. var result = [CUnsignedChar](repeating: 0, count: Int(algorithm.digestLength()))
  46. CCHmac(algorithm.toCCHmacAlgorithm(), cKey!, Int(strlen(cKey!)), cData!, Int(strlen(cData!)), &result)
  47. let hmacData:NSData = NSData(bytes: result, length: (Int(algorithm.digestLength())))
  48. var bytes = [UInt8](repeating:0, count: hmacData.length)
  49. hmacData.getBytes(&bytes, length: hmacData.length)
  50. var hexString = ""
  51. for byte in bytes {
  52. hexString += String(format:"%02hhx", UInt8(byte))
  53. }
  54. return hexString
  55. }
  56. }
  57. extension Data {
  58. struct HexEncodingOptions: OptionSet {
  59. let rawValue: Int
  60. static let upperCase = HexEncodingOptions(rawValue: 1 << 0)
  61. }
  62. func hexEncodedString(options: HexEncodingOptions = []) -> String {
  63. let hexDigits = Array((options.contains(.upperCase) ? "0123456789ABCDEF" : "0123456789abcdef").utf16)
  64. var chars: [unichar] = []
  65. chars.reserveCapacity(2 * count)
  66. for byte in self {
  67. chars.append(hexDigits[Int(byte / 16)])
  68. chars.append(hexDigits[Int(byte % 16)])
  69. }
  70. return String(utf16CodeUnits: chars, count: chars.count)
  71. }
  72. }
  73. func pbkdf2(hash: CCPBKDFAlgorithm, password: String, salt: String, keyByteCount: Int, rounds: Int) -> String? {
  74. guard let passwordData = password.data(using: .utf8), let saltData = salt.data(using: .utf8) else { return nil }
  75. var derivedKeyData = Data(repeating: 0, count: keyByteCount)
  76. let derivedCount = derivedKeyData.count
  77. let derivationStatus: Int32 = derivedKeyData.withUnsafeMutableBytes { derivedKeyBytes in
  78. let keyBuffer: UnsafeMutablePointer<UInt8> =
  79. derivedKeyBytes.baseAddress!.assumingMemoryBound(to: UInt8.self)
  80. return saltData.withUnsafeBytes { saltBytes -> Int32 in
  81. let saltBuffer: UnsafePointer<UInt8> = saltBytes.baseAddress!.assumingMemoryBound(to: UInt8.self)
  82. return CCKeyDerivationPBKDF(
  83. CCPBKDFAlgorithm(kCCPBKDF2),
  84. password,
  85. passwordData.count,
  86. saltBuffer,
  87. saltData.count,
  88. hash,
  89. UInt32(rounds),
  90. keyBuffer,
  91. derivedCount)
  92. }
  93. }
  94. return derivationStatus == kCCSuccess ? derivedKeyData.hexEncodedString() : nil
  95. }
  96. @objc(LessPassModule)
  97. class LessPassModule: NSObject {
  98. @objc(createFingerprint:resolver:rejecter:)
  99. func createFingerprint(_ masterPassword: String,
  100. resolver resolve: RCTPromiseResolveBlock,
  101. rejecter reject:RCTPromiseRejectBlock) -> Void {
  102. resolve("".hmac(algorithm: HMACAlgorithm.SHA256, key: masterPassword))
  103. }
  104. @objc(calcEntropy:withLogin:withMasterPassword:withCounter:resolver:rejecter:)
  105. func calcEntropy(_ site: String,
  106. withLogin login: String,
  107. withMasterPassword masterPassword: String,
  108. withCounter counter: String,
  109. resolver resolve: RCTPromiseResolveBlock,
  110. rejecter reject:RCTPromiseRejectBlock) -> Void {
  111. let salt = site + login + counter
  112. let r = pbkdf2(hash: CCPBKDFAlgorithm(kCCPRFHmacAlgSHA256), password: masterPassword, salt: salt, keyByteCount: 32, rounds: 100000)
  113. resolve(r)
  114. }
  115. @objc
  116. static func requiresMainQueueSetup() -> Bool {
  117. return false
  118. }
  119. }