MuntashirAkon/AppManager · error · KeyStoreException
Could not decrypt encrypted password.
Error message
Could not decrypt encrypted password.
What it means
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).
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.
Example fix
// before
char[] realPassword = getDecryptedPassword(mContext, encryptedPass);
if (realPassword == null) {
throw new KeyStoreException("Could not decrypt encrypted password.");
}
// after
char[] realPassword = getDecryptedPassword(mContext, encryptedPass);
if (realPassword == null) {
sSharedPreferences.edit().remove(PREF_AM_KEYSTORE_PASS).apply();
realPassword = promptUserForKeyStorePassword(); // re-encrypt and save
if (realPassword == null) throw new KeyStoreException("Could not decrypt encrypted password.");
} Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check before requesting the AM keystore password
if (!sSharedPreferences.contains(PREF_AM_KEYSTORE_PASS)) {
throw new KeyStoreException("No saved password for KeyStore."); // prompt user to set one first
} Try / catch
// try
try {
char[] pass = keyStoreManager.getAmKeyStorePassword();
} catch (KeyStoreException e) {
// password blob undecryptable: reset saved password and re-prompt
resetSavedKeyStorePassword();
promptUserForKeyStorePassword();
} Prevention
- 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'.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Decrypted pass is empty for alias
- Could not load AES local protection key from keystore
- Failed to setup metadata.
- No KeyPair with alias
- No KeyPair with alias
AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12).
Data as JSON: /api/errors/cde255c64e374db5.
Report an issue: GitHub.
Appendix: source
Thrown at app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/KeyStoreManager.java:481
/**
* Get App Manager's KeyStore password. The password is stored in the shared preferences in an
* encrypted format (the encryption/decryption is performed via AndroidKeyStore). In case the
* user restores from the cache or accidentally deletes all entries from the shared pref, App
* Manager will ask for KeyStore password again.
*
* @return KeyStore password in decrypted format. {@link Utils#clearChars(char[])} must be called when done.
*/
@CheckResult
@NonNull
public char[] getAmKeyStorePassword() throws KeyStoreException {
String encryptedPass = sSharedPreferences.getString(PREF_AM_KEYSTORE_PASS, null);
if (encryptedPass == null) {
throw new KeyStoreException("No saved password for KeyStore.");
}
char[] realPassword = getDecryptedPassword(mContext, encryptedPass);
if (realPassword == null) {
throw new KeyStoreException("Could not decrypt encrypted password.");
}
return realPassword;
}
/**
* @return Password for the given alias. {@link Utils#clearChars(char[])} must be called when done.
* @deprecated Kept for migratory purposes only, deprecated since v2.6.3. To be removed in v3.0.0.
*/
@Deprecated
@CheckResult
@NonNull
private char[] getAliasPassword(@NonNull String alias) throws KeyStoreException {
char[] password;
String prefAlias = getPrefAlias(alias);
if (sSharedPreferences.contains(prefAlias)) {
String encryptedPass = sSharedPreferences.getString(prefAlias, null);
if (encryptedPass == null) {
throw new KeyStoreException("Stored pass is empty for alias " + alias);View on GitHub (pinned to 0152f468fc)