MuntashirAkon/AppManager · error · IOException
Stream does not contain an unencrypted private key.
Error message
Stream does not contain an unencrypted private key.
What it means
generatePrivateKey parses a PEM/DER private key stream, accumulating base64 content between BEGIN/END markers. If no base64 key material is found (empty accumulation), it throws IOException "Stream does not contain an unencrypted private key." — i.e. the input wasn't an unencrypted PEM private key.
Solutions
- Supply an unencrypted PEM private key (-----BEGIN PRIVATE KEY----- or -----BEGIN RSA PRIVATE KEY-----).
- Decrypt an encrypted key first: openssl pkcs8 -topk8 -nocrypt -in encrypted.key -out unencrypted.key (enter passphrase, choose empty).
- Verify the correct file is selected — a private key file, not the certificate.
- Convert non-PEM formats (e.g. puttygen export to OpenSSH/PEM).
Example fix
// before InputStream is = cr.openInputStream(encryptedKeyUri); PrivateKey pk = KeyStoreUtils.generatePrivateKey(is); // after // decrypt on the command line first: // openssl pkcs8 -topk8 -nocrypt -in encrypted.key -out plain.key InputStream is = cr.openInputStream(plainKeyUri); PrivateKey pk = KeyStoreUtils.generatePrivateKey(is);
Defensive patterns
Strategy: validation
Validate before calling
// validate the stream is an unencrypted PEM private key before parsing
String pem = readAll(is);
if (!(pem.contains("-----BEGIN PRIVATE KEY-----")
|| pem.contains("-----BEGIN RSA PRIVATE KEY-----")
|| pem.contains("-----BEGIN DSA PRIVATE KEY-----"))) {
throw new IllegalArgumentException("Not an unencrypted PEM private key (encrypted/cert/other format?)");
} Type guard
boolean isUnencryptedPemPrivateKey(InputStream is) throws IOException {
String s = readAll(is);
return s.contains("-----BEGIN PRIVATE KEY-----")
|| s.contains("-----BEGIN RSA PRIVATE KEY-----")
|| s.contains("-----BEGIN DSA PRIVATE KEY-----");
} Try / catch
// try
try {
PrivateKey pk = KeyStoreUtils.generatePrivateKey(keyIs);
} catch (IOException e) {
if (e.getMessage().contains("unencrypted private key")) {
// wrong or encrypted input: ask user for a decrypted PEM key file
showKeyFormatHelpDialog();
}
} Prevention
- Decrypt encrypted PEM keys with `openssl pkcs8 -topk8 -nocrypt` before importing.
- Select the private key file, not the certificate, when importing.
- Convert PuTTY (.ppk) or OpenSSH-format keys to PEM beforehand.
- Inspect the file's BEGIN/END header to confirm the expected format before calling.
When it happens
Trigger: Calling generatePrivateKey with a stream that is not an unencrypted PKCS#8/PKCS#1 PEM key: encrypted PEM ("ENCRYPTED PRIVATE KEY", or password prompt lines), certificates, wrong file, or binary key where headers don't match expected patterns.
Common situations: User selected the certificate (.crt/.pem) instead of the key; key is openssl-encrypted and requires a passphrase; file exported in a format (e.g. PuTTY .ppk or XML) the parser doesn't recognize.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Couldn't find any suitable algorithm
- Alias exists.
- Alias app_manager does not exist in KeyStore.
- Checksums for master key did not match.
- Could not backup KeyStore item.
AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12).
Data as JSON: /api/errors/a7b5fce1a23350f9.
Report an issue: GitHub.
Appendix: source
Thrown at app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/KeyStoreUtils.java:239
} else {
switch (line) {
case RSA_BEGIN_HEADER:
readingKey = true;
rsaFormat = true;
break;
case DSA_BEGIN_HEADER:
readingKey = true;
dsaFormat = true;
break;
case PKCS8_BEGIN_HEADER:
readingKey = true;
pkcs8Format = true;
break;
}
}
}
if (base64EncodedKey.length() == 0) {
throw new IOException("Stream does not contain an unencrypted private key.");
}
BASE64Decoder decoder = new BASE64Decoder();
byte[] bytes = decoder.decodeBuffer(base64EncodedKey.toString());
KeyFactory kf;
KeySpec spec;
if (pkcs8Format) {
kf = KeyFactory.getInstance("RSA");
spec = new PKCS8EncodedKeySpec(bytes);
} else if (rsaFormat) {
// PKCS#1 format
kf = KeyFactory.getInstance("RSA");
List<BigInteger> rsaIntegers = new ArrayList<>();
ASN1Parse(bytes, rsaIntegers);
if (rsaIntegers.size() < 8) {
throw new InvalidKeyException("Stream does not appear to be a properly formatted RSA key.");
}View on GitHub (pinned to 0152f468fc)