Mensaje de error
algid parse error, not a sequence
También se muestra 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
En JDK 8–11, el propio texto de la excepción dice «InvalidKeyException: IOException : algid parse error, not a sequence». Los JDK más recientes (comprobado en 21 y 25) dicen «Unable to decode key» y conservan «algid parse error, not a sequence» en la línea `Caused by:` de la traza de pila.
Java (JDK) — KeyFactory.generatePrivate / generatePublic with PKCS8EncodedKeySpec or X509EncodedKeySpec
Qué significa
Los bytes envueltos en un `PKCS8EncodedKeySpec` o un `X509EncodedKeySpec` no empiezan con la estructura que promete esa especificación: ambos formatos comienzan con una SEQUENCE que contiene un AlgorithmIdentifier («algid»), y el JDK encontró ahí otra cosa. El caso clásico es una clave RSA PKCS#1 (`-----BEGIN RSA PRIVATE KEY-----`), cuyo primer elemento es un INTEGER. El JDK solo lee PKCS#8 para las claves privadas y X.509 SubjectPublicKeyInfo para las claves públicas.
Por qué ocurre
Una clave PKCS#1 («BEGIN RSA PRIVATE KEY»)
frecuente`genrsa` de OpenSSL 1.x, muchos paneles de hosting y herramientas más antiguas escriben PKCS#1. Su DER es la secuencia RSAPrivateKey sin el identificador de algoritmo que PKCS#8 añade, así que el JDK no encuentra el algid.
Especificaciones pública y privada intercambiadas
frecuenteUna clave privada pasada a `X509EncodedKeySpec`, o una clave pública a `PKCS8EncodedKeySpec`. Las estructuras difieren justo después de la SEQUENCE exterior.
No son los bytes DER de la clave
ocasionalTexto PEM pasado como bytes, base64 decodificado dos veces o una clave de un almacén de claves exportada en otro formato. Estos casos suelen fallar con otro `Caused by` («extra data at the end», «DerInputStream.getLength()»), pero el mensaje del algid aparece cuando los primeros bytes resultan analizables por casualidad.
Un certificado en lugar de una clave
ocasionalEl contenido de `-----BEGIN CERTIFICATE-----` es un certificado X.509, no un SubjectPublicKeyInfo. Cárgalo con `CertificateFactory` y llama a `getPublicKey()`.
Cómo solucionarlo
- 1.
Convertir la clave a PKCS#8 / SPKI una sola vez
Un solo comando de OpenSSL convierte las claves PKCS#1 a los formatos que el JDK lee de forma nativa.
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.
Quitar los delimitadores y comprobar la etiqueta
Decodifica solo el cuerpo en base64 y rechaza con un mensaje claro las etiquetas PEM que el JDK no puede leer, en lugar de dejar que salte un error de análisis.
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.
O leer cualquier variante de PEM con Bouncy Castle
`PEMParser` entiende PKCS#1, PKCS#8, SEC 1 y PEM cifrado, y `JcaPEMKeyConverter` convierte el resultado en claves 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); }
Errores 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