46 lines
1.4 KiB
Swift
46 lines
1.4 KiB
Swift
//
|
|
// OTPGenerator.swift
|
|
// OTPKit
|
|
//
|
|
// Created by Shadowfacts on 8/21/21.
|
|
//
|
|
|
|
import Foundation
|
|
import CryptoKit
|
|
|
|
public struct OTPGenerator {
|
|
|
|
private init() {}
|
|
|
|
public static func generate(key: OTPKey, counter: Int64) -> String {
|
|
let data = withUnsafeBytes(of: counter.bigEndian) {
|
|
Data($0)
|
|
}
|
|
|
|
let mac = HMAC<Insecure.SHA1>.authenticationCode(for: data, using: SymmetricKey(data: key.secret))
|
|
|
|
let uint32Code = mac.withUnsafeBytes { (ptr) -> UInt32 in
|
|
let offset = Int(ptr.last! & 0x0F)
|
|
let offsetPtr = ptr.baseAddress!.advanced(by: offset)
|
|
return offsetPtr.assumingMemoryBound(to: UInt32.self).pointee.bigEndian & 0x7FFFFFFF
|
|
}
|
|
|
|
let truncated = uint32Code % UInt32(pow(10, Double(key.digits)))
|
|
|
|
var s = truncated.description
|
|
if s.count < key.digits {
|
|
s = String(repeating: "0", count: key.digits - s.count) + s
|
|
}
|
|
return s
|
|
}
|
|
|
|
public static func generate(key: TOTPKey) -> TOTPCode {
|
|
let now = Date()
|
|
let counter = Int64(now.timeIntervalSince1970 / Double(key.period))
|
|
let start = Date(timeIntervalSince1970: Double(counter * Int64(key.period)))
|
|
let code = generate(key: key, counter: counter)
|
|
return TOTPCode(code: code, validFrom: start, validInterval: key.period)
|
|
}
|
|
|
|
}
|