Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Secure storage implementations #186

Open
HLCaptain opened this issue Feb 29, 2024 · 8 comments
Open

Secure storage implementations #186

HLCaptain opened this issue Feb 29, 2024 · 8 comments

Comments

@HLCaptain
Copy link

As iOS platform supports Keychain experimentally, other platforms have similar secure implementations of a simple key-value storage directly, like Android's Keystore or Credential Manager. Or encrypt your data with a master key, like in EncryptedSharedPreferences, also on Android.

I suggest that the library should provide these secure methods of data persistence. I also vouch for an implementation which relies on master keys, as we may reuse code and only need to encrypt the stored key-value pairs and not rely on an entirely different system.

@russhwolf
Copy link
Owner

You can already use EncryptedSharedPreferences with the existing SharedPreferencesSettings.

@HLCaptain
Copy link
Author

That is true, but I think there should be more default(er) implementations of secure storage methods, which relies on Android Keystore or other platform specific keystore methods. On JVM, I had to find a way to acquire and save the master key, which is not intuitive to do. On web, this secure storage is even harder to implement. I would like security to be an option in common code, with platform specific secure implementation of settings.

@russhwolf
Copy link
Owner

Regarding JVM and JS, I'm open to adding something but not clear on what the best backing API is. If you have any demo code of what worked for you, I'd be interested to see it.

For Android, a couple questions. Is there anything you'd like to do with the Keystore that you can't do via EncryptedSharedPreferences? And do you have an example of what you'd like to be able to do with the Credential Manager?

@HLCaptain
Copy link
Author

Regarding Android platform, yes, I think using EncryptedSharedPreferences with Android KeyStore is enough, thanks for pointing that out.

I have an experimental demo working on the JVM side via Credential Secure Storage. It relies on MacOS, Windows and Linux native KeyStore libraries. I still have some bugs to squish, but it works fine on Ubuntu 23 and Windows 11. You can check out platform implementations from here for Common, JVM, Android. I still have to figure out Web. There may be better alternatives to Microsoft's Credential Secure Storage, like CoreCrypto.

@HLCaptain
Copy link
Author

As I stabilized my EncryptedPreferences for JVM, I may make a proper pull request to include it as a solution for making settings encrypted in some sorts.

Currently:

  • EncryptedPreferences acts like java.util.prefs.Preferences, but with encrypted keys and values.
  • Both keys and values have an IV, but keys' IV is derived from the key (to keep keys' fingerprint the same for collisions) and value's IV is random.
  • All actions are delegated to an injected Preferences instance with encrypted keys and values.

I could make the encryption happen in the Credential Secure Storage instead of java Preferences, just like Apple's KeyStore implementation, but I think java Preferences is secure enough for now.

@darronschall
Copy link

Regarding #211 getting merged into this issue -

One of things I find helpful is differentiating Settings vs. SecureSettings in my apps. Having these two containers make is less likely that I accidentally inject the wrong container.

I typically do this with two marker interfaces:

/**
 * Marker interface to differentiate [com.russhwolf.settings.Settings] backed
 * by the insecure NSUserDefaults / SharedPreferences vs. the secure
 * Keychain / EncryptedSharedPreferences.
 */
interface SecureSettingsContainer : Settings

interface SettingsContainer : Settings

And then create project-specific settings, something like:

class SecureSettings(
    secureSettingsContainer: SecureSettingsContainer,
) {
    var accessToken: String? by secureSettingsContainer.nullableString()
}

class Settings(
    private val settingsContainer: SettingsContainer,
) {
    var hasUserOnboarded: Boolean by settingsContainer.boolean(defaultValue = false)
}

This distinction makes it harder on the developer to accidentally make a mistake.

In my DI framework object graph, then, I'll do something like:

single {
    Settings(
        settingsContainer = /* create settings container for platform, backed by NSUserDefaults / SharedPreferences */,
    )
}
single {
    SecureSettings(
        secureSettingsContainer = /* create secure settings container for platform, backed by KeychainSettings / EncryptedSharedPreferences */,
    )
}

My code is generic enough that I wrapped it up in a little library that I use whenever I use muiltiplatform-settings. Happy to submit a PR to add it officially if it's something others would find useful.

@russhwolf
Copy link
Owner

russhwolf commented Nov 26, 2024

As I mentioned in #211, I don't really see the value of a separate secure interface. I see how it would save you from accidentally putting the wrong com.russhwolf.settings.Settings in your project-specific Settings and SecureSettings classes, but if you're only ever doing that once then it doesn't seem like a significant impact.

Furthermore, I'd like to keep this issue focused on implementations, so if you want to discuss the idea of a separate secure interface further, please open another ticket.

@russhwolf
Copy link
Owner

@HLCaptain The link to your encrypted preferences implementation no longer appears to work. Does it implement java.util.prefs.Preferences, or just provide an equivalent API? The former would require no explicit support from Multiplatform Settings, assuming you published your implementation as a standalone dependency.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants