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

Proposal for HWKeyCrypter and Biometric Authentication #1121

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

oliveraemmer
Copy link

@oliveraemmer oliveraemmer commented Apr 14, 2024

Currently the keys in the wallet can be encrypted using a spending pin. With this PR we propose a new encryption type which leverages the Android KeyStore and Biometric Authentication to encrypt the keys. It is not a replacement of the spending pin but an addition.

image

This change requires additional changes in bitcoinj. The files in wallet/libs/ are built from the proposal_keycrypterfactory_new_encryptiontype branch.

This PR is not meant to be merged in the current state. If the proposed changes are accepted, the mentioned additional changes in bitcoinj would need to be merged and published first.

Change log of 31c78f7:

  • update bitcoinj to from 0.16.2 to 0.17

Change log of 894a9bf:

  • Add new HWKeyCrypter
  • Add new CryptActivity which runs while the Biometric Prompt is executed
  • Implement and set KeyCrypterFactory on WalletProtobufSerializer
  • Add radio buttons in EncryptKeyDialogFragment to chose between spending pin and hardware encryption
  • Remove encryption if hardware encryption is used before creating a backup (After decryption, the backup password can still be set, so the backup is still encrypted)

With Android Studio 2022.3.1 Patch 2 this current settings should build without additional changes

Authors: Sebastian Nicol and Oliver Aemmer

@schildbach
Copy link
Collaborator

Thanks for investigating into biometrics. For now, I only quickly skimmed over your PR, but I've got the following conceptual questions:

  1. You say "It is not a replacement of the spending pin but an addition", but in the app (for the user, per wallet) it's an either/or – correct?
  2. How can keys stored in the secure module (I assume) be backed up and restored in case of hardware failure or loss? I PIN can be written down, or "simply" be remembered.
  3. Can keys for different wallets somehow co-exist in the secure module? Sometimes users use multiple wallets by restoring from one of multiple backups. It's an edge case, but it happens.
  4. Is there a way to recover a biometics-protected wallet with common software (like currently openssl and bitcoinj wallet-tool)?

@oliveraemmer
Copy link
Author

@schildbach

  1. You say "It is not a replacement of the spending pin but an addition", but in the app (for the user, per wallet) it's an either/or – correct?

It's not a replacement in the sense that both features co-exist but you're right that they are mutually exclusive. Having both active at the same time isn't supported.

  1. How can keys stored in the secure module (I assume) be backed up and restored in case of hardware failure or loss? I PIN can be written down, or "simply" be remembered.

The key in the secure element/TEE is not extractable which is precisely why it's secure. Here it is important to understand the Bitcoin master key is not imported into the secure module as Android KeyStore doesn't support the secp256k1 elliptical curve. However, an AES key is generated in the secure environment and used to encrypt the wallet file the same way the spending PIN derived AES key did. The key acts as a key encryption key (KEK).
Because the KEK is unextractable and bound to the device, we modified the wallet backup functionality to check if HW encryption is enabled and to decrypt the wallet before backing it up. The backup is then only protected by the backup password, which allows the user to import the file on any other supported Android device.

  1. Can keys for different wallets somehow co-exist in the secure module? Sometimes users use multiple wallets by restoring from one of multiple backups. It's an edge case, but it happens.

Initially when HW-encryption is first activated, a key is generated in the secure environment. When importing a different wallet and activating HW-encryption, that same key will be used for encryption because the key is bound to the application and always uses the same key reference defined in Constants.java.

  1. Is there a way to recover a biometics-protected wallet with common software (like currently openssl and bitcoinj wallet-tool)?

There is no way to recover the biometrics-protected wallet. However, this is only relevant if trying to recover the currently in-use wallet file under /data/data/de.schildbach.wallet/files/wallet-protobuf. A backup file will never be HW-encrypted.

Co-authored-by: Sebastian Nicol <sebastian.r.nicol@gmail.com>
Co-authored-by: Oliver Aemmer <oliver.aemmer@protonmail.ch>
@schildbach
Copy link
Collaborator

Because the KEK is unextractable and bound to the device, we modified the wallet backup functionality to check if HW encryption is enabled and to decrypt the wallet before backing it up. The backup is then only protected by the backup password, which allows the user to import the file on any other supported Android device.

I wonder if we should take that part of this PR and extend it to always remove any kind of wallet encryption (currently: spending PIN) for the back up.

I've been pondering with this for a long time. The issue is people tend to forget (despite warnings in the app) that they still might need to remember their (possibly outdated) spending PIN along with their backup password. That seems too much of an ask for normal users.

As a positive side effect, merging such a change in advance will reduce the size of this PR.

Would you be willing to spearhead such a PR?

@@ -24,6 +24,7 @@ dependencies {
implementation "androidx.room:room-runtime:2.6.1"
annotationProcessor "androidx.room:room-compiler:2.6.1"
implementation 'com.google.guava:guava:31.1-android'
implementation 'androidx.biometric:biometric:1.2.0-alpha04'
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you say if the native Android API would be an option here?

For one, I'm always reluctant to add new dependencies due to supply chain attacks being on the rise. And this dep comes from a not-really-trusted Google repo only.

And second, it's an alpha.

@@ -274,6 +281,9 @@ public Dialog onCreateDialog(final Bundle savedInstanceState) {
if (showEncryptedMessage) {
message.append("\n\n");
message.append(getString(R.string.restore_wallet_dialog_success_encrypted));
} else {
message.append("\n\n");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of adding a message here, we could rework how tutorial hints work and add something like a "security checklist" to the main flow.

…le attack vector.

Co-authored-by: Sebastian Nicol <sebastian.r.nicol@gmail.com>
Co-authored-by: Oliver Aemmer <oliver.aemmer@protonmail.ch>
Copy link

@Gary19751957 Gary19751957 left a comment

Choose a reason for hiding this comment

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

Check my account garydebora7557@gmail.com

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

Successfully merging this pull request may close these issues.

None yet

4 participants