本文へスキップ
ecdsa.com
Java (JDK)Java

エラーメッセージ

algid parse error, not a sequence

別の表記

  • 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

JDK 8〜11 では、例外のテキスト自体が「InvalidKeyException: IOException : algid parse error, not a sequence」になります。新しい JDK(21 と 25 で確認)は「Unable to decode key」と表示し、「algid parse error, not a sequence」はスタックトレースの `Caused by:` 行に残ります。

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

このエラーの意味

`PKCS8EncodedKeySpec` または `X509EncodedKeySpec` で包んだバイト列が、そのクラスが前提とする構造で始まっていません。どちらの形式も AlgorithmIdentifier(「algid」)を含む SEQUENCE で始まりますが、JDK はその位置で別のものを見つけました。典型的なのは PKCS#1 の RSA 鍵(`-----BEGIN RSA PRIVATE KEY-----`)で、その最初の要素は INTEGER です。JDK が読み込めるのは、秘密鍵では PKCS#8、公開鍵では X.509 の SubjectPublicKeyInfo だけです。

発生する理由

修正方法

  1. 1.

    鍵を一度だけ PKCS#8 / SPKI に変換する

    OpenSSL のコマンド 1 つで、PKCS#1 の鍵を JDK が標準で読み込める形式に変換できます。

    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.

    アーマーを取り除き、ラベルを確認する

    base64 の本文だけをデコードし、JDK が読み込めない PEM ラベルは、解析エラーではなく明確なメッセージで拒否してください。

    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.

    または Bouncy Castle であらゆる種類の PEM を読み込む

    `PEMParser` は PKCS#1、PKCS#8、SEC 1、暗号化された PEM を解釈でき、`JcaPEMKeyConverter` がその結果を 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);
    }

関連するエラー

署名エラーデータベースをすべて見る