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

android: support system keystore #127

Open
phlip9 opened this issue May 22, 2023 · 15 comments
Open

android: support system keystore #127

phlip9 opened this issue May 22, 2023 · 15 comments

Comments

@phlip9
Copy link
Contributor

phlip9 commented May 22, 2023

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.

@phlip9 phlip9 changed the title android: use android: support system keystore May 22, 2023
@landhb
Copy link
Contributor

landhb commented May 22, 2023

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
Copy link
Contributor

landhb commented May 23, 2023

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
Copy link
Collaborator

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
Copy link

Zack-Xb commented Jul 14, 2023

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
Copy link

Zack-Xb commented Jul 14, 2023

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

@Zack-Xb
Copy link

Zack-Xb commented Jan 21, 2024

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
Copy link

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
Copy link

Zack-Xb commented Mar 23, 2024

@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
Copy link

Zack-Xb commented Mar 23, 2024

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

@clickonetwo
Copy link

@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.

@tmpfs
Copy link
Contributor

tmpfs commented Dec 14, 2024

I would also like to see support for Android, another perhaps simpler option we could try is the EncryptedSharedPreferences support:

https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences

It's available from Android 6.0 (Marshmallow) - minSdkVersion 23.

What do you think?

@brotskydotcom
Copy link
Collaborator

At a glance, the EncryptedSharedPreferences look promising, but I am not an Android developer so really have no idea about pursing this. The one issue I saw looking at the API docs you cited is that it doesn't look like preferences can handle store arbitrary binary data, only Unicode strings. Now that keyring supports binary stores on other platforms, you would probably have to build some kind of encode/decode into the get_secret and set_secret methods.

@tmpfs
Copy link
Contributor

tmpfs commented Dec 22, 2024

Thanks for taking a look @brotskydotcom , I am not an Android developer either but do have some experience with the platform as I am developing an app that works across all 5 major platforms.

That's a good observation about the binary data, maybe we could use data: URLs for the encoding? We can use the MIME type to distinguish between string and binary types and base64 encode the binary data.

I would be willing to do the work (JNI bindings) to see this happen as it is important for my app to have a cohesive interface to the platform keyring. Would you be interested in a PR for this?

@Rigidity
Copy link

This would be great for Tauri apps :)

@brotskydotcom
Copy link
Collaborator

I would be willing to do the work (JNI bindings) to see this happen as it is important for my app to have a cohesive interface to the platform keyring. Would you be interested in a PR for this?

Very! I suggest you start with either the mock keystore or the macOS keystore and see if you can cut in the Android storage APIs instead of the mechanisms they are using.

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

No branches or pull requests

7 participants