Mensagem de erro
algid parse error, not a sequence
Também aparece como
- java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : algid parse error, not a sequence
- java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: Unable to decode key
Do JDK 8 ao 11, o próprio texto da exceção diz “InvalidKeyException: IOException : algid parse error, not a sequence”. JDKs mais novos (testados no 21 e no 25) dizem “Unable to decode key” e mantêm “algid parse error, not a sequence” na linha `Caused by:` do stack trace.
Java (JDK) — KeyFactory.generatePrivate / generatePublic with PKCS8EncodedKeySpec or X509EncodedKeySpec
O que significa
Os bytes que você encapsulou em um `PKCS8EncodedKeySpec` ou `X509EncodedKeySpec` não começam com a estrutura que essa spec promete: os dois formatos começam com uma SEQUENCE que contém um AlgorithmIdentifier (“algid”), e o JDK encontrou outra coisa ali. O caso clássico é uma chave RSA PKCS#1 (`-----BEGIN RSA PRIVATE KEY-----`), cujo primeiro elemento é um INTEGER. O JDK lê apenas PKCS#8 para chaves privadas e X.509 SubjectPublicKeyInfo para chaves públicas.
Por que acontece
Uma chave PKCS#1 (“BEGIN RSA PRIVATE KEY”)
comumO `genrsa` do OpenSSL 1.x, muitos painéis de hospedagem e ferramentas mais antigas gravam PKCS#1. O DER desse formato é a sequência RSAPrivateKey sem o identificador de algoritmo que o PKCS#8 acrescenta, por isso o JDK não encontra o algid.
Specs de chave pública e privada trocadas
comumUma chave privada passada para `X509EncodedKeySpec`, ou uma chave pública para `PKCS8EncodedKeySpec`. As estruturas divergem logo depois da SEQUENCE externa.
Não são os bytes DER da chave
ocasionalTexto PEM passado como bytes, base64 decodificado duas vezes ou uma chave de um keystore exportada em outro formato. Esses casos costumam falhar com outro `Caused by` (“extra data at the end”, “DerInputStream.getLength()”), mas a mensagem do algid aparece quando os primeiros bytes, por acaso, podem ser interpretados.
Um certificado em vez de uma chave
ocasionalO conteúdo de `-----BEGIN CERTIFICATE-----` é um certificado X.509, não um SubjectPublicKeyInfo. Carregue-o com `CertificateFactory` e chame `getPublicKey()`.
Como corrigir
- 1.
Converter a chave para PKCS#8 / SPKI uma única vez
Um único comando do OpenSSL transforma chaves PKCS#1 nos formatos que o JDK lê nativamente.
bash # "-----BEGIN RSA PRIVATE KEY-----" (PKCS#1) -> "-----BEGIN PRIVATE KEY-----" (PKCS#8) openssl pkcs8 -topk8 -nocrypt -in rsa-pkcs1.pem -out private-pkcs8.pem # "-----BEGIN RSA PUBLIC KEY-----" -> "-----BEGIN PUBLIC KEY-----" (X.509 SubjectPublicKeyInfo) openssl rsa -RSAPublicKey_in -in rsa-public-pkcs1.pem -pubout -out public.pem - 2.
Remover as linhas delimitadoras e conferir o rótulo
Decodifique apenas o corpo em base64 e rejeite com uma mensagem clara os rótulos PEM que o JDK não consegue ler, em vez de deixar aparecer um erro de análise.
java import java.nio.file.*; import java.security.*; import java.security.spec.*; import java.util.Base64; static PrivateKey loadPkcs8(Path path, String algorithm) throws Exception { String pem = Files.readString(path); if (!pem.contains("-----BEGIN PRIVATE KEY-----")) { throw new IllegalArgumentException("expected a PKCS#8 'BEGIN PRIVATE KEY' file"); } String body = pem.replaceAll("-----[A-Z ]+-----", "").replaceAll("\\s", ""); return KeyFactory.getInstance(algorithm).generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(body))); } static PublicKey loadSpki(Path path, String algorithm) throws Exception { String body = Files.readString(path).replaceAll("-----[A-Z ]+-----", "").replaceAll("\\s", ""); return KeyFactory.getInstance(algorithm).generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(body))); } - 3.
Ou ler qualquer variante de PEM com o Bouncy Castle
O `PEMParser` entende PKCS#1, PKCS#8, SEC 1 e PEM criptografado, e o `JcaPEMKeyConverter` transforma o resultado em chaves JCA.
java // With Bouncy Castle (bcpkix): reads PKCS#1, PKCS#8, SEC 1 and encrypted keys try (var parser = new org.bouncycastle.openssl.PEMParser(Files.newBufferedReader(path))) { Object object = parser.readObject(); var converter = new org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter(); PrivateKey key = object instanceof org.bouncycastle.openssl.PEMKeyPair pair ? converter.getKeyPair(pair).getPrivate() : converter.getPrivateKey((org.bouncycastle.asn1.pkcs.PrivateKeyInfo) object); }
Erros relacionados
x509: failed to parse private key (use ParsePKCS1PrivateKey instead for this ke…Go crypto/x509java.lang.IllegalArgumentException: Illegal base64 character 2dJava (JDK)System.Security.Cryptography.CryptographicException: ASN1 corrupted data..NET System.Security.CryptographyCould not deserialize key data. The data may be in an incorrect format, it may…Python cryptography