尝试使用 OpenSSL RSA 生成的密钥在 ASP .NET 应用程序中使用

问题描述 投票:0回答:1

我正在尝试使用通过 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 令牌签名应该可以工作)。

c# asp.net-core openssl rsa private-key
1个回答
0
投票

首先导入私钥,然后导入公钥并用其覆盖私钥,即最终只导入公钥。
由于

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 编码的密钥派生)。

© www.soinside.com 2019 - 2024. All rights reserved.