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

Encrypt credentials in memory #2723

Open
wants to merge 45 commits into
base: master
Choose a base branch
from
Open

Conversation

avazirna
Copy link
Contributor

@avazirna avazirna commented Oct 10, 2023

Summary

This PR addresses an issue flagged by the auditors in which CommCare stores sensitive data (user credentials) in heap memory in plaintext, meaning that a memory dump would be sufficient for an attacker to gain unauthorised access to the app. The proposal was to encrypt the user's credentials while in memory and store any cryptographic keys used in the process in the Android keyStore. The tricky part is that KeyGenParameterSpec, which is the recommended API to generate and store keys in the KeyStore, is only available from API 23, so for devices running Android 5 - 5.1.1, a different API had to be used, KeyPairGeneratorSpec. KeyPairGeneratorSpec generates key pairs which are used in asymmetric algorithms, such as RSA, this forced the need to support both algorithms AES and RSA.

Ticket: https://dimagi-dev.atlassian.net/browse/INDIV-98

Safety Assurance

  • [ x ] I have confidence that this PR will not introduce a regression for the reasons below

Safety story

This feature shouldn't affect the user in any way, the principle is just to encrypt the username and password when these are set and decrypt when returned. However, we still need to consider any potential slowness caused by running cryptographic operations. This will be properly assessed during QA.
A note for reviewers is around the generation of the cryptographic key, this is currently done during app initialisation, and this is a process that needs to happen in order to install the key in the KeyStore, the question is whether there are other scenarios to consider?

Cross-request: dimagi/commcare-core#1349

@avazirna
Copy link
Contributor Author

@damagatchi retest this please

@avazirna
Copy link
Contributor Author

@damagatchi retest this please

@avazirna
Copy link
Contributor Author

@damagatchi retest this please

@shubham1g5
Copy link
Contributor

@avazirna There is no description or context in these PRs to associate PR reviews. Can we add more context to these PRs in terms of what necessitate these changes, safety story and testing around different Android OS if there is dependency on different Android versions with Android Key store involved here etc.

@avazirna
Copy link
Contributor Author

@damagatchi retest this please

@avazirna
Copy link
Contributor Author

@avazirna There is no description or context in these PRs to associate PR reviews. Can we add more context to these PRs in terms of what necessitate these changes, safety story and testing around different Android OS if there is dependency on different Android versions with Android Key store involved here etc.

Yes, I was looking into an issue that was causing most of the instrumentation tests to fail. It should be sorted now.

@avazirna avazirna marked this pull request as ready for review October 13, 2023 20:59
@avazirna
Copy link
Contributor Author

@damagatchi retest this please

@avazirna avazirna force-pushed the encrypt-credentials-in-memory branch 2 times, most recently from 782573d to 0ac80b0 Compare December 7, 2023 09:21
@avazirna avazirna force-pushed the encrypt-credentials-in-memory branch from 0ac80b0 to efe1908 Compare December 7, 2023 09:48
app/build.gradle Outdated
* map. The task registerServiceProviders is responsible for iterating over it and create the
* configuration files under META-INF/services
*/
SERVICE_PROVIDERS = ['org.commcare.util.IEncryptionKeyProvider' : 'org.commcare.utils.EncryptionKeyProvider']
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the reasoning behind specifying it here instead of Java - registerServiceKeyProvider(new EncryptionKeyProvider() ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@shubham1g5 this is just to create the static configuration files, the instantiation is done by the JRE using the ServiceLoader. The reasoning here is to decouple the service interface from its implementations, more concretely, it removes any dependency between commcare-android and commcare-core when it comes to IEncryptionKeyProvider implementations.

@@ -228,6 +231,8 @@ public void onCreate() {
setRoots();
prepareTemporaryStorage();

getEncryptionKeyProvider().generateCryptographicKeyInKeyStore(USER_CREDENTIALS_KEY_ALIAS);
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this key is not user specific, can we call it something general like cc_in_memory_encryption_key ?

app/build.gradle Outdated
@@ -632,3 +640,17 @@ downloadLicenses {
includeProjectDependencies = true
dependencyConfiguration = 'compile'
}

task registerServiceProviders {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why add it at build time instead of just having a static file ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@shubham1g5 that was the initial approach but I thought about making it easy for future additions and also to put this on others radar, a static file can very easily be overlooked. So, not necessarily strong reasons.

Copy link
Contributor

Choose a reason for hiding this comment

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

Got it, I would still prefer a static file if we go with service provider approach as this adds an unnecessary build step without any strong advantages.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reverted

@avazirna avazirna force-pushed the encrypt-credentials-in-memory branch from 0138c07 to 7d66b9f Compare January 23, 2024 12:24
@avazirna avazirna requested a review from ctsims January 23, 2024 23:11
@avazirna avazirna force-pushed the encrypt-credentials-in-memory branch from cae26be to db7ef66 Compare January 24, 2024 08:21
@avazirna
Copy link
Contributor Author

@damagatchi retest this please

@avazirna avazirna modified the milestones: 2.54, 2.55 Apr 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants