keyring-rs
keyring-rs copied to clipboard
android: support system keystore
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
- I believe (?) the user needs to compile against a recent SDK (v28) and flip some XML config flags to use
androidx. - Making lots of JVM calls and handling exceptions looks painful.
(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.
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
~~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
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!
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.
https://github.com/dodorare/android-tools-rs/tree/main runs keytool from command line so this has to be changed.
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.
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.
@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
@Rigidity have any idea if this library support biometrics for iOS ?
@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.