Blog | G5 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:

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

4. What NOT To Do

Exit mobile version