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

  1. Verify the file is a genuine andOTP encrypted backup (starts with the iteration count as a big-endian int32)
  2. Re-export from andOTP and select that file instead
  3. Open the file in a hex editor and check the first 4 bytes decode to a plausible iteration count (> 0)
  4. 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

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


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)