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

Improve lock screen implementation with extra security measures #6523

Merged
merged 2 commits into from
Jul 27, 2022

Conversation

jmartinesp
Copy link
Member

Type of change

  • Feature
  • Bugfix
  • Technical
  • Other :

Content

See #6522 .

Motivation and context

We want to add additional security measures to the biometric authentication of the lock screen feature:

  1. An extra check to make sure the Cipher used is unlocked after authentication.
  2. Enabling a setting to only be able to use this Cipher while the device is unlocked.

Tests

  • With your app in develop or any other branch, go to Settings -> Security -> Protect access, and create a PIN code and enable biometric authentication. This can be done on the emulator too, but you need to make sure you're on API >= 30).
  • Build and launch this branch, make sure you can still use biometric authentication.

Tested devices

  • Physical
  • Emulator
  • OS version(s): 12.

Checklist

@jmartinesp jmartinesp added Security T-Enhancement New features, changes in functionality, performance boosts, user-facing improvements A-Pin code labels Jul 12, 2022
@jmartinesp jmartinesp self-assigned this Jul 12, 2022
@jmartinesp jmartinesp force-pushed the fix/jorgem/improve-security-of-lock-screen branch 2 times, most recently from 1695a69 to b18048f Compare July 15, 2022 10:11
@jmartinesp jmartinesp requested review from a team and ericdecanini and removed request for a team July 15, 2022 10:59
@jmartinesp jmartinesp marked this pull request as ready for review July 15, 2022 10:59
@jmartinesp jmartinesp requested review from a team and yostyle and removed request for ericdecanini and a team July 15, 2022 10:59
@artkoenig
Copy link
Contributor

I have some remarks about this.

  1. if (cipher != null && !isCipherValid(cipher)) should be IMO if (cipher == null || !isCipherValid(cipher))
  2. isCipherValid should IMO check, if it can decrypt the encrypted data

@jmartinesp
Copy link
Member Author

I have some remarks about this.

  1. if (cipher != null && !isCipherValid(cipher)) should be IMO if (cipher == null || !isCipherValid(cipher))
  2. isCipherValid should IMO check, if it can decrypt the encrypted data

About these:

  1. I wrote it that way so the authentication can also be successful if no CryptoObject is used, although it is by default now. We could enforce using a CryptoObject as you suggest here.
  2. That function actually checks if the Cipher inside the CryptoObject is unlocked by the biometric authentication, in this case, by using it to encode some value. If we tried to bypass it, the Cipher would throw an exception when it's used. Isn't this enough to avoid the issues around the current implementation?

If we wanted to both encode and decode using the Cipher inside the CryptoObject we'd need to:

  1. Create a new credential when the biometric authentication is enabled since its Cipher with ENCRYPT_MODE would need to be unlocked by a successful authentication.
  2. Store it.
  3. Decrypt that credential using another Cipher with DECRYPT_MODE and verify it matches the original.

The problem here would be the migration for users who are already using biometric authentication: to create this encrypted credential we first need to have the user unlock a Cipher with encrypt mode enabled. This means either silently trying to do this migration by trying to create the credential the first time biometric unlock is used and not checking the Cipher if there is no credential, or force every user already using biometric unlock to unlock twice if the credential is not present (one to create them, another one to verify those credentials). Also, in the first case the Cipher validation could be bypassed by just removing that credential from its storage.

@artkoenig
Copy link
Contributor

I think it should be enough to enforce a non-null CryptoObject (to prevent the bypassing with a Frida script) and leave the isCipherValid method as it is.

@jmartinesp jmartinesp force-pushed the fix/jorgem/improve-security-of-lock-screen branch 2 times, most recently from 65aebdc to dc03e46 Compare July 18, 2022 11:22
@jmartinesp
Copy link
Member Author

jmartinesp commented Jul 18, 2022

I've been having issues all morning with the same emulator on API 31 I've been using so far where there is an extremely weird crash:

  1. We need to pass a CryptoObject when we call BiometricHelper.authenticateIntenal.
  2. For this CryptoObject we need an initialized Cipher instance.
  3. When the Cipher is initialized it throws an UserNotAuthenticatedException, which is unexpected and uncaught.
  4. To authenticate the user we need to call BiometricHelper.authenticate. We're back on point 1.

This is actually working fine on another API 30 emulator and 2 real devices with APIs 30 and 31, and I still haven't found what could be causing this weird behaviour, not even creating a new API 31 emulator fixed it. I did upgrade my emulator version from the SDK not long ago, so it might be a newly introduced bug in emulators in that API.

@artkoenig
Copy link
Contributor

Just one more remark: PKCS1Padding used here has some security issues. It's better to use OAEPPadding here.

@jmartinesp
Copy link
Member Author

jmartinesp commented Jul 22, 2022

Just one more remark: PKCS1Padding used here has some security issues. It's better to use OAEPPadding here.

RSA with PKCS1Padding is used for Android 5 and 5.1. We can try to change the padding used to a better one, but SecretStoringUtils is used through the app in quite a few places, and if any of the data encrypted on those places is stored to disk and reused between app sessions we'd have to migrate those too along with the keys, so this work would probably need its own issue and planning first.

Either that, or split the cryptography in 2 separate components, one for the rest of the app and another one specially for this. Also, we were already considering bumping minSdk to 23 (see #6067), and in that case we could just drop support for this RSA encryption after a migration to AES if I'm not mistaken.

@artkoenig
Copy link
Contributor

Switching to minSdk 23 sounds good to me.

Copy link
Contributor

@yostyle yostyle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jmartinesp jmartinesp force-pushed the fix/jorgem/improve-security-of-lock-screen branch 2 times, most recently from 665bcd0 to e122f12 Compare July 26, 2022 15:20
@jmartinesp jmartinesp force-pushed the fix/jorgem/improve-security-of-lock-screen branch from e122f12 to 49edfa5 Compare July 27, 2022 08:30
@sonarqubecloud
Copy link

SonarCloud Quality Gate failed.    Quality Gate failed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

75.0% 75.0% Coverage
0.0% 0.0% Duplication

@jmartinesp jmartinesp merged commit 58ea816 into develop Jul 27, 2022
@jmartinesp jmartinesp deleted the fix/jorgem/improve-security-of-lock-screen branch July 27, 2022 12:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Pin code Security T-Enhancement New features, changes in functionality, performance boosts, user-facing improvements
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants