shwenzhang/AndResGuard · error · InvalidKeySpecException
Failed to parse encrypted private key blob
Error message
Failed to parse encrypted private key blob <keyFile>
What it means
This InvalidKeySpecException is thrown when readEncryptedPkcs8PrivateKey fails to parse the key blob as an encrypted PKCS#8 structure AND a key password was actually specified (keyPasswordSpec != null). The library interprets the parse failure as: you gave a password, so the blob should be encrypted, but it is not valid encrypted-PKCS#8 data (or the password is wrong).
Solutions
- Omit --key-pass if the key file is unencrypted, letting the library parse it as plain PKCS#8.
- Convert the key to PKCS#8: 'openssl pkcs8 -topk8 -in key.pem -out key.pk8' (add -v2 des3 for encryption).
- Verify the file is a valid PKCS#8 blob: 'openssl asn1parse -in keyfile' and check the header (BEGIN PRIVATE KEY / BEGIN ENCRYPTED PRIVATE KEY, not BEGIN RSA PRIVATE KEY).
- Re-download/regenerate the key file if it is truncated or corrupted, and confirm the password is correct.
Example fix
// before: PEM RSA key + password flag apksigner sign --key rsa_key.pem --key-pass pass:secret --cert cert.pem ... // after: convert to PKCS#8 first, then sign without unneeded password openssl pkcs8 -topk8 -nocrypt -in rsa_key.pem -out key.pk8 apksigner sign --key key.pk8 --cert cert.pem ...
Defensive patterns
Strategy: validation
Validate before calling
// Verify key format before signing
String head = new String(java.nio.file.Files.readAllBytes(Paths.get(keyPath)), 0, 40);
boolean isPem = head.contains("PRIVATE KEY");
boolean isPkcs1 = head.contains("BEGIN RSA PRIVATE KEY");
if (isPkcs1) throw new IllegalArgumentException("PKCS#1 key detected; convert with: openssl pkcs8 -topk8 -in key.pem -out key.pk8");
if (keyPassSpecified && head.contains("BEGIN PRIVATE KEY") && !head.contains("BEGIN ENCRYPTED")) {
throw new IllegalArgumentException("Key is unencrypted; remove --key-pass");
} Try / catch
try {
signerParams.loadPrivateKeyAndCerts(passwordRetriever);
} catch (InvalidKeySpecException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Failed to parse encrypted private key blob")) {
// convert to PKCS#8 or drop --key-pass, then retry
} throw e;
} Prevention
- Standardize on PKCS#8 keys (openssl pkcs8 -topk8) for file-based signing.
- Only supply --key-pass when the key file is genuinely encrypted (BEGIN ENCRYPTED PRIVATE KEY).
- Validate key files with 'openssl asn1parse' or 'openssl pkey -check' before running CI signing jobs.
When it happens
Trigger: loadPrivateKeyAndCertsFromFiles reads --key, the blob does not parse as encrypted PKCS#8 (EncryptionAlgorithmException / ASN.1 failure), and --key-pass was supplied, so the fallback to unencrypted PKCS#8 is refused.
Common situations: Passing a PEM private key (Base64, unencrypted) while also supplying --key-pass, so it cannot be an 'encrypted blob'; feeding a PKCS#1 ('RSA PRIVATE KEY') file instead of PKCS#8; truncated or corrupted key files; wrong password for a genuinely encrypted key.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Not an RSA, EC, or DSA private key
- Failed to load PKCS #8 encoded private key from
- No passwords
- Failed to obtain key with alias
- entry " " does not contain certificates
AI-assisted analysis of shwenzhang/AndResGuard@e4df245d82 (2026-09-12).
Data as JSON: /api/errors/4c1d02ee4d677d47.
Report an issue: GitHub.
Appendix: source
Thrown at AndResGuard-core/src/main/java/apksigner/ApkSignerTool.java:802
byte[] privateKeyBlob = readFully(new File(keyFile));
PKCS8EncodedKeySpec keySpec;
// Potentially encrypted key blob
try {
EncryptedPrivateKeyInfo encryptedPrivateKeyInfo = new EncryptedPrivateKeyInfo(privateKeyBlob);
// The blob is indeed an encrypted private key blob
String passwordSpec = (keyPasswordSpec != null) ? keyPasswordSpec : PasswordRetriever.SPEC_STDIN;
List<char[]> keyPasswords = passwordRetriver.getPasswords(passwordSpec, "Private key password for " + name);
keySpec = decryptPkcs8EncodedKey(encryptedPrivateKeyInfo, keyPasswords);
} catch (IOException e) {
// The blob is not an encrypted private key blob
if (keyPasswordSpec == null) {
// Given that no password was specified, assume the blob is an unencrypted
// private key blob
keySpec = new PKCS8EncodedKeySpec(privateKeyBlob);
} else {
throw new InvalidKeySpecException("Failed to parse encrypted private key blob " + keyFile, e);
}
}
// Load the private key from its PKCS #8 encoded form.
try {
privateKey = loadPkcs8EncodedPrivateKey(keySpec);
} catch (InvalidKeySpecException e) {
throw new InvalidKeySpecException("Failed to load PKCS #8 encoded private key from " + keyFile, e);
}
// Load certificates
Collection<? extends Certificate> certs;
try (FileInputStream in = new FileInputStream(certFile)) {
certs = CertificateFactory.getInstance("X.509").generateCertificates(in);
}
List<X509Certificate> certList = new ArrayList<>(certs.size());
for (Certificate cert : certs) {
certList.add((X509Certificate) cert);View on GitHub (pinned to e4df245d82)