-
Notifications
You must be signed in to change notification settings - Fork 303
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
feat: implement android keystore #150
base: master
Are you sure you want to change the base?
Conversation
These tests are replaced by instrumental tests
08eafd3
to
fce26dc
Compare
Nice work! I have a question around the bottlerocket addition though. I started work on this a month back but didn't get time to finish adding code to migrate legacy shared prefs keys. It also includes some test stuff there using JKECKS store so we can run unittests separate from the device. I'd be in favor of not adding that bottlerocket code if we can directly use the Android API, just thought I'd share what I'd done in this direction, I think it's a big improvement either way for FreeOTP to move secrets out of SharedPrefs |
I would very much like to merge a patch like this. However, now that we are targeting minimum API version 23+, we can implement this with much stronger guarantees than what is implemented in this patch. We can actually import the key into the keystore and then do hmac against a reference to the key. This way, once the token is imported FreeOTP never sees the key again. @max-wittig Would you be willing to implement something like this with better guarantees? |
@npmccallum I would really like to implement this, but I'm not quite sure how. Do you have any additonal pointers on how to approach this? Also does the user need to authentificate, if we use the KeyProtection APIs? Because that would be overkill and deter users from using this app imo. |
The native KeyStore API doesn't seem to be that hard. You basically just want to import the key into the keystore and then do HMAC against the reference to the key (rather than the key directly). I think we should make authentication an two-fold option. If the token provider provides a flag (an extension to the OTP URI) that indicates authentication is required, we should respect that. Otherwise, we should offer the user the choice. |
Where can I find a reference to this extension of the OTP URI ? I think, we shouldn't invent a new flag, if it doesn't exist |
But don't we need the URI string directly to read the values and generate a HTOP code? |
We already support the To make things work, the app receives the URI during provisioning. Then it takes the secret and stores it in the key store under the appropriate HMAC algorithm. Once this is done, the secret never comes out of the key store again. When you want to generate the OTP code, you simply use the reference to the secret and ask the key store to perform HMAC on your behalf. You provide as input either the counter or the time stamp. Then you perform OTP truncation on the result. The really positive step here is that FreeOTP can use the secret but can never again see the secret. |
Notice: This PR should not be merged, before #141
is merged, because #141 also implements the new permission system, which is needed because the min API level is bumped to 23
This PR uses the Android Keystore, which replaces the SharedPreference save method. This improves the security of the tokens, without causing an inconvenience for the user.
Tested:
Added libraries
./gradlew connectedAndroidTest