Сообщение об ошибке
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`, начинаются не с той структуры, которую обещает эта спецификация: оба формата начинаются с SEQUENCE, внутри которого лежит AlgorithmIdentifier («algid»), а JDK нашёл на этом месте что-то другое. Классический случай — ключ RSA в формате PKCS#1 (`-----BEGIN RSA PRIVATE KEY-----`), первый элемент которого — INTEGER. JDK читает закрытые ключи только в формате PKCS#8, а открытые ключи — только в формате X.509 SubjectPublicKeyInfo.
Почему это происходит
Ключ в формате PKCS#1 («BEGIN RSA PRIVATE KEY»)
часто`genrsa` из OpenSSL 1.x, многие панели хостинга и более старые инструменты записывают ключи в PKCS#1. DER такого ключа — это последовательность RSAPrivateKey без идентификатора алгоритма, добавляемого в PKCS#8, поэтому JDK не находит algid.
Перепутаны спецификации для открытого и закрытого ключа
частоЗакрытый ключ передан в `X509EncodedKeySpec` или открытый ключ — в `PKCS8EncodedKeySpec`. Структуры различаются сразу после внешнего SEQUENCE.
Переданы не байты ключа в DER
иногдаТекст PEM, переданный как байты, дважды декодированный base64 или ключ из хранилища ключей, экспортированный в другом формате. Обычно в этих случаях `Caused by` другой («extra data at the end», «DerInputStream.getLength()»), но сообщение про algid появляется, если первые байты случайно удаётся разобрать.
Сертификат вместо ключа
иногдаСодержимое `-----BEGIN CERTIFICATE-----` — это сертификат X.509, а не SubjectPublicKeyInfo. Загрузите его через `CertificateFactory` и вызовите `getPublicKey()`.
Как исправить
- 1.
Один раз преобразуйте ключ в PKCS#8 / SPKI
Одна команда OpenSSL преобразует ключи 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.
Уберите обрамление и проверьте метку
Декодируйте только тело в base64, а метки PEM, которые JDK не умеет читать, отклоняйте с понятным сообщением вместо ошибки разбора.
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.
Или читайте PEM любого вида с помощью Bouncy Castle
`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); }
Связанные ошибки
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