hwchen / keyring-rs

Cross-platform library and utility to manage passwords
Apache License 2.0
450 stars 49 forks source link

android: support system keystore #127

Open phlip9 opened 1 year ago

phlip9 commented 1 year ago

Overview

Currently keyring-rs supports iOS but not Android. If we can extend support to Android, then keyring-rs handles all major platforms, desktop and mobile, which would be pretty cool : )

Issues

Sadly Android doesn't appear to expose any access to the platform keystore via the ndk ffi bindings. Any solution would have to go through the Java interface. I'm not super familiar with how this works, but the approach taken in app_dirs2 would probably work: https://github.com/app-dirs-rs/app_dirs2/blob/main/src/imp/platform/android.rs.

Options

(1) Platform KeyStore/TEE/enclave

Safest, but annoying implementation.

After a cursory scan of the Android docs, it seems the main interface to the platform TEE is something called KeyStore. You can configure an instance that stores key material in the platform enclave. Secrets in the enclave are not exportable, so you need an extra layer of indirection to get a keyring entry in memory.

My guess is that they expect most users to use the EncryptedFile API, which stores a single "master key" in the platform KeyStore and then stores master-key-encrypted per-file (?) keys in the app's SharedPreferences. These sub-keys are then used to actually encrypt/decrypt a file on-disk.

The EncryptedFile API docs look like they have some sharp edges though:

Class used to create and read encrypted files. WARNING: The encrypted file should not be backed up with Auto Backup. When restoring the file it is likely the key used to encrypt it will no longer be present. You should exclude all EncryptedFiles from backup using backup rules. Be aware that if you are not explicitly calling setKeysetPrefName() there is also a silently-created default preferences file created at

   ApplicationProvider
        .getApplicationContext()
        .getFilesDir()
        .getParent() + "/shared_prefs/__androidx_security_crypto_encrypted_file_pref__"

This preferences file (or any others created with a custom specified location) also should be excluded from backups.

Challenges

(2) Just stick files in the application data directory

A simpler approach is to just dump keyring-rs entries into the application's data directory. I believe each application's data directory files are sandboxed and inaccessible to any other applications (unless the device is rooted of course).

The internal storage filesystem (where apps store their data) is also encrypted and only accessible after the user unlocks the device.

Challenges

This approach is definitely easier--we can probably reuse the approach in app_dirs2 verbatim.

landhb commented 1 year ago

One thing to note is that the keyutils backend might work on Android, since it's running a Linux kernel. But I'm not sure if the seccomp profiles apps are subject to would allow the syscalls.

https://android-developers.googleblog.com/2017/07/seccomp-filter-in-android-o.html

landhb commented 1 year ago

Nevermind, looks like it's explicitly blocked on Android.

But then they also have this core utility. So I'm not sure. Probably worth a shot to see.

It might work since it seems the init process uses keyctl: https://github.com/aosp-mirror/platform_system_core/blob/1f7c08e2412c8316f4978259eaace0d3d778306a/init/init.cpp#L958. So depends if the seccomp profile is applied afterwards and is different for child processes, but that comment makes it seem like it's intended for child processes to have access to the session keyring. Since the File Based Encryption (FBE) keys, mentioned in part 2 above are stored there. https://github.com/aosp-mirror/platform_system_core/blob/1f7c08e2412c8316f4978259eaace0d3d778306a/init/fscrypt_init_extensions.cpp#L49

brotskydotcom commented 1 year ago

I think I like the simplicity of just using the native app filesystem, which seems sufficiently protected in the same way that the typical gnome keyring is (by the user's login). But I don't really have time to work on this now, as it would require me to understand Android app development (which I've never tried). So if someone wants to take a shot at this, please do!

Zack-Xb commented 11 months ago

Have any of you tried this crate https://github.com/dodorare/android-tools-rs , I think in combination with app_dirs2 and then rusqlite for persistent storage or binding SharedPrefrence java interface, can be a sufficient solution.

Zack-Xb commented 11 months ago

https://github.com/dodorare/android-tools-rs/tree/main runs keytool from command line so this has to be changed.

Zack-Xb commented 5 months ago

This can be done if we add a java module named keystore and it would have to be bridged manually in android studio as a new module, in rust we'd use jni to invoke the methods in java. Will be open sourcing this implementation in our app later this year, I'll make sure to find the time and create a branch here with a solution and docs.

Rigidity commented 4 months ago

Hello, I'm wondering if there's any open source solution for using the Android keyring yet? I'm building an app which needs to store an encryption key in the system's native keyring, but it also needs to work on all of MacOS/Windows/Linux/iOS/Android.

Zack-Xb commented 3 months ago

@Rigidity Here you go this is the library I have developed and been using. Be cautious re using this in production cause have not tested this and its security implications rigorously enough. You can then use jni bindings from your rust project to call the functions in Java, hit me up if you need any help and if you see anything that can be improved of which there is a lot feel free to contribute.

https://github.com/AvailX/keystore_module

Zack-Xb commented 3 months ago

@Rigidity have any idea if this library support biometrics for iOS ?

clickonetwo commented 3 months ago

@Zack-Xb Are you asking whether the keychain rust crate supports biometrics for iOS? If so, the answer is yes - it uses the iOS native keychain and so supports biometrics.