{"record":{"id":"2d9f7a7840c173e3","repo":"MuntashirAkon/AppManager","slug":"checksums-for-master-key-did-not-match","errorCode":null,"errorMessage":"Checksums for master key did not match.","messagePattern":"Checksums for master key did not match\\.","errorType":"exception","errorClass":"BackupException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/backup/RestoreOp.java","lineNumber":270,"sourceCode":"        if (true) {\n            // TODO: 6/2/22 MasterKey may not actually be necessary.\n            return;\n        }\n        String oldChecksum = mChecksum.get(MASTER_KEY);\n        Path masterKey;\n        try {\n            masterKey = KeyStoreUtils.getMasterKey(mUserId);\n        } catch (FileNotFoundException e) {\n            if (oldChecksum == null) return;\n            else\n                throw new BackupException(\"Master key existed when the checksum was made but now it doesn't.\");\n        }\n        if (oldChecksum == null) {\n            throw new BackupException(\"Master key exists but it didn't exist when the backup was made.\");\n        }\n        String newChecksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, masterKey.getContentAsString().getBytes());\n        if (!newChecksum.equals(oldChecksum)) {\n            throw new BackupException(\"Checksums for master key did not match.\");\n        }\n    }\n\n    private void restoreApkFiles() throws BackupException {\n        if (!mBackupFlags.backupApkFiles()) {\n            throw new BackupException(\"APK restore is requested but backup doesn't contain any source files.\");\n        }\n        Path[] backupSourceFiles = mBackupItem.getSourceFiles();\n        if (backupSourceFiles.length == 0) {\n            // No source backup found\n            throw new BackupException(\"Source restore is requested but there are no source files.\");\n        }\n        boolean isVerified = true;\n        if (mPackageInfo != null) {\n            // Check signature of the installed app\n            List<String> certChecksumList = Arrays.asList(PackageUtils.getSigningCertChecksums(mBackupInfo.checksumAlgo, mPackageInfo, false));\n            String[] certChecksums = BackupItems.Checksum.getCertChecksums(mChecksum);\n            for (String checksum : certChecksums) {","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/backup/RestoreOp.java#L252-L288","documentation":"checkMasterKey() hashes the current keystore master key bytes with the backup's checksum algorithm and compares the result to the checksum recorded at backup time. A mismatch means the master key changed since the backup was made, so encrypted backup data (key store/crypto-protected files) cannot be decrypted with the current key. Currently unreachable in this code version because checkMasterKey() returns early.","triggerScenarios":"During restore, both the keystore key and the recorded old checksum exist, but DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, masterKey.getContentAsString().getBytes()) != oldChecksum.","commonSituations":"Android keystore keys were rotated/regenerated (clearing credentials, factory reset then restore of keystore, vendor keystore changes); restoring backups on a different device or user profile where a different master key exists; using a backup made before a key reset.","solutions":["Restore the backup on the original device/user where the master key matches; keys are typically not portable across devices.","Regenerate the backup on the current device if the original key is unrecoverable — old encrypted data cannot be decrypted after key rotation.","Verify the checksum file belongs to this exact backup; a swapped checksum file yields a false mismatch.","Use the skip/decrypt-unsupported paths or an App Manager version where master-key verification is disabled, if the backup is unencrypted."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Verify master key checksum yourself before restore:\nPath key = null;\ntry { key = KeyStoreUtils.getMasterKey(userId); } catch (FileNotFoundException ignored) {}\nif (key != null && checksums.get(MASTER_KEY) != null) {\n    String now = DigestUtils.getHexDigest(info.checksumAlgo, key.getContentAsString().getBytes());\n    if (!now.equals(checksums.get(MASTER_KEY))) { /* key rotated: abort early */ }\n}","typeGuard":null,"tryCatchPattern":"try { restoreOp.runRestore(); } catch (BackupException e) {\n    if (e.getMessage().contains(\"Checksums for master key did not match\")) {\n        // restore on the original device/user or recreate the backup\n    }\n}","preventionTips":["Avoid actions that rotate/regenerate keystore keys (credential resets, factory reset) while backups are pending restore.","Test-restore backups shortly after creating them to catch key drift early.","Re-create backups after any keystore change."],"tags":["android","keystore","backup","encryption"],"backgroundTag":"checksum-mismatch","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}