我有一个 .PEM 格式的私钥,我试图用它来使用 Microsoft 的库从 JWT 中解密密文,但无法解密。我有一个使用 Jose.JWT.Decode 的工作解决方案。但是,当我尝试使用 JwtSecurityTokenHandler.ValidateToken 时,我总是收到 idx10609: 解密失败。如果有人能向我解释如何使用 Microsoft 库而不是 Jose,我会很高兴。
这是工作的 Jose.JWT 代码:
public static string jweRsaDecryptFromBase64UrlToken(string rsaPrivateKey, string jweTokenBase64Url)
{
RSA rsaAlg = RSA.Create();
byte[] privateKeyByte = getRsaPrivateKeyEncodedFromPem(rsaPrivateKey);
int _out;
rsaAlg.ImportPkcs8PrivateKey(privateKeyByte, out _out);
string json = "";
try
{
json = Jose.JWT.Decode(jweTokenBase64Url, rsaAlg);
}
catch (Jose.EncryptionException)
{
Console.WriteLine("*** Error: payload corrupted or wrong private key ***");
// throws: Jose.EncryptionException: Unable to decrypt content or authentication tag do not match.
}
return json;
}
static byte[] Base64Decoding(string input)
{
return Convert.FromBase64String(input);
}
private static byte[] getRsaPrivateKeyEncodedFromPem(string rsaPrivateKeyPem)
{
string rsaPrivateKeyHeaderPem = "-----BEGIN PRIVATE KEY-----\r\n";
string rsaPrivateKeyFooterPem = "-----END PRIVATE KEY-----";
string rsaPrivateKeyDataPem = rsaPrivateKeyPem.Replace(rsaPrivateKeyHeaderPem, "").Replace(rsaPrivateKeyFooterPem, "").Replace("\n", "");
return Base64Decoding(rsaPrivateKeyDataPem);
}
private static string loadRsaPrivateKeyPem()
{
string keyPath = "..\\..\\..\\keys\\";
string encryptionKey = File.ReadAllText($"{keyPath}private.pem");
return encryptionKey;
}
这是我认为应该有效但总是失败的代码:
public static void DecryptJwe(string jweString, string decryptionKeyInput)
{
string jweToken = jweString;
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(jweToken);
var tokens = jsonToken as JwtSecurityToken;
var rsaKey = RSA.Create();
byte[] privateKeyByte = getRsaPrivateKeyEncodedFromPem(decryptionKeyInput);
static byte[] Base64Decoding(string input)
{
return Convert.FromBase64String(input);
}
static byte[] getRsaPrivateKeyEncodedFromPem(string rsaPrivateKeyPem)
{
string rsaPrivateKeyHeaderPem = "-----BEGIN PRIVATE KEY-----\r\n";
string rsaPrivateKeyFooterPem = "-----END PRIVATE KEY-----";
string rsaPrivateKeyDataPem = rsaPrivateKeyPem.Replace(rsaPrivateKeyHeaderPem, "").Replace(rsaPrivateKeyFooterPem, "").Replace("\n", "");
return Base64Decoding(rsaPrivateKeyDataPem);
}
rsaKey.ImportPkcs8PrivateKey(privateKeyByte, out _);
byte[] hashed = rsaKey.ExportRSAPrivateKey();
var privateEncryptionKey = new RsaSecurityKey(rsaKey);
var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(hashed);
//var encryptingCredentials = new EncryptingCredentials(new SymmetricSecurityKey(privateKeyByte), SecurityAlgorithms.Aes256Gcm, SecurityAlgorithms.RsaOAEP);
bool alg = securityKey.IsSupportedAlgorithm("A256GCM");
var readableToken = handler.CanReadToken(jweString);
if (readableToken != true)
{
Console.WriteLine("The token doesn't seem to be in a proper JWT format.");
}
/*
//Extract the headers of the JWT
var headers = tokens.Header;
var jwtHeaders = "{";
foreach (var h in headers)
{
jwtHeaders += '"' + h.Key + "\":\"" + h.Value + "\",";
Console.WriteLine($"Header: {h.Key} Value: {h.Value} ");
}
jwtHeaders += "}";
*/
handler.ValidateToken(jweString, new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
TokenDecryptionKey = new SymmetricSecurityKey(privateKeyByte),
ValidateIssuer = false,
ValidateAudience = false,
}, out SecurityToken validatedToken);
如果 JWT 使用 RSA 密钥加密,则应使用 RsaSecurityKey 而不是 SymmetricSecurityKey。在 TokenValidationParameters 中,您提供了 TokenDecryptionKey 作为从 RSA 私钥字节派生的 SymmetricSecurityKey。您应该直接使用 RsaSecurityKey。
资源:
public static void DecryptJwe(string jweString, string decryptionKeyInput)
{
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
var handler = new JwtSecurityTokenHandler();
if (!handler.CanReadToken(jweString))
{
Console.WriteLine("The token doesn't seem to be in a proper JWT format.");
return;
}
byte[] privateKeyByte = getRsaPrivateKeyEncodedFromPem(decryptionKeyInput);
RSA rsaKey = RSA.Create();
rsaKey.ImportPkcs8PrivateKey(privateKeyByte, out _);
var privateEncryptionKey = new RsaSecurityKey(rsaKey);
SecurityToken validatedToken;
try
{
handler.ValidateToken(jweString, new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
TokenDecryptionKey = privateEncryptionKey, // Use the RSA key directly
ValidateIssuer = false,
ValidateAudience = false,
}, out validatedToken);
// If successful, the token is decrypted and validated. Use validatedToken as needed.
}
catch (Exception ex)
{
Console.WriteLine($"Token validation failed: {ex.Message}");
}
}
备注: