我正在尝试使用通过 OpenSSL 生成的密钥。以下是我用来创建它们的命令:
openssl genrsa -out keypair-2023.pem 4096
openssl rsa -in keypair-2023.pem -pubout -out pub-2023.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair-2023.pem -out priv-2023-v8.key
文件的格式是这样的...
-----BEGIN PUBLIC KEY-----
{{ public key contents }}
-----END PUBLIC KEY-----
-----BEGIN PRIVATE KEY-----
{{ private key contents }}
-----END PRIVATE KEY-----
这里有一些我尝试过的代码片段,以便让它们工作(以及结果)
var rsaKey = RSA.Create();
rsaKey.ImportFromPem(privateKeyStr);
rsaKey.ImportFromPem(publicKeyStr);
var rsaParams = rsaKey.ExportParameters(true);
var securityKey = new RsaSecurityKey(rsaParams);
结果:
System.Security.Cryptography.CryptographicException: 'Key does not exist.'
位于“ExportParameters”行
var privateKeyBuffer = new Span<byte>(new byte[privateKeyStr.Length]);
Convert.TryFromBase64String(privateKeyStr, privateKeyBuffer, out _);
var rsaKey = RSA.Create();
rsaKey.ImportRSAPrivateKey(privateKeyBuffer, out _);
rsaKey.ImportFromPem(publicKeyStr);
var rsaParams = rsaKey.ExportParameters(true);
结果:
AsnContentException: The provided data is tagged with 'Universal' class value '0', but it should have been 'Universal' class value '16'
位于“ImportRSAPrivateKey”行。
将“ImportRSAPrivateKey”方法替换为“ImportPkcs8PrivateKey”会导致抛出相同的异常。
现在,这些密钥的用途是签署和验证 JWT 令牌。如果我使用第一个代码片段,但使用“rsaKey”对象创建“securityKey”,则我有以下代码:
var rsaKey = RSA.Create();
rsaKey.ImportFromPem(privateKeyStr);
rsaKey.ImportFromPem(publicKeyStr);
var securityKey = new RsaSecurityKey(rsaKey);
_signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSha512);
_securityTokenHandler = new JwtSecurityTokenHandler();
应用程序启动,但当我到达使用“_signingCredentials”创建 JWT 令牌的代码时,出现此异常:
System.Security.Cryptography.CryptographicException: 'Key does not exist.'
有没有办法正确使用密钥以便我可以创建 JWT 令牌? (我怀疑如果我能越过
var rsaParams = rsaKey.ExportParameters(true)
线,那么 JWT 令牌签名应该可以工作)。
首先导入私钥,然后导入公钥并用其覆盖私钥,即最终只导入公钥。
由于
ExportParameters(true)
和签名时需要私钥,但缺少私钥,因此会抛出 CryptographicException' 'Key does not exist'
。
修复:私钥隐式包含公钥,即通过
rsaKey.ImportFromPem(privateKeyStr)
,私钥和公钥都被导入。rsaKey.ImportFromPem(publicKeyStr)
行。
以下作品:
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Security.Cryptography;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
...
var rsaKey = RSA.Create();
rsaKey.ImportFromPem(privateKeyStr);
//rsaKey.ImportFromPem(publicKeyStr); // Fix: remove line
var rsaParams = rsaKey.ExportParameters(true); // succeeds now...
var securityKey = new RsaSecurityKey(rsaKey);
var _signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSha512);
var jwt = new JwtSecurityToken(new JwtHeader(_signingCredentials),new JwtPayload("issuer", "audience", new List<Claim>(), DateTime.UtcNow, DateTime.UtcNow.AddHours(3)));
var token = new JwtSecurityTokenHandler().WriteToken(jwt); // succeeds now...
第二次尝试失败,因为另外发布的私钥的密钥格式是PKCS#8,而
ImportRSAPrivateKey()
需要PKCS#1格式的私钥。ImportRSAPrivateKey()
需要 DER 编码的密钥,而发布的密钥是 PEM 编码的(DER 编码的密钥可以通过删除页眉、页脚和换行符以及对其余部分进行 Base64 解码来从 PEM 编码的密钥派生)。