Skip to content
Bloga Dönün
Güvenlik

RS256 özel anahtar biçim hatası: tek mesaj, yedi neden

Node yanlış kapsayıcı, girintili başlık veya genel anahtarda aynı DECODER hatasını verir. Test edilmiş PKCS#1/PKCS#8 çözümleri ve çevrimiçi anahtar oluşturucu.

13 dakika okuma

RS256 özel anahtar biçim hatası: tek mesaj, yedi neden

Bir RS256 özel anahtar biçim hatası kendi nedenini neredeyse hiçbir zaman söylemez. Node v25.8.2 üzerinde, aşağıdaki hataların her biri birebir aynı satırı üretir:

code:    ERR_OSSL_UNSUPPORTED
message: error:1E08010C:DECODER routines::unsupported

Birbiriyle ilgisiz beş şey bunu tetikler: PEM anahtarı beklenen yerde duran bir OpenSSH kapsayıcısı, girintili bir -----BEGIN satırı, imzalayıcıya verilmiş bir genel anahtar, kimsenin kaçışını çözmediği birebir \n dizileri ve satır sonları yolda silinmiş bir dosya. 2. bölümdeki test edilmiş liste yediye çıkıyor. Her seferinde aynı satır. Hata metnini arattığınızda kendinizi başka birinin, başka bir nedenle açtığı bir konu başlığında bulmanızın sebebi de bu.

Önce sorunu ikiye bölün:

İlk durum için otuz saniyelik ön eleme:

openssl rsa -in key.pem -noout -text | head -1

Bu komut hata verirse sorun dosyadadır ve 3–6. bölümler onu bulur. Başarılı olursa OpenSSL kapsayıcıyı anlamış demektir; sorununuz kütüphanede ya da kütüphaneye verdiğiniz şeydedir, yani 4. ve 7. bölümlerde.

Aşağıdaki her şey 2026-08-11 tarihinde OpenSSL 3.6.2 7 Apr 2026, Node v25.8.2, Go go1.26.1 darwin/arm64 ve Java 1.8.0_162 üzerinde ölçüldü. Bir iddia çalıştırmaya değil kaynak kodu okumaya dayanıyorsa, metin bunu açıkça söylüyor.

1. Önce hangi arıza türüyle karşı karşıya olduğunuzu belirleyin

Ayrım çizgisi tek bir soruda: ortada hiç anahtar nesnesi oluştu mu?

Ayrıştırma anındaki arızalar, herhangi bir kriptografi çalışmadan önce olur. Kütüphane PEM’inizi okur, onu bir anahtara dönüştüremez ve hata fırlatır. Hiçbir şey imzalanmamış, hiçbir şey doğrulanmamıştır; hata ayıkladığınız token zaten hiç üretilmemiştir. Doğrulama anındaki arızalar bunun tam tersidir: anahtar sorunsuz yüklenmiş, bir imza hesaplanmış ve tutmamıştır. Bunlar imzalayan ile doğrulayan arasındaki bayt düzeyi uyuşmazlıklardan doğar; invalid signature rehberi onları ele alıyor.

İkisini ayırmak için yığın izine tek bir bakış yeter. Ayrıştırma anındaki bir arıza bir çözücüden, bir anahtar spesifikasyonundan ya da bir ASN.1 yapısından söz eder. Doğrulama anındaki bir arıza imzadan söz eder.

Reddedilen bir özel anahtar üç ekosistemde şöyle görünür:

Çalışma zamanıTest edilen sürümAnahtar yüklenmediğinde çıkan mesaj
Node cryptov25.8.2error:1E08010C:DECODER routines::unsupported
Go crypto/x509go1.26.1 darwin/arm64x509: failed to parse private key (use ParsePKCS1PrivateKey instead for this key format)
Java PKCS8EncodedKeySpec1.8.0_162InvalidKeySpecException: java.security.InvalidKeyException: IOException : algid parse error, not a sequence

Üçünün ne kadar işe yaradığına dikkat edin. Go, bunun yerine hangi işlevi çağırmanız gerektiğini adıyla söyler. Java “algid” ve “sequence” der, bunun “anahtarınız yanlış kapsayıcıda” anlamına geldiğini çıkarmayı size bırakır. Node ise işinize yarayacak hiçbir şey söylemez.

Peşinde olduğunuz token’ın gerçekten RS256 olduğundan emin değilseniz, devam etmeden önce onu JWT Çöz Online aracına yapıştırın ve başlıktaki alg alanını okuyun. HS256 yazan bir başlık, anahtar çiftine değil paylaşılan bir gizli anahtara ihtiyacınız olduğu anlamına gelir; bu yazıdaki her belirti sizi yanlış yöne çeker.

2. Hata metninden kök nedene: RS256 özel anahtar biçim hatası arama tablosu

Kendi metninizi birebir bulun. Sağdaki sütun bundan sonra nereye bakacağınızı söylüyor.

Hata metniNereden geliyorGerçekte ne anlama geliyor
error:1E08010C:DECODER routines::unsupportedNode v25.8.2Aşağıda sıralanan yedi olası neden
error:07880109:common libcrypto routines::interrupted or cancelledNode v25.8.2Anahtar şifreli ve siz parola vermediniz
x509: failed to parse private key (use ParsePKCS8PrivateKey instead for this key format)Go 1.26.1Bir PKCS#8 dosyasında ParsePKCS1PrivateKey çağırdınız
x509: failed to parse private key (use ParsePKCS1PrivateKey instead for this key format)Go 1.26.1Bir PKCS#1 dosyasında ParsePKCS8PrivateKey çağırdınız
asn1: structure error: tags don't match (16 vs {class:0 tag:6 ...})Go 1.26.1İlk PEM bloğu anahtar değil, EC PARAMETERS
algid parse error, not a sequenceJava 1.8.0_162PKCS8EncodedKeySpec sınıfına PKCS#1 verilmiş
secretOrPrivateKey must have a valuejsonwebtoken, kaynak koddaAnahtar argümanı falsy ve alg değeri none değil
secretOrPrivateKey is not valid key materialjsonwebtoken, kaynak koddaNe özel anahtar ne de gizli anahtar oluşturulabildi
secretOrPrivateKey must be a symmetric key when using ${header.alg}jsonwebtoken, kaynak koddaalg değeri HS ile başlıyor ama anahtar bir secret değil
secretOrPrivateKey must be an asymmetric key when using ${header.alg}jsonwebtoken, kaynak koddaalg değeri RS, PS veya ES ile eşleşiyor ama anahtar özel anahtar değil
secretOrPrivateKey has a minimum key size of 2048 bits for ${header.alg}jsonwebtoken, kaynak koddaRS veya PS ile 2048 bitin altında bir anahtar ve allowInsecureKeySizes kapalı

Beş secretOrPrivateKey metni, jsonwebtoken’ın master dalındaki sign.js dosyasından okundu, yerelde çalıştırılmadı. Bu yüzden tetikleme koşullarını bu makinede yeniden üretilmiş sonuçlar olarak değil, kaynağın söylediği şey olarak değerlendirin. ${header.alg} kısmı o kaynaktaki bir şablon yer tutucusu; çalışma zamanında orada kendi algoritma adınızı görürsünüz. Süslü parantezli metni birebir arattığınızda hiçbir şey bulamamanızın nedeni de bu.

DECODER routines::unsupported üretmenin yedi yolu

Yedisi de Node v25.8.2 üzerinde crypto.createPrivateKey() çağrısına karşı yeniden üretildi ve yedisi de aynı kodu ve aynı mesajı verdi:

  1. Bir OpenSSH kapsayıcısı. Dosya -----BEGIN OPENSSH PRIVATE KEY----- ile başlar ve aslında bir PEM anahtar yapısı değildir.
  2. Girintili bir -----BEGIN satırı ya da girintili bir -----END satırı. Gövde satırları bunun dışında; kesin sınır 5. bölümde.
  3. PEM’in tamamından önce gelen boşluk. Baştaki boş bir satır sorun değil, baştaki bir boşluk karakteri sorun.
  4. Satır sonlarının tümüyle silinmesi; başlık, base64 ve alt bilgi tek satırda birbirine yapışır.
  5. Özel anahtar beklenen yerde bir genel anahtar.
  6. Kaçışı çözülmemiş, birebir ters bölü-n dizileri; tek satırlık bir ortam değişkeni tam olarak buna dönüşür.
  7. Tire sayısı yanlış olan bir ayraç ya da küçük harfle yazılmış begin/end.

Bunların ikisi kapsayıcı sorunu, dördü metin bozulması sorunu, biri de düpedüz karıştırma. Mesaj hangisi olduğunu söyleyemediği için en hızlı yol tek tek elemek.

Node’un kabul ettikleri: aramayı asıl daraltan liste

Ters liste daha işe yarar, çünkü üzerindeki her madde hemen elenebilecek bir varsayım. Node v25.8.2 üzerinde crypto.createPrivateKey() aşağıdakilerin hepsini itirazsız kabul etti:

  • PKCS#1 ve PKCS#8 özel anahtarlar
  • EC SEC1 özel anahtarlar
  • CRLF satır sonları
  • Sondaki satır sonunun eksik olması
  • Tek satıra sığdırılmış, katlanmamış base64 gövdesi
  • Girintili gövde satırları
  • PEM’den önce gelen boş bir satır
  • UTF-8 BOM, hem '' + pem biçiminde hem de 0xEF 0xBB 0xBF ile başlayan bir Buffer olarak
  • PKCS#8 gövdesinin etrafına sarılmış bir PKCS#1 başlığı

Sonuncusunun nedeni şu: çözücü, base64’ün içindeki DER yapısını okur ve dıştaki etiketi yok sayar; bu yüzden PKCS#8 içeriğinin üzerinde BEGIN RSA PRIVATE KEY yazan bir dosya yine de yüklenir. 3. bölüm için de bir uyarı: başlık satırı bir ipucudur, garanti değil.

3. PEM başlık satırı: elinizde aslında hangi kapsayıcı var

Her PEM kendini birinci satırda tanıtır. Aşağıdakiler OpenSSL 3.6.2’nin yazdığı başlık değerleri:

İçerikİlk satır
PKCS#8 özel anahtar-----BEGIN PRIVATE KEY-----
PKCS#1 özel anahtar-----BEGIN RSA PRIVATE KEY-----
Şifreli özel anahtar-----BEGIN ENCRYPTED PRIVATE KEY-----
OpenSSH özel anahtar-----BEGIN OPENSSH PRIVATE KEY-----
EC SEC1 özel anahtar-----BEGIN EC PARAMETERS-----, ardından ikinci bir blok -----BEGIN EC PRIVATE KEY-----
SPKI genel anahtar-----BEGIN PUBLIC KEY-----
PKCS#1 genel anahtar-----BEGIN RSA PUBLIC KEY-----
Ed25519 özel anahtar-----BEGIN PRIVATE KEY-----, ve dosyanın tamamı üç satır

Yani head -1 key.pem her incelemenin ilk sorusunu yanıtlar. Tablonun üç satırı biraz açıklama istiyor.

ENCRYPTED PRIVATE KEY bir biçim hatası değildir. Vermeyi unuttuğunuz bir paroladır. Node bunu diğer her şeyden farklı bildirir (ERR_OSSL_CRYPTO_INTERRUPTED_OR_CANCELLED ve error:07880109:common libcrypto routines::interrupted or cancelled), çünkü kütüphane parola istemiş ve karşılığında hiçbir şey alamamıştır. Bu mesajı DECODER mesajıyla karıştırmayın; ikisinin birbiriyle ilgisi yok.

OPENSSH PRIVATE KEY ise bambaşka bir dünya. OpenSSH kendi kapsayıcısını yazar; PEM görünümlü ayraçların arasında dursa da bu ne PKCS#1’dir ne de PKCS#8. Node onu doğrudan reddeder; Go’nun crypto/x509 ayrıştırıcıları ve JDK’nın PKCS8EncodedKeySpec sınıfı da öyle. JWT imzalama anahtarınız ssh-keygen çıktısıysa hatanız budur.

EC SEC1 dosyaları iki blok taşır. openssl ecparam -genkey önce bir EC PARAMETERS bloğu, sonra özel anahtarı yazar. Yalnızca ilk PEM bloğunu okuyan her şey parametreleri alır ve ikisinden de söz etmeyen bir biçimde başarısız olur. Bu arızanın Go’daki hâli 4. bölümde.

Başlık yalnızca bir etiket olduğu için ters yöndeki denetim de önemli: başlığı bir şey, DER’i başka bir şey söyleyen bir dosya DER’e göre ayrıştırılır. head -1 okumak, doğrudan OpenSSL’den çıkmış dosyalar için güvenilirdir; bir insanın, bir wiki sayfasının ya da karakter dizisi değiştiren bir betiğin elinden geçmiş dosyalar için güvenilir değildir.

4. Hangi kütüphane hangisini kabul ediyor: üç ekosistemde PKCS#1 ve PKCS#8

Ekipler arası biçim tartışmalarının çoğunu açıklayan matris bu. Her satır, bu yazının başında listelenen sürümler üzerinde ölçüldü.

KütüphanePKCS#1PKCS#8OpenSSHHata kendini açıklıyor mu?
Node cryptoEvetEvetHayırHayır. Çok sayıda neden, tek bir DECODER routines::unsupported
Go crypto/x509Evet, ayrı bir işlevEvet, ayrı bir işlevHayırEvet. Geçmeniz gereken işlevin adını verir
Java standart kütüphanesiHayırEvetHayırHayır. algid parse error, not a sequence düpedüz yanıltıcı

Sütunları okuyun, tartışmalar kendiliğinden biter. Tek bir anahtar dosyasını paylaşan bir Node servisi ile bir Java servisi, anahtar PKCS#1 olana kadar sorunsuz çalışır; o noktada Node imzalamayı sürdürür, Java ise ASN.1 dizilerinden söz eden bir mesaj fırlatır. Kimse anahtardan şüphelenmez; sonuçta o anahtar öbür serviste üretimde gözle görülür biçimde çalışıyor.

Node. Yapılandırılacak bir şey yok. Kapsayıcı PKCS#1 ya da PKCS#8 ise createPrivateKey() onu kabul eder. Hata fırlattığında sorun kapsayıcıda olmadığı için zamanınızı 2. bölümdeki yedi nedene ayırın.

const fs = require('node:fs');
const { createPrivateKey } = require('node:crypto');

try {
  const key = createPrivateKey(fs.readFileSync('key.pem'));
  console.log('parsed:', key.asymmetricKeyType);
} catch (err) {
  console.log(err.code, '/', err.message);
}

Bunu elle oluşturduğunuz bir kopyaya değil, uygulamanızın gerçekten yüklediği dosyaya karşı çalıştırın; catch dalı size 2. bölümde arayabileceğiniz kod ve mesaj çiftini basar.

Go. İki kapsayıcı, iki işlev; yanlış olanı çağırmak Go tarafındaki en yaygın arıza. Mesaj hangisini kullanmanız gerektiğini söylediği için düzeltme mekanik. İkisini sırayla denemek kararı ortadan kaldırır:

priv, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
	rsaKey, err2 := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err2 != nil {
		log.Fatalf("neither container parsed: %v / %v", err, err2)
	}
	priv = rsaKey
}

Ne var ki EC tuzağının bundan önce ele alınması gerekiyor. openssl ecparam -genkey ile üretilmiş bir dosyada pem.Decode, Type alanı EC PARAMETERS olan bir blok döndürür ve üç ayrıştırma işlevi de bu blokta şu hatayla başarısız olur:

asn1: structure error: tags don't match (16 vs {class:0 tag:6 ...})

Bu mesaj PEM bloklarından hiç söz etmez; bu yüzden ilk tepki anahtardan şüphelenmek olur. Bunun yerine parametre bloğunu atlayın:

block, rest := pem.Decode(pemBytes)
if block == nil {
	log.Fatal("no PEM block found")
}
if block.Type == "EC PARAMETERS" {
	block, _ = pem.Decode(rest)
}

Ya da dosyayı yazan ecparam komutuna -noout ekleyerek fazladan bloğun hiç üretilmemesini sağlayın.

Java. Standart kütüphane PKCS#8 okur, başka hiçbir şey okumaz. Java 1.8.0_162 üzerinde PKCS8EncodedKeySpec sınıfına bir PKCS#1 anahtarı verirseniz şunu alırsınız:

InvalidKeySpecException: java.security.InvalidKeyException: IOException : algid parse error, not a sequence

“algid”, algoritma tanımlayıcısı: PKCS#8’in eklediği, PKCS#1’de ise hiç bulunmayan alan. Ayrıştırıcı onu aradı, bir RSA modülünün başlangıcını buldu ve pes etti. Mesaj aynı ölçüde hem doğru hem işe yaramaz. Dosyayı dönüştürün, hata kaybolur:

openssl pkcs8 -topk8 -nocrypt -in pkcs1.pem -out pkcs8.pem

Dosya PKCS#8 olduktan sonra çalışan Java 8 yükleme yolu, düzeltmeyi doğrularken bir teste doğrudan gömecek kadar kısa:

String pem = new String(Files.readAllBytes(Paths.get("key.pem")), StandardCharsets.UTF_8)
        .replace("-----BEGIN PRIVATE KEY-----", "")
        .replace("-----END PRIVATE KEY-----", "")
        .replaceAll("\\s+", "");
byte[] der = Base64.getDecoder().decode(pem);
PrivateKey key = KeyFactory.getInstance("RSA")
        .generatePrivate(new PKCS8EncodedKeySpec(der));

Dönüştürmenin alternatifi, PKCS#1’i gerçekten okuyabilen BouncyCastle’ı eklemek. Dönüştürme tek bir komut ve sıfır bağımlılık demek; bu yüzden yığınınızda o kütüphaneye zaten ihtiyaç duyan başka bir şey yoksa dönüştürün.

5. Göremediğiniz karakterler

Aşağıdaki şüphelilerin hepsi Node v25.8.2 üzerinde tek tek denendi; sonuçlardan biri yaygın tavsiyenin tam tersi çıktı.

Girinti: size söylenenin tam tersi

Sıkça tekrarlanan bir yönerge, bir PEM’in ayraçlar dışındaki her satırının sıfırıncı sütundan başlaması gerektiğini söyler. Node v25.8.2 üzerinde test edildiğinde durum tam tersi:

Dosyadaki değişiklikSonuç
Her satır girintiliBaşarısız
Yalnızca -----BEGIN satırı girintiliBaşarısız
Yalnızca -----END satırı girintiliBaşarısız
Yalnızca base64 gövde satırları girintiliKabul edildi
PEM’in tamamından önce bir boşluk karakteriBaşarısız
PEM’in tamamından önce boş bir satırKabul edildi

Yani kural şu: -----BEGIN ve -----END satırları sıfırıncı sütundan başlamalı, gövde satırlarının girintisi ise hiç fark etmez. İnsanlara girintileyebilecekleri söylenen tam da o iki satır işleri bozuyor; hizalamaları söylenen satırlar ise esnek olanlar.

Bunun önemi, özel anahtarların en baştan nasıl girintilendiğinden geliyor. Kimse bir PEM’i elle girintilemez. Bu, anahtar bir YAML bloğuna, bir Helm values dosyasına, bir Terraform heredoc’una ya da bir sınıf gövdesindeki üç tırnaklı Python karakter dizisine yapıştırıldığında olur. Bunların hepsi metnin tamamını, ayraçlar dâhil, aynı ölçüde girintiler; tablonun ilk satırı da tam olarak bu.

Tek satırlık ortam değişkeninden gelen birebir ters bölü-n

Bir PEM’de satır sonu vardır, bir ortam değişkeninde ise pratikte yoktur. Bu yüzden anahtarlar .env dosyalarına, \n iki karakter olarak yazılmış tek bir satır hâlinde iner. O dosyayı okuyan her ne ise kodunuza ters bölü içeren bir karakter dizisi verir ve ayrıştırıcı bir ayracın ardından çöp görür. Node tarafında bu, 2. bölümdeki 6. nedendir ve diğer her şeyle aynı DECODER routines::unsupported mesajını verir.

Kullanıldığı noktada geri alın:

const pem = process.env.PRIVATE_KEY.replace(/\\n/g, '\n');

Bunun etrafına iki koruma ekleyin. Birincisi: değiştirmeyi yalnızca karakter dizisi o iki karakterlik diziyi gerçekten içeriyorsa uygulayın; böylece farklı bir yükleyiciden geçmiş, gerçekten çok satırlı bir değere zaten dokunulmamış olur. İkincisi: platformunuz izin veriyorsa PEM’in tamamı için base64’ü tercih edin. Tek satır base64 saklayın, açılışta çözün; ortada kaçış diye bir soru kalmasın.

BOM: Node’da zararsız, başka yerlerde test edilmedi

Bayt sırası işareti (BOM), bazı Windows düzenleyicilerinin bir UTF-8 dosyasının başına yazdığı üç bayttır: EF BB BF. Anahtarı yüklemeden önce onu temizlemenizi söyleyen tavsiye yaygın. Node v25.8.2 üzerinde hiçbir fark yaratmadı: BOM ile başlayan bir PEM, hem karakter dizisi olarak hem de o üç baytla başlayan bir Buffer olarak sorunsuz ayrıştırıldı.

Bu sonucun kapsamını dikkatle çizin. Yalnızca Node v25.8.2 üzerinde ölçüldü. Java, Python ve diğer ayrıştırıcılar burada test edilmedi; bu yazıdaki hiçbir şey onların nasıl davrandığını söylemiyor. Bir Java servisinde hata ayıklıyorsanız BOM, elenmiş bir olasılık değil hâlâ açık bir soru olarak duruyor.

BOM başka şeyleri gerçekten bozuyor; anahtarla ilgili tavsiye de büyük olasılıkla bu çağrışımdan doğdu. BOM ile başlayan bir karakter dizisinde JSON.parse çağırmak gerçek ve iyi belgelenmiş bir arıza; UTF-8 BOM: JSON ayrıştırma ve CSV hatalarını çözün yazısı bunu ele alıyor. Dolayısıyla bir JSON yapılandırmasının içinde saklanan bir anahtar dosyası, daha kimse anahtara bakmadan çok önce patlayabilir.

Satır sonları, sondaki satır sonu ve katlama genişliği

Node v25.8.2’nin akladığı üç şüpheli daha:

  • CRLF satır sonları. Kabul edildi. Windows’tan geçmiş bir anahtar kendiliğinden bozulmuş sayılmaz.
  • Sondaki satır sonunun eksik olması. Kabul edildi. Bunun ayrıştırıcıya özgü olduğuna dikkat edin: bazı ayrıştırıcıların sondaki satır sonu olmayan bir PEM’i reddettiği söylenir, Node onlardan biri değil. Node kabul ediyor; diğer ayrıştırıcılar burada test edilmedi.
  • Katlanmamış gövde. Kabul edildi. Base64’ün 64 karakterde katlanması gerekmiyor.

Bir base64 gövdesini asıl bozan şey, kaybolan, araya giren ya da değişen bir karakter; bu da katlamadan farklı bir arıza. Satır sonunu boşluğa çeviren bir sohbet istemcisi ya da sondaki bir karakteri yiyen bir metin alanı, artık çözülemeyen bir gövde üretir. Metni fareyle sürüklemek yerine kopyala düğmesini kullanın.

6. OpenSSL 3.x varsayılanı siz farkında olmadan değiştirdi

OpenSSL 3.6.2 7 Apr 2026 üzerinde ölçüldü:

KomutYazdığı kapsayıcı
openssl genrsa -out k.pem 2048PKCS#8, başlık BEGIN PRIVATE KEY
openssl genrsa -traditional -out k.pem 2048PKCS#1
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048PKCS#8
openssl genpkey -algorithm ED25519PKCS#8
openssl pkcs8 -topk8 -nocrypt -in a.pem -out b.pemPKCS#1’i PKCS#8’e dönüştürür
openssl rsa -in b.pem -traditional -out a.pemPKCS#8’i PKCS#1’e dönüştürür

İlk iki satırı bir daha okuyun. Bu derlemede genrsa varsayılan olarak size PKCS#8 verir; BEGIN RSA PRIVATE KEY dosyasını üreten şey -traditional seçeneğidir. Pek çok rehber hâlâ genrsa komutunu PKCS#1’in, genpkey komutunu ise PKCS#8’in karşılığı diye anlatıyor; onları izlerseniz üretmediğiniz bir biçimi ürettiğinizden emin olarak yolunuza devam edersiniz.

Pratik sonucu göçlerde ortaya çıkar. Java kullanan bir ekip, daha eski bir OpenSSL çalıştıran bir meslektaşından çalışan bir anahtar alır, her şey yolundadır; altı ay sonra biri anahtarı yeni bir makinede yeniden üretir. Aynı komut, aynı belgeler, farklı kapsayıcı. JDK artık “tıpatıp aynı şekilde üretilmiş” bir anahtara algid parse error, not a sequence fırlatıyordur. Öyle üretilmemiştir.

Varsaymadan kontrol edin:

head -1 key.pem

Tek satırlık bir çıktı ve 3. bölümdeki tablo elinizde ne olduğunu söyler. Bunu herhangi bir dönüştürme komutu çalıştırmadan önce yapın; çünkü bir PKCS#8 dosyasını PKCS#8’e dönüştürmek, düzeltmeye benzeyen ama hiçbir şeyi düzeltmeyen boş bir işlem.

Bayrakları hiç düşünmek istemiyorsanız, Çevrimiçi RSA Anahtar Oluşturucu aynı anahtar çiftinden her iki kapsayıcıyı da bir düğmeyle verir; böylece tek bir anahtarın PKCS#1 ve PKCS#8 kopyalarını çıkarıp sizi reddeden kütüphaneye ikisini de ayrı ayrı deneyebilirsiniz.

7. Kusursuz bir anahtarı reddeden 2048 bit alt sınırı

Bir arıza biçim sorununa benzer ama değildir. jsonwebtoken kaynağında sign.js şunu fırlatır:

secretOrPrivateKey has a minimum key size of 2048 bits for ${header.alg}

Kaynak kod bunu, alg bir RS ya da PS algoritmasıysa, anahtar 2048 bitin altındaysa ve allowInsecureKeySizes ayarlanmamışsa yükseltir. Bu denetim kütüphanenin kendi denetimi, çalışma zamanının değil. Node v25.8.2 bir 1024 bitlik RSA anahtarını itirazsız ayrıştırır; modulusLength: 1024 her zamanki gibi bir anahtar nesnesi üretir. Yani anahtar yapısal olarak geçerlidir, kapsayıcı doğrudur, OpenSSL onu okur ve imzalama çağrısı yine de başarısız olur.

İşaret şu: bu mesaj bir sayı söylüyor. Biçim hataları çözücülerden, dizilerden ve anahtar malzemesinden söz eder; bu ise bitlerden söz ediyor. Mesajda bir boyut görüyorsanız PEM’e bakmayı bırakın.

1024 bitlik anahtarların kaynağı genellikle tarih: yıllar önce, o zamandan beri değişmiş bir varsayılana göre üretilmiş bir anahtar ya da küçük anahtarlar daha hızlı üretildiği için kimsenin dönüp bakmadığı bir test verisi. Doğru düzeltme, 2048 bit ve üzeri yeni bir çift üretmek. allowInsecureKeySizes seçeneği, bir nedeni olduğu için var olan bir denetimi kapatıyor.

Geriye kalan tek sorunun boyut olduğunu doğrulamak için aynı yükü, doğru boyutta yeni bir anahtarla JWT Oluşturucu ve Kodlayıcı aracında imzalayın. Orada bir token üretiliyor ama sizin kodunuzda üretilmiyorsa fark, claim’lerinizde ya da yapılandırmanızda değil anahtarınızdadır.

8. RS256 anahtar arızaları için yinelenebilir bir iş akışı

Bunları sırayla çalıştırın. Her adım ya nedeni bulur ya da bir dalı eler.

  1. Başlık satırını okuyun. head -1 key.pem çalıştırın, sonra çıktıyı 3. bölümdeki tabloyla eşleştirin. Bu size kapsayıcıyı, dosyanın şifreli olup olmadığını ve hiçbir zaman çalışmayacak bir OpenSSH anahtarı olup olmadığını söyler.

  2. OpenSSL’den ayrıştırmasını isteyin. RSA için openssl rsa -in key.pem -noout -text | head -1, herhangi bir algoritma için openssl pkey -in key.pem -noout. Başarı, baytların geçerli bir anahtar olduğu ve sorunun kütüphane tarafında bulunduğu anlamına gelir. Başarısızlık dosyanın hasarlı olduğu anlamına gelir; 4. adımdan devam edin.

  3. Matriste kendi kütüphanenizin satırına bakın. 4. bölüm. Elinizde PKCS#1 dosyasıyla Java varsa ya da Go’da yanlış ayrıştırma işlevini çağırıyorsanız işiniz burada biter.

  4. Görünmeyen karakterlere bakın. head -c 32 key.pem | xxd ilk baytları gösterir; tek bakışta bir BOM’u, baştaki bir boşluğu ve girintili bir ayracı yakalar. Ardından 5. bölüme göre -----BEGIN ve -----END satırlarının sıfırıncı sütundan başladığını doğrulayın.

  5. Sağlam olduğu bilinen bir anahtarla ikiye bölün. Çevrimiçi RSA Anahtar Oluşturucu ile yeni bir çift üretin, kodunuzu ona yöneltin ve hatanın ayakta kalıp kalmadığına bakın. Kalıyorsa hata anahtar dosyasında değil yükleme kodunuzdadır; orijinali ne kadar yeniden biçimlendirirseniz biçimlendirin bir işe yaramaz. Kayboluyorsa kabahat orijinal dosyada ve artık karşılaştırma yapabileceğiniz çalışan bir anahtarınız var.

  6. Algoritmayı ve boyutu en sona bırakın. Başlıkta RS256 yazdığını doğrulayın ve 7. bölüme göre anahtarın en az 2048 bit olduğunu doğrulayın.

  7. adım, insanların atladığı ve en çok zaman kazandıran adım. Temiz bir referans anahtar, belirsiz bir “anahtar çalışmıyor” ifadesini hangi tarafın bozuk olduğuna dair ikili bir cevaba çevirir.

SSS

BEGIN RSA PRIVATE KEY ile BEGIN PRIVATE KEY arasındaki fark nedir?

İkisi de aynı RSA anahtarının etrafındaki iki kapsayıcı. BEGIN RSA PRIVATE KEY PKCS#1’dir ve RSA sayılarını doğrudan tutar; BEGIN PRIVATE KEY PKCS#8’dir ve bir algoritma tanımlayıcısı ekler; ECDSA ve Ed25519 anahtarlarını da taşıyabilmesinin nedeni bu. Hangisine ihtiyacınız olduğu tümüyle kütüphaneye bağlı ve Çevrimiçi RSA Anahtar Oluşturucu ikisini de yazar.

openssl genrsa neden eğiticide gösterilenden farklı bir biçim üretiyor?

Çünkü varsayılan değişti. OpenSSL 3.6.2 üzerinde openssl genrsa -out k.pem 2048, BEGIN PRIVATE KEY başlıklı bir PKCS#8 yazar. Eski rehberlerin anlattığı geleneksel PKCS#1 düzenini almak için -traditional ekleyin. Kendi derlemenizin ne ürettiği konusunda herhangi bir eğiticiye güvenmek yerine çıktıda head -1 çalıştırın.

Java’daki algid parse error, not a sequence hatası nasıl düzeltilir?

Java 1.8.0_162 üzerindeki bu mesaj, PKCS8EncodedKeySpec sınıfına bir PKCS#1 anahtarı verdiğiniz anlamına gelir. Standart kütüphane PKCS#1’i hiç okumaz. openssl pkcs8 -topk8 -nocrypt -in pkcs1.pem -out pkcs8.pem ile bir kez dönüştürün ya da projede başka bir şeyin zaten ihtiyacı varsa BouncyCastle’ı ekleyin.

Bir özel anahtarın her satırı sıfırıncı sütundan başlamak zorunda mı?

Hayır ve yaygın tavsiye bunu ters biliyor. Node v25.8.2 üzerinde test edildiğinde, yalnızca base64 gövde satırlarını girintilemek sorunsuz ayrıştırılıyor; buna karşılık yalnızca -----BEGIN satırını ya da yalnızca -----END satırını girintilemek başarısız oluyor. PEM’den önce gelen boş bir satır kabul ediliyor, baştaki bir boşluk karakteri kabul edilmiyor.

Bir özel anahtar .env dosyasında nasıl saklanmalı?

Ya \n kaçışları içeren, tırnaklı tek bir satır olarak (yükleme sırasında .replace(/\\n/g, '\n') ile geri alarak) ya da açılışta çözdüğünüz tek satırlık base64 olarak. İkincisi daha güvenli, çünkü ortada bir yapılandırma yükleyicisinin yanlış anlayabileceği bir kaçış kuralı yok.

RS256 ile 1024 bitlik bir anahtar kullanabilir miyim?

Node v25.8.2 bir 1024 bitlik RSA anahtarını hatasız ayrıştırır, ama jsonwebtoken kaynağı onunla imzalamayı reddeder: allowInsecureKeySizes ayarlanmadıkça secretOrPrivateKey has a minimum key size of 2048 bits. Bunun yerine 2048 bitlik bir anahtar üretin. Mesajın bir bit sayısı söylemesi, onu bir biçim sorunundan ayırmanızı sağlayan işaret.

Özel anahtar dosyası verdiğim hâlde neden asimetrik anahtar istendiğini söyleyen bir RS256 özel anahtar biçim hatası alıyorum?

jsonwebtoken kaynağında secretOrPrivateKey must be an asymmetric key when using ${header.alg} mesajı, alg değeri RS, PS ya da ES olduğunda ve anahtar bir özel anahtar olmadığında tetiklenir. Genellikle değer, önceki bir yapılandırmadan kalmış HS256 tarzı bir gizli anahtar karakter dizisidir. Rastgele bir karakter dizisi HS256’ya ve JWT Gizli Anahtar Oluşturucu aracına aittir; RS256 gizli anahtar değil, anahtar çifti ister.

Sonuç

Bu hata sınıfı, birbirinden bağımsız birkaç aksilik üst üste bindiği için pahalıya mal oluyor. Node’da tek bir hata metni yedi nedeni birden kapsıyor. Gerçek cevap “yanlış kapsayıcı” iken Java’nın mesajı ASN.1’i işaret ediyor. Konuyla ilgili en çok tekrarlanan biçimlendirme tavsiyesi de tersine dönmüş durumda. Cevabı okuyarak bulamazsınız, eleyerek bulursunuz: başlık satırı, OpenSSL ayrıştırması, kütüphane matrisi, görünmeyen karakterler, sağlam olduğu bilinen anahtar.

Tekrarını iki alışkanlık önler. Her servisin hangi kapsayıcıyı gerektirdiğini, gizli anahtar deponuzda anahtarın yanına yazın; çünkü kısıt anahtarda değil kütüphanede duruyor. Bir de geliştirme ortamınızda yalnızca kontrol amacıyla, sağlam olduğu bilinen bir anahtar çifti bulundurun; böylece her anahtar arızasında sorulan ilk soru bir dakika içinde evet ya da hayır cevabını alsın.

Bu anahtarlar doğru yüklendikten sonra nasıl verilmesi, döndürülmesi ve kapsamlandırılması gerektiği gibi daha geniş bir soru için JWT Güvenliği: En İyi Uygulamalar, Saldırılar ve Savunma yazısına bakın.

Etiketler: jwt rsa pem openssl debugging security