Get a Pentest and security assessment of your IT network.

Cyber Security

Securely Storing Passwords in Desktop Apps

TL;DR

Storing passwords directly in a desktop application is risky. Use your operating system’s secure storage (Keychain on macOS, Credential Manager on Windows) to protect them. Avoid simple encryption and never store passwords in plain text.

1. Why Not Just Encrypt It?

Many developers think they can solve this by encrypting the password with a key stored somewhere else. This is usually not secure enough. Here’s why:

  • Key Management: Where do you store the encryption key? If it’s in the application code, someone reverse-engineering your app can find it.
  • Algorithm Weaknesses: Encryption algorithms get broken over time. What seems secure today might not be tomorrow.
  • Side Channel Attacks: Attackers can sometimes extract keys by observing how your application uses memory and processing power.

Operating system-level storage is designed to resist these attacks.

2. Using the Operating System’s Secure Storage

Both macOS and Windows have built-in systems for securely storing credentials. These are much better options than trying to roll your own solution.

macOS: Keychain

  1. Accessing the Keychain: Use the Security framework in Swift or Objective-C.
  2. Storing a Password: The following example shows how to store a password associated with an account:
    import Security
    
    func savePassword(accountName: String, password: String) throws {
        let query = [kSecClass as String: kSecClassGenericPassword,
                     kSecAttrAccount as String: accountName,
                     kSecValueData as String: password.data(using: .utf8)!] as [String : Any]
    
        let status = SecItemAdd(query as CFDictionary, nil)
    
        if status != errSecSuccess {
            throw NSError(domain: "KeychainError", code: Int(status), userInfo: nil)
        }
    }
    
  3. Retrieving a Password:
    import Security
    
    func retrievePassword(accountName: String) throws -> String? {
        let query = [kSecClass as String: kSecClassGenericPassword,
                     kSecAttrAccount as String: accountName,
                     kSecReturnData as String: kCFBooleanTrue] as [String : Any]
    
        var result: AnyObject?
        let status = SecItemGet(query as CFDictionary, &result)
    
        if status == errSecSuccess {
            return String(data: result as! Data, encoding: .utf8) ?? nil
        } else {
            return nil // Password not found
        }
    }
    
  4. Important Considerations: Always use a unique account name for each service.

Windows: Credential Manager

  1. Accessing the Credential Manager: Use the Windows API via .NET (C# or VB.NET).
  2. Storing a Password: The following example shows how to store a password:
    using System.Runtime.InteropServices;
    
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
    static extern bool CredUICreateCredential(string targetName, string credentialType, IntPtr flags, IntPtr reserved)
    
    // Example (simplified - error handling omitted for brevity)
    CredUICreateCredential("MyApplicationService", "GENERIC_PASSWORD", IntPtr.Zero, IntPtr.Zero);
    
  3. Retrieving a Password: Use the CredEnumerateCredentials and CredRetrieveCredential functions to retrieve credentials.

    Note: The Windows Credential Manager API is more complex than macOS Keychain. Consider using a wrapper library for easier access.

3. Additional Security Measures

  • Two-Factor Authentication (2FA): Encourage users to enable 2FA wherever possible. This adds an extra layer of security even if the password is compromised.
  • Limited Access: Only store the passwords needed for your application’s core functionality. Don’t ask for unnecessary credentials.
  • Regular Updates: Keep your application and its dependencies up to date to patch any security vulnerabilities.
  • Code Obfuscation: While not a primary security measure, code obfuscation can make it harder for attackers to reverse-engineer your application.

4. What NOT To Do

  • Never store passwords in plain text. This is the most basic and critical rule.
  • Avoid custom encryption schemes. Operating system storage is almost always better.
  • Don’t hardcode keys or secrets into your application code.
Related posts
Cyber Security

Zip Codes & PII: Are They Personal Data?

Cyber Security

Zero-Day Vulnerabilities: User Defence Guide

Cyber Security

Zero Knowledge Voting with Trusted Server

Cyber Security

ZeroNet: 51% Attack Risks & Mitigation