Aller au contenu
ecdsa.com
Java (JDK)Java

Message d’erreur

algid parse error, not a sequence

Également affiché sous la forme

  • 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

Sur les JDK 8 à 11, le texte de l’exception lui-même est « InvalidKeyException: IOException : algid parse error, not a sequence ». Les JDK plus récents (vérifié sur 21 et 25) indiquent « Unable to decode key » et conservent « algid parse error, not a sequence » dans la ligne `Caused by:` de la pile d’appels.

Java (JDK) — KeyFactory.generatePrivate / generatePublic with PKCS8EncodedKeySpec or X509EncodedKeySpec

Ce que cela signifie

Les octets que vous avez placés dans un `PKCS8EncodedKeySpec` ou un `X509EncodedKeySpec` ne commencent pas par la structure promise par cette spec : les deux formats commencent par une SEQUENCE contenant un AlgorithmIdentifier (« algid »), et le JDK a trouvé autre chose à cet endroit. Le cas classique est une clé RSA PKCS#1 (`-----BEGIN RSA PRIVATE KEY-----`), dont le premier élément est un INTEGER. Le JDK ne lit que PKCS#8 pour les clés privées et X.509 SubjectPublicKeyInfo pour les clés publiques.

Pourquoi cela se produit

Comment corriger l’erreur

  1. 1.

    Convertir la clé en PKCS#8 / SPKI une fois pour toutes

    Une seule commande OpenSSL convertit les clés PKCS#1 aux formats que le JDK lit nativement.

    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. 2.

    Retirer l’armure et vérifier l’étiquette

    Ne décodez que le corps base64, et rejetez les étiquettes PEM que le JDK ne sait pas lire avec un message clair plutôt qu’avec une erreur d’analyse.

    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. 3.

    Ou lire toutes les variantes de PEM avec Bouncy Castle

    `PEMParser` comprend PKCS#1, PKCS#8, SEC 1 et le PEM chiffré, et `JcaPEMKeyConverter` transforme le résultat en clés 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);
    }

Erreurs associées

Parcourir toute la base de données des erreurs de signature