beemdevelopment/Aegis · error · DatabaseImporterException
Unexpected master key cipher
Error message
Unexpected master key cipher: %s
What it means
FreeOTP's master key must be encrypted with AES/GCM/NoPadding. The importer reads "mCipher" from the backup's master key JSON object and throws DatabaseImporterException if it is any other cipher transformation, since Aegis only implements GCM unwrapping for FreeOTP imports.
Solutions
- Update Aegis to a version supporting the new cipher, or re-export from stock FreeOTP
- Inspect mEncryptedKey.mCipher in the JSON to see what was actually used
- If the file was hand-edited, restore the original cipher string
- Re-create tokens in FreeOTP (stock build) and export again
Example fix
// before
if (!_mkCipher.equals("AES/GCM/NoPadding")) {
throw new DatabaseImporterException(String.format("Unexpected master key cipher: %s", _mkCipher));
}
// after
if (!_mkCipher.equals("AES/GCM/NoPadding")) {
throw new DatabaseImporterException(String.format(
"Unexpected master key cipher: %s (only AES/GCM/NoPadding is supported)", _mkCipher));
} Defensive patterns
Strategy: validation
Validate before calling
String cipher = backupJson.getJSONObject("mMasterKey")
.getJSONObject("mEncryptedKey").getString("mCipher");
if (!cipher.equals("AES/GCM/NoPadding")) {
throw new IllegalArgumentException("Unsupported master key cipher: " + cipher);
} Try / catch
try {
importer.read(stream);
} catch (DatabaseImporterException e) {
if (e.getMessage().startsWith("Unexpected master key cipher")) {
showUserError("Backup master key is not AES/GCM — re-export with stock FreeOTP");
}
} Prevention
- Re-export from unmodified FreeOTP if ciphers differ
- Verify mEncryptedKey.mCipher before import
- Avoid forks/patches that change crypto primitives
When it happens
Trigger: Importing a FreeOTP backup whose mEncryptedKey.mCipher is not "AES/GCM/NoPadding" — e.g. from a modified FreeOTP build or an edited JSON file.
Common situations: FreeOTP fork changing cipher mode (e.g. CBC); manual JSON edits; importing a backup from an unrelated app that reuses the FreeOTP schema.
Related errors
- Unexpected cipher
- Unexpected master key KDF
- unsupported otp type:
- Password incorrect
- Invalid number of iterations for PBKDF
AI-assisted analysis of beemdevelopment/Aegis@d6f4e5925a (2026-09-08).
Data as JSON: /api/errors/51dcc5571bbefb0d.
Report an issue: GitHub.
Appendix: source
Thrown at app/src/main/java/com/beemdevelopment/aegis/importers/FreeOtpImporter.java:139
private final byte[] _mkCipherText;
private final byte[] _mkParameters;
private final byte[] _mkToken;
private final byte[] _mkSalt;
private final int _mkIterations;
private final Map<String, String> _entries;
private EncryptedState(JSONObject mkObj, Map<String, String> entries)
throws DatabaseImporterException, JSONException {
super(true);
_mkAlgo = mkObj.getString("mAlgorithm");
if (!_mkAlgo.equals("PBKDF2withHmacSHA1") && !_mkAlgo.equals("PBKDF2withHmacSHA512")) {
throw new DatabaseImporterException(String.format("Unexpected master key KDF: %s", _mkAlgo));
}
JSONObject keyObj = mkObj.getJSONObject("mEncryptedKey");
_mkCipher = keyObj.getString("mCipher");
if (!_mkCipher.equals("AES/GCM/NoPadding")) {
throw new DatabaseImporterException(String.format("Unexpected master key cipher: %s", _mkCipher));
}
_mkCipherText = toBytes(keyObj.getJSONArray("mCipherText"));
_mkParameters = toBytes(keyObj.getJSONArray("mParameters"));
_mkToken = keyObj.getString("mToken").getBytes(StandardCharsets.UTF_8);
_mkSalt = toBytes(mkObj.getJSONArray("mSalt"));
_mkIterations = mkObj.getInt("mIterations");
_entries = entries;
}
public State decrypt(char[] password) throws DatabaseImporterException {
PBKDFTask.Params params = new PBKDFTask.Params(_mkAlgo, MASTER_KEY_SIZE, password, _mkSalt, _mkIterations);
SecretKey passKey = PBKDFTask.deriveKey(params);
return decrypt(passKey);
}
public State decrypt(SecretKey passKey) throws DatabaseImporterException {
byte[] masterKeyBytes;
try {View on GitHub (pinned to d6f4e5925a)