beemdevelopment/Aegis · error · DatabaseImporterException
Invalid number of iterations for PBKDF
Error message
Invalid number of iterations for PBKDF: %d
What it means
Aegis's andOTP importer reads the PBKDF2 iteration count from the first 4 bytes of the imported file. If the parsed integer is below 1, the file cannot contain a valid andOTP key derivation parameter set, so the importer aborts with a DatabaseImporterException before attempting an expensive PBKDF run.
Solutions
- Verify the file is a genuine andOTP encrypted backup (starts with the iteration count as a big-endian int32)
- Re-export from andOTP and select that file instead
- Open the file in a hex editor and check the first 4 bytes decode to a plausible iteration count (> 0)
- Use Aegis's other importers if the file came from a different authenticator app
Example fix
// before
cursor.moveToFirst(); // wrong file opened as andOTP backup
byte[] iterBytes = Arrays.copyOfRange(_data, 0, INT_SIZE);
// after
if (_data.length < INT_SIZE) {
throw new DatabaseImporterException("File too small to be an andOTP backup");
}
int iterations = ByteBuffer.wrap(_data, 0, INT_SIZE).getInt();
if (iterations < 1) {
throw new DatabaseImporterException("Not an andOTP backup: invalid PBKDF iteration count");
} Defensive patterns
Strategy: validation
Validate before calling
byte[] head = Arrays.copyOfRange(fileBytes, 0, 4);
int iterations = ByteBuffer.wrap(head).getInt();
if (iterations < 1 || iterations > 10_000_000) {
throw new IllegalArgumentException("Not an andOTP backup: iterations=" + iterations);
} Try / catch
try {
importer.read(stream, password);
} catch (DatabaseImporterException e) {
if (e.getMessage().contains("iterations")) {
showUserError("Selected file is not a valid andOTP backup");
}
} Prevention
- Only feed andOTP's own encrypted export files to this importer
- Check the file header (first 4 bytes) before import
- Keep andOTP exports unmodified — don't re-zip or re-encode
When it happens
Trigger: Importing a file into Aegis's andOTP importer whose first 4 bytes decode to an integer < 1 — e.g. the user selected a non-andOTP file (wrong export format, encrypted vault, image, etc.) whose leading bytes happen to parse as 0 or negative.
Common situations: User picks the wrong backup file in the Aegis import dialog; an andOTP export that was re-encoded, truncated, or corrupted; a file with a different header layout (other apps' exports) that shifts the iteration field.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Unexpectedly high number of iterations
- Accounts.txt
- Key not found
- Empty secret (empty authority)
- Unexpected master key KDF
AI-assisted analysis of beemdevelopment/Aegis@d6f4e5925a (2026-09-08).
Data as JSON: /api/errors/68657a9e55759bdf.
Report an issue: GitHub.
Appendix: source
Thrown at app/src/main/java/com/beemdevelopment/aegis/importers/AndOtpImporter.java:121
int len = _data.length - offset - NONCE_SIZE - TAG_SIZE;
CryptResult result = CryptoUtils.decrypt(_data, offset + NONCE_SIZE, len, cipher, params);
return read(result.getData());
} catch (IOException | BadPaddingException | JSONException e) {
throw new DatabaseImporterException(e);
} catch (NoSuchAlgorithmException
| InvalidAlgorithmParameterException
| InvalidKeyException
| NoSuchPaddingException
| IllegalBlockSizeException e) {
throw new RuntimeException(e);
}
}
private PBKDFTask.Params getKeyDerivationParams(char[] password) throws DatabaseImporterException {
byte[] iterBytes = Arrays.copyOfRange(_data, 0, INT_SIZE);
int iterations = ByteBuffer.wrap(iterBytes).getInt();
if (iterations < 1) {
throw new DatabaseImporterException(String.format("Invalid number of iterations for PBKDF: %d", iterations));
}
// If number of iterations is this high, it's probably not an andOTP file, so
// abort early in order to prevent having to wait for an extremely long key derivation
// process, only to find out that the user picked the wrong file
if (iterations > 10_000_000L) {
throw new DatabaseImporterException(String.format("Unexpectedly high number of iterations: %d", iterations));
}
byte[] salt = Arrays.copyOfRange(_data, INT_SIZE, INT_SIZE + SALT_SIZE);
return new PBKDFTask.Params("PBKDF2WithHmacSHA1", KEY_SIZE, password, salt, iterations);
}
protected DecryptedState decryptOldFormat(char[] password) throws DatabaseImporterException {
// WARNING: DON'T DO THIS IN YOUR OWN CODE
// this exists solely to support the old andOTP backup format
// it is not a secure way to derive a key from a password
MessageDigest hash;
try {View on GitHub (pinned to d6f4e5925a)