如何在 C# 中解密 JWE 源代码(使用 RSA1_5 A256CBC-HS512 加密)?

How to decrypt JWE source (encrypted with RSA1_5 A256CBC-HS512) in C#?

我正在实现一个客户端,用于通过密码学方式与某些服务器进行通信。客户端向服务器发送带有 public RSA 密钥的获取请求。文档“如何与服务器通信”包含带有 java 代码的示例。以下代码生成 public 键:

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keypair = keyGen.genKeyPair();
byte[] pubKeyBytes = keypair.getPublic().getEncoded();

我需要用 C# 实现我的客户端。我找到了如何在 C# 中执行相同操作的方法:

var rsa = new RSACryptoServiceProvider(2048);
var parameters = _rsa.ExportParameters(includePrivateParameters: false);

客户端使用来自的参数和解决方案,没关系。客户端可以生成可以在服务器上通过验证的密钥。 结果,我得到了加密的响应并尝试对其进行解密。

responseContent = rsa.Decrypt(responseContent)

但是此代码抛出以下异常:

System.Security.Cryptography.CryptographicException: 'The data to be decrypted exceeds the maximum for this modulus of 256 bytes.'

responseContent是字节数组,长度为250996。而且我看到不可能通过上面的方式解密响应内容。

根据文档,我知道

此外,我有一个示例如何解密 java 中的响应:

JWEObject jweObject = JWEObject.parse(encryptedPayload); 
RSAPrivateKey rsaPrivatteKey = (RSAPrivateKey)KeyFactory
    .getInstance("RSA")
    .generatePrivate(new PKCS8EncodedKeySpec(keybytes));
RSADecrypter RSADecrypter rsaDecrypter= new RSADecrypter(rsaPrivateKey);
JWEObject jweObject.decrypt(rsaDecrypter); 
String decryptedResponse = jweObject.getPayload().toString();

我认为 rsa.Decrypt 是上面代码的模拟。但正如我播种 - 不是。 经过一番研究,我发现我的回复是 JWE 来源。 基于 https://www.rfc-editor.org/rfc/rfc7516,我将我的回复拆分为以“.”分隔的部分。并从 base64url 解码它们中的每一个。结果我有:

我认为主要内容在Cipertext中,我需要对其进行解密。但我不知道是怎么回事,因为 Cipertext 大小超过 256 字节,我不能使用 rsa.Decrypt.

当源文件的大小大于 RSA 密钥时,如何解密源文件?

我发现这个库 js-jose 可以完全满足我的需要。我将它添加为 NuGet 包,编写如下代码:

 JWT.Decode(responseContent, // content as String read from Response
            rsa, // RSACryptoServiceProvider
            JweAlgorithm.RSA1_5, 
            JweEncryption.A256CBC_HS512); 

并解密了内容。

我刚刚使用 .NET6 完成了一个实验性控制台应用程序,以熟悉 JWT、JWS 和 JWE 的概念。

也许这可以帮助某人...

我想让它在不使用任何第三方包的情况下工作。 这些都是 using 语句:

using Microsoft.IdentityModel.Tokens;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

您将需要一个 TokenValidationParameters object 来配置验证。 为此,您需要:

  • 一个public验证签名的密钥
  • 用于解密 header 和有效载荷的私钥

为了演示目的,这两个都存储在本地。

// Get public key to verify the signature
string publicKeySign = File.ReadAllText(@"C:\Docs\publicKeySign.pem");
var rsaPublicKey = RSA.Create();
rsaPublicKey.ImportFromPem(publicKeySign);

// Get private key to decrypt
string privateKeyEncrypt = File.ReadAllText(@"C:\Docs\privateKeyEncrypt.key");
rsaPrivateKey = RSA.Create();
rsaPrivateKey.ImportFromPem(privateKeyEncrypt);

// Pass those keys into the TokenValidationParameters object
var validationParameters = new TokenValidationParameters
{
    ValidateIssuerSigningKey = true,
    ValidateIssuer = true,
    ValidateAudience = true,
    ValidIssuer = "http://mysite.example.com",
    ValidAudience = "http://myaudience.example.com",
    IssuerSigningKey = new RsaSecurityKey(rsaPublicKey),
    TokenDecryptionKey = new RsaSecurityKey(rsaPrivateKey)
};

// Pass in the token (as a string) and your tokenValidationParameters
JwtSecurityTokenHandler jwtSecurityTokenHandler = new();
TokenValidationResult result = await jwtSecurityTokenHandler.ValidateTokenAsync(token, tokenValidationParameters);

结果是 TokenValidationResultMS Docs here。它具有以下属性:

  1. 声明,这是一个字典
  2. ClaimsIdentity,它又具有 属性:
    • 声明,这是一个 IEnumerable

这样,您就可以检查与 JWE 一起发送的声明。 希望这对您有所帮助,祝您玩得愉快!