Multi-Factor Authentication (MFA)
Multi-Factor Authentication (MFA)
Implementing MFA significantly enhances security by requiring multiple verification methods.
// iOS - Multi-factor authentication system
class MFAManager {
enum MFAMethod {
case sms(phoneNumber: String)
case totp(secret: String)
case pushNotification(deviceToken: String)
case biometric
case email(address: String)
}
private let networkManager = SecureNetworkManager()
private let keychain = KeychainWrapper()
// Configure MFA for user
func setupMFA(
methods: [MFAMethod],
completion: @escaping (Result<MFAConfiguration, Error>) -> Void
) {
// Validate at least 2 methods
guard methods.count >= 2 else {
completion(.failure(MFAError.insufficientMethods))
return
}
// Setup each method
let group = DispatchGroup()
var configuredMethods: [ConfiguredMFAMethod] = []
var setupError: Error?
for method in methods {
group.enter()
setupMethod(method) { result in
switch result {
case .success(let configured):
configuredMethods.append(configured)
case .failure(let error):
setupError = error
}
group.leave()
}
}
group.notify(queue: .main) {
if let error = setupError {
completion(.failure(error))
} else {
let configuration = MFAConfiguration(
methods: configuredMethods,
requiredFactors: 2,
createdAt: Date()
)
// Store configuration securely
self.storeMFAConfiguration(configuration)
completion(.success(configuration))
}
}
}
// TOTP implementation
func generateTOTPCode(secret: String) -> String? {
guard let secretData = base32Decode(secret) else { return nil }
let counter = UInt64(Date().timeIntervalSince1970 / 30)
var counterBigEndian = counter.bigEndian
let counterData = Data(bytes: &counterBigEndian, count: 8)
// Generate HMAC
let key = SymmetricKey(data: secretData)
let hmac = HMAC<SHA256>.authenticationCode(for: counterData, using: key)
// Extract dynamic binary code
let hmacData = Data(hmac)
let offset = Int(hmacData[hmacData.count - 1] & 0x0f)
let code = hmacData.withUnsafeBytes { bytes in
let bytes = bytes.bindMemory(to: UInt8.self)
var truncatedCode = UInt32(bytes[offset] & 0x7f) << 24
truncatedCode |= UInt32(bytes[offset + 1]) << 16
truncatedCode |= UInt32(bytes[offset + 2]) << 8
truncatedCode |= UInt32(bytes[offset + 3])
return truncatedCode
}
// Generate 6-digit code
let otp = code % 1000000
return String(format: "%06d", otp)
}
// Verify MFA challenge
func verifyMFAChallenge(
method: ConfiguredMFAMethod,
response: String,
completion: @escaping (Result<Bool, Error>) -> Void
) {
switch method.type {
case .totp:
// Verify TOTP locally
if let secret = method.secret,
let expectedCode = generateTOTPCode(secret: secret),
response == expectedCode {
completion(.success(true))
} else {
completion(.success(false))
}
case .sms, .email:
// Verify with server
verifyCodeWithServer(
method: method,
code: response,
completion: completion
)
case .pushNotification:
// Check push notification response
verifyPushResponse(
method: method,
completion: completion
)
case .biometric:
// Biometric already verified
completion(.success(true))
}
}
}
struct MFAConfiguration: Codable {
let methods: [ConfiguredMFAMethod]
let requiredFactors: Int
let createdAt: Date
}
struct ConfiguredMFAMethod: Codable {
let id: String
let type: MFAMethodType
let displayName: String
let secret: String?
let isBackup: Bool
}