Skip to content

Conversation

@shubham1g5
Copy link
Contributor

@shubham1g5 shubham1g5 commented Jun 2, 2025

Product Description

No user visible changes, Refactors the existing code around android key store to make it easier to extend.

Labels and Review

  • Do we need to enhance the manual QA test coverage ? If yes, the "QA Note" label is set correctly
  • Does the PR introduce any major changes worth communicating ? If yes, the "Release Note" label is set and a "Release Note" is specified in PR description.
  • Risk label is set correctly
  • The set of people pinged as reviewers is appropriate for the level of risk of the change

@coderabbitai
Copy link

coderabbitai bot commented Jun 2, 2025

📝 Walkthrough

Walkthrough

This set of changes introduces a modular and extensible key management system for encryption in the application. The previous logic for handling encryption keys, which was embedded in the EncryptionKeyProvider class, is now refactored to delegate key management to specialized handler classes: RsaKeystoreHandler for pre-Android M devices and AesKeystoreHandler for Android M and above. Supporting utilities such as AndroidKeyStore and the KeystoreHandler interface are introduced. The refactor also updates all usages and tests to use the new interface, replacing the previous context-based and boolean-flagged method calls with explicit getKeyForEncryption() and getKeyForDecryption() methods. Test classes and mock providers are updated accordingly.

Sequence Diagram(s)

sequenceDiagram
    participant Application
    participant EncryptionKeyProvider
    participant KeystoreHandler
    participant RsaKeystoreHandler
    participant AesKeystoreHandler
    participant AndroidKeyStore

    Application->>EncryptionKeyProvider: getKeyForEncryption()/getKeyForDecryption()
    EncryptionKeyProvider->>EncryptionKeyProvider: getHandler(isEncrypt)
    alt If RSA key exists
        EncryptionKeyProvider->>RsaKeystoreHandler: getKeyOrGenerate()
        RsaKeystoreHandler->>AndroidKeyStore: doesKeyExists(alias)
        alt Key exists
            RsaKeystoreHandler->>AndroidKeyStore: retrieve RSA Key
        else Key does not exist
            RsaKeystoreHandler->>AndroidKeyStore: generate RSA Key
        end
        RsaKeystoreHandler-->>EncryptionKeyProvider: EncryptionKeyAndTransform
    else If Android M+ and no RSA key
        EncryptionKeyProvider->>AesKeystoreHandler: getKeyOrGenerate()
        AesKeystoreHandler->>AndroidKeyStore: doesKeyExists(alias)
        alt Key exists
            AesKeystoreHandler->>AndroidKeyStore: retrieve AES Key
        else Key does not exist
            AesKeystoreHandler->>AndroidKeyStore: generate AES Key
        end
        AesKeystoreHandler-->>EncryptionKeyProvider: EncryptionKeyAndTransform
    end
    EncryptionKeyProvider-->>Application: EncryptionKeyAndTransform
Loading

Suggested labels

skip-integration-tests

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (7)
app/unit-tests/src/org/commcare/utils/EncryptionUtilsTest.java (1)

38-38: Consider using getKeyForEncryption() for encryption operations.

In the testDecryption() method, you're using getKeyForDecryption() to obtain a key for the encryption step. For consistency and clarity, consider using getKeyForEncryption() for encryption operations, even in decryption tests.

-        EncryptionKeyAndTransform kat = provider.getKeyForDecryption();
+        EncryptionKeyAndTransform kat = provider.getKeyForEncryption();
app/src/org/commcare/fragments/personalId/PersonalIdBiometricConfigFragment.java (2)

259-259: Method call added but implementation is missing.

The call to storeBiometricInvalidationKey() is added at the appropriate place when biometric or PIN configuration is confirmed, but the method implementation is empty.

This appears to be preparation for biometric key invalidation functionality. Would you like me to help implement this method or open an issue to track this TODO?


273-275: Empty method requires implementation.

The storeBiometricInvalidationKey() method is declared but contains no implementation, making it a no-op currently.

Based on the method name and context within the encryption key management refactor, this method should likely handle storing or managing biometric invalidation keys. Would you like me to generate an implementation or create a TODO issue for this?

app/src/org/commcare/android/security/AndroidKeyStore.kt (1)

8-19: LGTM: Well-designed KeyStore singleton with minor style nitpick.

The singleton design with lazy initialization is appropriate for centralizing Android KeyStore access. The API is clean and the KeyStore is properly initialized.

Minor style improvement:

    fun doesKeyExists(alias: String): Boolean {
-        return instance.containsAlias(alias);
+        return instance.containsAlias(alias)
    }

The semicolon is not needed in Kotlin.

app/src/org/commcare/android/security/AesKeystoreHandler.kt (1)

21-33: LGTM: Solid AES key management implementation with minor suggestion.

The implementation correctly handles key retrieval and generation with appropriate security configurations. The use of EncryptionKeyAndTransform with the standard AES/CBC/PKCS7Padding transformation is appropriate.

Consider adding explicit type checking for robustness:

        val key = if (entry is KeyStore.SecretKeyEntry) {
            entry.secretKey
+        } else if (entry != null) {
+            // Log unexpected key type and regenerate
+            generateAesKey(alias, needsUserAuth)
        } else {
            generateAesKey(alias, needsUserAuth)
        }

This would handle cases where a key exists but is not the expected SecretKey type.

app/src/org/commcare/android/security/RsaKeystoreHandler.kt (1)

15-15: Fix typo in documentation.

-* User for Pre Android M devices to do RSA encryption with Android Key Store
+* Used for Pre Android M devices to do RSA encryption with Android Key Store
app/src/org/commcare/utils/EncryptionKeyProvider.java (1)

45-45: Consider making user authentication configurable.

The user authentication requirement is hardcoded to false. Consider making this configurable for future flexibility.

For future extensibility, consider making the user authentication requirement configurable through a constructor parameter or system property, especially since the PR objectives mention making the code easier to extend.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6c2d5dc and fae5d58.

📒 Files selected for processing (11)
  • app/src/org/commcare/CommCareApplication.java (1 hunks)
  • app/src/org/commcare/android/security/AesKeystoreHandler.kt (1 hunks)
  • app/src/org/commcare/android/security/AndroidKeyStore.kt (1 hunks)
  • app/src/org/commcare/android/security/KeystoreHandler.kt (1 hunks)
  • app/src/org/commcare/android/security/RsaKeystoreHandler.kt (1 hunks)
  • app/src/org/commcare/connect/database/ConnectDatabaseUtils.java (2 hunks)
  • app/src/org/commcare/fragments/personalId/PersonalIdBiometricConfigFragment.java (2 hunks)
  • app/src/org/commcare/utils/EncryptionKeyProvider.java (1 hunks)
  • app/unit-tests/src/org/commcare/CommCareTestApplication.java (1 hunks)
  • app/unit-tests/src/org/commcare/utils/EncryptionUtilsTest.java (4 hunks)
  • app/unit-tests/src/org/commcare/utils/MockEncryptionKeyProvider.java (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
app/unit-tests/src/org/commcare/utils/EncryptionUtilsTest.java (1)
app/unit-tests/src/org/commcare/CommCareTestApplication.java (1)
  • CommCareTestApplication (65-327)
app/src/org/commcare/connect/database/ConnectDatabaseUtils.java (1)
app/src/org/commcare/CommCareApplication.java (1)
  • CommCareApplication (154-1260)
app/src/org/commcare/android/security/AesKeystoreHandler.kt (1)
app/src/org/commcare/utils/EncryptionKeyAndTransform.java (1)
  • EncryptionKeyAndTransform (10-39)
app/src/org/commcare/android/security/RsaKeystoreHandler.kt (2)
app/src/org/commcare/android/security/AndroidKeyStore.kt (1)
  • doesKeyExists (16-18)
app/src/org/commcare/utils/EncryptionKeyAndTransform.java (1)
  • EncryptionKeyAndTransform (10-39)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Lint Code Base
🔇 Additional comments (11)
app/unit-tests/src/org/commcare/CommCareTestApplication.java (1)

81-81: LGTM! Context parameter correctly added.

The change appropriately updates the MockEncryptionKeyProvider instantiation to pass the application context, aligning with the refactored constructor that now requires a Context parameter.

app/src/org/commcare/android/security/KeystoreHandler.kt (1)

5-7: Excellent interface design!

The KeystoreHandler interface provides a clean abstraction for key management with a single, well-named method that clearly indicates its dual purpose of retrieving existing keys or generating new ones when needed.

app/unit-tests/src/org/commcare/utils/EncryptionUtilsTest.java (3)

20-20: LGTM! Provider instantiation correctly updated.

The change properly updates the MockEncryptionKeyProvider instantiation to include the required context parameter from CommCareTestApplication.instance().


26-26: LGTM! API methods correctly updated.

The migration from the generic getKey(null, boolean) method to the more explicit getKeyForEncryption() method improves code clarity and aligns with the refactored encryption key provider API.

Also applies to: 51-51, 57-57, 63-63


42-42: LGTM! Correct use of getKeyForDecryption() for decryption operation.

Appropriately uses getKeyForDecryption() for the actual decryption step in the test.

app/src/org/commcare/CommCareApplication.java (1)

266-266: LGTM! Context parameter correctly added to EncryptionKeyProvider.

The change appropriately updates the EncryptionKeyProvider instantiation to pass the application context (this), which is required by the refactored constructor and enables the new modular key management system.

app/src/org/commcare/connect/database/ConnectDatabaseUtils.java (2)

23-24: LGTM: Clean API change for encryption key retrieval.

The change from getKey(context, forEncryption) to getKeyForEncryption() provides a cleaner, more explicit API. The context is no longer needed as a parameter since the EncryptionKeyProvider now holds it internally.


80-81: LGTM: Consistent API usage for decryption key retrieval.

The change to getKeyForDecryption() is consistent with the encryption case and provides clear separation of concerns between encryption and decryption key operations.

app/src/org/commcare/android/security/AesKeystoreHandler.kt (1)

35-53: LGTM: Proper AES key generation with security best practices.

The key generation follows Android security best practices:

  • Correct use of KeyGenParameterSpec with appropriate purposes
  • Proper block mode (CBC) and padding (PKCS7)
  • Version-appropriate user authentication settings
  • Biometric enrollment invalidation for enhanced security
app/unit-tests/src/org/commcare/utils/MockEncryptionKeyProvider.java (1)

20-40: LGTM! Clean refactoring for test mock implementation.

The separation of encryption and decryption key retrieval methods improves API clarity. The exception handling approach is appropriate for test code.

app/src/org/commcare/utils/EncryptionKeyProvider.java (1)

29-35: Clean delegation to handler pattern.

The refactoring to use specialized handlers improves modularity and aligns with the Single Responsibility Principle.

Comment on lines 24 to 31
if (doesKeyExists()) {
val entry = AndroidKeyStore.instance.getEntry(alias, null) as KeyStore.PrivateKeyEntry
val key = entry.privateKey
return EncryptionKeyAndTransform(key, "RSA/ECB/PKCS1Padding")
} else {
return generateRsaKey()
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical: Return appropriate key based on encryption mode.

The method always returns the private key when a key exists, but for encryption operations, it should return the public key.

 override fun getKeyOrGenerate(): EncryptionKeyAndTransform {
     if (doesKeyExists()) {
         val entry = AndroidKeyStore.instance.getEntry(alias, null) as KeyStore.PrivateKeyEntry
-        val key = entry.privateKey
+        val key = if (isEncryptMode) entry.certificate.publicKey else entry.privateKey
         return EncryptionKeyAndTransform(key, "RSA/ECB/PKCS1Padding")
     } else {
         return generateRsaKey()
     }
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In app/src/org/commcare/android/security/RsaKeystoreHandler.kt around lines 24
to 31, the code always returns the private key when a key exists, but for
encryption, it should return the public key instead. Modify the code to check
the encryption mode and return the public key from the KeyStore.PrivateKeyEntry
when performing encryption operations, ensuring the correct key type is used.

Comment on lines 33 to 42
fun doesKeyExists(): Boolean {
val keystore = AndroidKeyStore.instance
if (keystore.containsAlias(alias)) {
val entry = keystore.getEntry(alias, null)
if (entry is KeyStore.PrivateKeyEntry) {
return true;
}
}
return false;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Simplify by using existing AndroidKeyStore utility.

The doesKeyExists() method duplicates functionality already available in AndroidKeyStore.

Based on the relevant code snippet, AndroidKeyStore already provides a doesKeyExists(alias: String) method. Consider using it directly:

-fun doesKeyExists(): Boolean {
-    val keystore = AndroidKeyStore.instance
-    if (keystore.containsAlias(alias)) {
-        val entry = keystore.getEntry(alias, null)
-        if (entry is KeyStore.PrivateKeyEntry) {
-            return true;
-        }
-    }
-    return false;
-}
+fun doesKeyExists(): Boolean {
+    return AndroidKeyStore.doesKeyExists(alias) && 
+           AndroidKeyStore.instance.getEntry(alias, null) is KeyStore.PrivateKeyEntry
+}

Also remove the unnecessary semicolon on line 38:

-            return true;
+            return true

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In app/src/org/commcare/android/security/RsaKeystoreHandler.kt lines 33 to 42,
simplify the doesKeyExists() method by replacing the manual key existence check
with a direct call to AndroidKeyStore's existing doesKeyExists(alias: String)
method. Also, remove the unnecessary semicolon on line 38 to clean up the code.

Comment on lines 51 to 57
public EncryptionKeyAndTransform getKeyForEncryption(Context context) {
return getHandler(true).getKeyOrGenerate();
}

private static EncryptionKeyAndTransform generateKeyInKeystore(Context context, boolean trueForEncrypt)
throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_NAME);
KeyGenParameterSpec keySpec = new KeyGenParameterSpec.Builder(SECRET_NAME,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.build();

keyGenerator.init(keySpec);
return new EncryptionKeyAndTransform(keyGenerator.generateKey(), String.format("%s/%s/%s", ALGORITHM, BLOCK_MODE, PADDING));
} else {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", KEYSTORE_NAME);

GregorianCalendar start = new GregorianCalendar();
GregorianCalendar end = new GregorianCalendar();
end.add(Calendar.YEAR, 100);
KeyPairGeneratorSpec keySpec = new KeyPairGeneratorSpec.Builder(context)
// You'll use the alias later to retrieve the key. It's a key for the key!
.setAlias(SECRET_NAME)
// The subject used for the self-signed certificate of the generated pair
.setSubject(new X500Principal(String.format("CN=%s", SECRET_NAME)))
// The serial number used for the self-signed certificate of the
// generated pair.
.setSerialNumber(BigInteger.valueOf(1337))
// Date range of validity for the generated pair.
.setStartDate(start.getTime())
.setEndDate(end.getTime())
.build();

generator.initialize(keySpec);
KeyPair pair = generator.generateKeyPair();

Key key = trueForEncrypt ? pair.getPublic() : pair.getPrivate();
return new EncryptionKeyAndTransform(key, "RSA/ECB/PKCS1Padding");
}
public EncryptionKeyAndTransform getKeyForDecryption(Context context) {
return getHandler(false).getKeyOrGenerate();
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove redundant methods or clarify their purpose.

These methods accept a Context parameter but ignore it, using the instance's context instead. This is confusing and could lead to bugs.

Either remove these methods if they're not needed for backward compatibility, or update them to use the provided context:

-public EncryptionKeyAndTransform getKeyForEncryption(Context context) {
-    return getHandler(true).getKeyOrGenerate();
-}
-
-public EncryptionKeyAndTransform getKeyForDecryption(Context context) {
-    return getHandler(false).getKeyOrGenerate();
-}

If backward compatibility is required, consider marking them as deprecated:

@Deprecated
public EncryptionKeyAndTransform getKeyForEncryption(Context context) {
    // Use instance method instead
    return getKeyForEncryption();
}
🤖 Prompt for AI Agents
In app/src/org/commcare/utils/EncryptionKeyProvider.java around lines 51 to 57,
the methods getKeyForEncryption and getKeyForDecryption accept a Context
parameter but do not use it, which is confusing. To fix this, either remove
these methods if they are unnecessary or update them to use the provided Context
parameter properly. If these methods must remain for backward compatibility,
mark them as @Deprecated and modify their implementation to call the instance
methods without the Context parameter, clearly indicating their deprecated
status.

@shubham1g5 shubham1g5 force-pushed the androidKeyStoreEncryptionRefactor branch from fae5d58 to e9d8bd8 Compare June 2, 2025 06:32
@Override
public EncryptionKeyAndTransform getKey(Context context, boolean trueForEncrypt)
public EncryptionKeyAndTransform getKeyForEncryption() {
try {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Why not have getKey convert the NoSuchAlgorithmException to a RuntimeException to avoid duplicated code in these two functions?

}
}

fun doesKeyExists(): Boolean {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Should be doesKeyExist (no 's' at the end).

}
}

fun doesKeyExists(alias: String): Boolean {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Should be doesKeyExist (no 's' at the end).

val key = if (entry is KeyStore.SecretKeyEntry) {
entry.secretKey
} else {
generateAesKey(alias, needsUserAuth)
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be "key = generateAesKey"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

all of this is key = assignment in line 24 above.

}
}
public EncryptionKeyProvider(Context context) {
this.context = context.getApplicationContext();
Copy link
Contributor

Choose a reason for hiding this comment

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

@shubham1g5 context is already application, can be set directly

Comment on lines 51 to 52
public EncryptionKeyAndTransform getKeyForEncryption(Context context) {
return getHandler(true).getKeyOrGenerate();
Copy link
Contributor

Choose a reason for hiding this comment

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

@shubham1g5 We might remove this as not used

Comment on lines 55 to 56
public EncryptionKeyAndTransform getKeyForDecryption(Context context) {
return getHandler(false).getKeyOrGenerate();
Copy link
Contributor

Choose a reason for hiding this comment

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

@shubham1g5 We might remove this?

object AndroidKeyStore {
const val ANDROID_KEY_STORE_NAME = "AndroidKeyStore"
val instance: KeyStore by lazy {
KeyStore.getInstance(ANDROID_KEY_STORE_NAME).apply {
Copy link
Contributor

Choose a reason for hiding this comment

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

@shubham1g5 I think we should remove the apply

Copy link
Contributor Author

Choose a reason for hiding this comment

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

why so ?

Copy link
Contributor

Choose a reason for hiding this comment

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

@shubham1g5 as we are setting params null so ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we still need to call load on keystore to load it and being able to use it


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
builder.setUserAuthenticationRequired(needsUserAuth)
builder.setInvalidatedByBiometricEnrollment(needsUserAuth)
Copy link
Contributor

Choose a reason for hiding this comment

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

@shubham1g5 Just a question: Whenever biometric is altered, key becomes invalid, how does app recovers old keys to unlock DB?

Copy link
Contributor Author

@shubham1g5 shubham1g5 Jun 2, 2025

Choose a reason for hiding this comment

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

Currently we don't any keys that gets invalidated tied to DB - details in here

Copy link
Contributor

Choose a reason for hiding this comment

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

@shubham1g5 No, I mean when biometric is altered, what will happen to key?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah so how do we recover/decode the DB phrase which is already stored locally which was encrypted using key store previously?

*/
object AndroidKeyStore {
const val ANDROID_KEY_STORE_NAME = "AndroidKeyStore"
val instance: KeyStore by lazy {
Copy link
Contributor

Choose a reason for hiding this comment

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

@shubham1g5 +1 for lazy load

@shubham1g5
Copy link
Contributor Author

@damagatchi retest this please

Copy link
Contributor

@OrangeAndGreen OrangeAndGreen left a comment

Choose a reason for hiding this comment

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

Nice to see the extra code in CommCareApplication go away!

@shubham1g5
Copy link
Contributor Author

@damagatchi retest this please

@shubham1g5 shubham1g5 merged commit 738a1f4 into master Jun 3, 2025
5 of 9 checks passed
@shubham1g5 shubham1g5 deleted the androidKeyStoreEncryptionRefactor branch June 3, 2025 03:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-integration-tests Skip android tests.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants