{"record":{"id":"cde255c64e374db5","repo":"MuntashirAkon/AppManager","slug":"could-not-decrypt-encrypted-password","errorCode":null,"errorMessage":"Could not decrypt encrypted password.","messagePattern":"Could not decrypt encrypted password\\.","errorType":"exception","errorClass":"KeyStoreException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/KeyStoreManager.java","lineNumber":481,"sourceCode":"\n    /**\n     * Get App Manager's KeyStore password. The password is stored in the shared preferences in an\n     * encrypted format (the encryption/decryption is performed via AndroidKeyStore). In case the\n     * user restores from the cache or accidentally deletes all entries from the shared pref, App\n     * Manager will ask for KeyStore password again.\n     *\n     * @return KeyStore password in decrypted format. {@link Utils#clearChars(char[])} must be called when done.\n     */\n    @CheckResult\n    @NonNull\n    public char[] getAmKeyStorePassword() throws KeyStoreException {\n        String encryptedPass = sSharedPreferences.getString(PREF_AM_KEYSTORE_PASS, null);\n        if (encryptedPass == null) {\n            throw new KeyStoreException(\"No saved password for KeyStore.\");\n        }\n        char[] realPassword = getDecryptedPassword(mContext, encryptedPass);\n        if (realPassword == null) {\n            throw new KeyStoreException(\"Could not decrypt encrypted password.\");\n        }\n        return realPassword;\n    }\n\n    /**\n     * @return Password for the given alias. {@link Utils#clearChars(char[])} must be called when done.\n     * @deprecated Kept for migratory purposes only, deprecated since v2.6.3. To be removed in v3.0.0.\n     */\n    @Deprecated\n    @CheckResult\n    @NonNull\n    private char[] getAliasPassword(@NonNull String alias) throws KeyStoreException {\n        char[] password;\n        String prefAlias = getPrefAlias(alias);\n        if (sSharedPreferences.contains(prefAlias)) {\n            String encryptedPass = sSharedPreferences.getString(prefAlias, null);\n            if (encryptedPass == null) {\n                throw new KeyStoreException(\"Stored pass is empty for alias \" + alias);","sourceCodeStart":463,"sourceCodeEnd":499,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/KeyStoreManager.java#L463-L499","documentation":"getAmKeyStorePassword loads the App Manager keystore password from SharedPreferences, where it is stored encrypted. It throws KeyStoreException when the encrypted password exists but getDecryptedPassword returns null, meaning decryption failed (wrong/corrupted Crypto trapdoor or broken saved blob).","triggerScenarios":"Calling getAmKeyStorePassword() when sSharedPreferences contains PREF_AM_KEYSTORE_PASS but getDecryptedPassword(mContext, encryptedPass) returns null — e.g. crypto key material unavailable or the stored ciphertext is corrupt.","commonSituations":"Device crypto (e.g. Android Keystore-backed) reset or wiped after OS update/biometric change; app data partially restored from backup so the ciphertext no longer matches the decryption key; corruption of the prefs XML.","solutions":["Re-set the App Manager keystore password so a fresh encrypted value is saved under PREF_AM_KEYSTORE_PASS.","Clear the stale preference entry (remove PREF_AM_KEYSTORE_PASS) and prompt the user to re-enter credentials.","Check that the crypto primitive used by getDecryptedPassword (Android Keystore key) is valid and re-initialize it if invalidated.","If prefs were restored from a backup, restore app data from the same device instead, or reconfigure the keystore."],"exampleFix":"// before\nchar[] realPassword = getDecryptedPassword(mContext, encryptedPass);\nif (realPassword == null) {\n    throw new KeyStoreException(\"Could not decrypt encrypted password.\");\n}\n// after\nchar[] realPassword = getDecryptedPassword(mContext, encryptedPass);\nif (realPassword == null) {\n    sSharedPreferences.edit().remove(PREF_AM_KEYSTORE_PASS).apply();\n    realPassword = promptUserForKeyStorePassword(); // re-encrypt and save\n    if (realPassword == null) throw new KeyStoreException(\"Could not decrypt encrypted password.\");\n}","handlingStrategy":"try-catch","validationCode":"// pre-check before requesting the AM keystore password\nif (!sSharedPreferences.contains(PREF_AM_KEYSTORE_PASS)) {\n    throw new KeyStoreException(\"No saved password for KeyStore.\"); // prompt user to set one first\n}","typeGuard":null,"tryCatchPattern":"// try\ntry {\n    char[] pass = keyStoreManager.getAmKeyStorePassword();\n} catch (KeyStoreException e) {\n    // password blob undecryptable: reset saved password and re-prompt\n    resetSavedKeyStorePassword();\n    promptUserForKeyStorePassword();\n}","preventionTips":["Always re-encrypt and save the password through the app's own save path, never edit prefs manually.","Avoid restoring app data across devices — the crypto key won't match the restored ciphertext.","Handle Android Keystore key invalidation (biometric/lock changes) by detecting and re-keying on startup.","Wipe the stale pref when decryption fails so callers can distinguish 'unset' from 'corrupt'."],"tags":["keystore","crypto","android","decryption-failed"],"backgroundTag":"decryption-failed","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}