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
}