エラーメッセージ
System.Security.Cryptography.CryptographicException: ASN1 corrupted data.
別の表記
- ASN1 corrupted data.
- Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: ASN1 corrupted data.
Linux と macOS では型は `CryptographicException` です。Windows では同じテキストの `WindowsCryptographicException` として現れることがあります。内部例外は、たとえば「The provided data is tagged with 'Universal' class value '2', but it should have been 'Universal' class value '16'.」のようになります。
.NET System.Security.Cryptography — ImportSubjectPublicKeyInfo / ImportPkcs8PrivateKey / ImportRSAPrivateKey / ImportECPrivateKey
このエラーの意味
`Import…` メソッドのいずれかに渡したバイト列が、そのメソッドがデコードする ASN.1 構造になっていません。各メソッドは PKCS#8、PKCS#1、SEC 1、SubjectPublicKeyInfo のうちちょうど 1 つの構造だけを読み取ります。外側の DER が一致しないため、鍵自体は別の形式としてはまったく問題がなくても、.NET はデータが破損していると報告します。内部例外の `AsnContentException` に、タグの不一致が示されています。
発生する理由
PKCS#1 と PKCS#8(または SEC 1)の取り違え
よくある`RSA PRIVATE KEY` のバイト列を `ImportPkcs8PrivateKey` に渡した、または `PRIVATE KEY` のバイト列を `ImportRSAPrivateKey` に渡したケースです。2 つの構造は最初の要素が異なります(INTEGER と SEQUENCE)。
PEM テキストや base64 を DER として渡している
よくあるアーマー行を含むファイル全体に `Encoding.ASCII.GetBytes(pem)` や `Convert.FromBase64String` を適用しても、DER は得られません。
公開鍵用と秘密鍵用のメソッドを取り違えている
ときどき`ImportSubjectPublicKeyInfo` に秘密鍵を渡した、または鍵のインポートメソッドに(鍵ではなく)証明書を渡したケースです。
修正方法
- 1.
PEM ファイルには ImportFromPem を使う
このメソッドは PEM のラベルに応じて処理を振り分けるため、間違った DER デコーダーを手作業で選んでしまうことを防げます。証明書は代わりに `X509Certificate2` で扱ってください。
csharp // .NET 5+: ImportFromPem reads the label and picks the right decoder // (PRIVATE KEY, RSA PRIVATE KEY, EC PRIVATE KEY, PUBLIC KEY, RSA PUBLIC KEY). using var key = ECDsa.Create(); key.ImportFromPem(File.ReadAllText("key.pem")); - 2.
DER 構造に合ったメソッドを使う
生の DER を扱う必要がある場合は、データの中身に応じてインポートメソッドを選んでください。ASN.1 ビューアーを使えば、どの構造なのかが分かります。
csharp // DER input: choose the method by structure rsa.ImportPkcs8PrivateKey(der, out _); // "PRIVATE KEY" rsa.ImportRSAPrivateKey(der, out _); // "RSA PRIVATE KEY" rsa.ImportSubjectPublicKeyInfo(der, out _); // "PUBLIC KEY" rsa.ImportRSAPublicKey(der, out _); // "RSA PUBLIC KEY" ecdsa.ImportECPrivateKey(der, out _); // "EC PRIVATE KEY"