我正在使用jose-jwt library并希望使用RS256算法在C#中创建签名的JWT进行加密。我没有密码学的经验,所以请原谅我的无知。我在文档中看到以下示例:
var payload = new Dictionary<string, object>()
{
{ "sub", "mr.x@contoso.com" },
{ "exp", 1300819380 }
};
var privateKey=new X509Certificate2("my-key.p12", "password", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet).PrivateKey as RSACryptoServiceProvider;
string token=Jose.JWT.Encode(payload, privateKey, JwsAlgorithm.RS256);
显示了p12
文件的使用,但如何使用下表中的RSA密钥文件?我正在查看X509Certificate2的文档,但我看不到RSA私钥的选项。它似乎只接受PKCS7
,我理解为公钥。
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END RSA PRIVATE KEY-----
最后,docs中列出的两个选项有什么区别,我如何在两者之间做出选择?
-------------------------- OPTION 1 ------------------- -------
RS- *和PS- *家庭
CLR:
需要RS256,RS384,RS512和PS256,PS384,PS512签名 RSACryptoServiceProvider(通常是私有)对应的密钥 长度。需要强制CSP使用Microsoft增强RSA和AES 加密提供商。通常可以重新导入 RSAParameters。见http://clrsecurity.codeplex.com/discussions/243156 详情。
-------------------------- OPTION 2 ------------------- -------
CORECLR:RS256,RS384,RS512签名需要相应长度的RSA(通常是私有)密钥。
答案 0 :(得分:16)
我知道这篇文章很老了,但我花了很长时间才想到这一点,所以我想我会分享。
测试我使用OpenSSL创建了RSA密钥:
openssl genrsa -out privateKey.pem 512
openssl rsa -in privateKey.pem -pubout -out publicKey.pem
您将需要以下2个nuget包:
测试代码
public static void Test()
{
string publicKey = File.ReadAllText(@"W:\Dev\Temp\rsa_keys\publicKey.pem");
string privateKey = File.ReadAllText(@"W:\Dev\Temp\rsa_keys\privateKey.pem");
var claims = new List<Claim>();
claims.Add(new Claim("claim1", "value1"));
claims.Add(new Claim("claim2", "value2"));
claims.Add(new Claim("claim3", "value3"));
var token = CreateToken(claims, privateKey);
var payload = DecodeToken(token, publicKey);
}
创建令牌
public static string CreateToken(List<Claim> claims, string privateRsaKey)
{
RSAParameters rsaParams;
using (var tr = new StringReader(privateRsaKey))
{
var pemReader = new PemReader(tr);
var keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair;
if (keyPair == null)
{
throw new Exception("Could not read RSA private key");
}
var privateRsaParams = keyPair.Private as RsaPrivateCrtKeyParameters;
rsaParams = DotNetUtilities.ToRSAParameters(privateRsaParams);
}
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(rsaParams);
Dictionary<string, object> payload = claims.ToDictionary(k => k.Type, v => (object)v.Value);
return Jose.JWT.Encode(payload, rsa, Jose.JwsAlgorithm.RS256);
}
}
解码令牌
public static string DecodeToken(string token, string publicRsaKey)
{
RSAParameters rsaParams;
using (var tr = new StringReader(publicRsaKey))
{
var pemReader = new PemReader(tr);
var publicKeyParams = pemReader.ReadObject() as RsaKeyParameters;
if (publicKeyParams == null)
{
throw new Exception("Could not read RSA public key");
}
rsaParams = DotNetUtilities.ToRSAParameters(publicKeyParams);
}
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(rsaParams);
// This will throw if the signature is invalid
return Jose.JWT.Decode(token, rsa, Jose.JwsAlgorithm.RS256);
}
}
我发现https://jwt.io/是测试令牌的绝佳资源
答案 1 :(得分:1)
如果您想使用证书,可以使用此方法通过指纹检索
private X509Certificate2 GetByThumbprint(string Thumbprint)
{
var localStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
localStore.Open(OpenFlags.ReadOnly);
return localStore.Certificates//.Find(X509FindType.FindByKeyUsage, X509KeyUsageFlags.DigitalSignature, false)
.Find(X509FindType.FindByThumbprint, Thumbprint, false)
.OfType<X509Certificate2>().First();
}
然后:
private JwtSecurityToken GenerateJWT()
{
var securityKey = new Microsoft.IdentityModel.Tokens.X509SecurityKey(GetByThumbprint("YOUR-CERT-THUMBPRINT-HERE"));
var credentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey, "RS256");
var JWTHeader = new JwtHeader(credentials);
var payload = new JwtPayload
{
{ "iss", "Issuer-here"},
{ "exp", (Int32)(DateTime.UtcNow.AddHours(1).Subtract(new DateTime(1970, 1, 1))).TotalSeconds},
{ "iat", (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds}
};
var token = new JwtSecurityToken(JWTHeader, payload);
return token;
}
答案 2 :(得分:1)
使用BouncyCastle和Jose nuget包,以下代码对我有用。
public static string CreateToken(Dictionary<string, object> payload)
{
string jwt = string.Empty;
RsaPrivateCrtKeyParameters keyPair;
var cert = ConfigurationManager.AppSettings["cert"];
/// cert begins -----BEGIN PRIVATE KEY----- and ends with -END PRIVATE KEY-----";
using (var sr = new StringReader(cert))
{
PemReader pr = new PemReader(sr);
keyPair = (RsaPrivateCrtKeyParameters)pr.ReadObject();
}
RSAParameters rsaParams = DotNetUtilities.ToRSAParameters(keyPair);
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(rsaParams);
jwt = Jose.JWT.Encode(payload, rsa, Jose.JwsAlgorithm.RS256);
}
return jwt;
}
答案 3 :(得分:1)
我想我会添加我的发现,因为我昨晚必须这样做。此页面中的示例确实有帮助,但它们并没有立即起作用。
在我的具体案例中,我试图为 DocuSign 生成 JWT 令牌,但由于其他一些原因我无法使用他们的 SDK,手动生成 JWT 令牌是我的用例的正确方法。
var privateKeybyteArray = Encoding.ASCII.GetBytes(@"-----BEGIN RSA PRIVATE KEY-----
xxxxxxxxxxxxxxxxxx
-----END RSA PRIVATE KEY-----");
var payload = new Dictionary<string, object>
{
{ "iss", "3a31fd58-xxxx-xxxx-xxxx-17639ade3c1b" },
{ "sub", "40a3a606-xxxx-xxxx-xxxx-762c6e7dadb6" },
{ "aud", "account-d.docusign.com" },
{ "iat", DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds },
{ "exp", DateTime.UtcNow.AddHours(1).Subtract(new DateTime(1970, 1, 1)).TotalSeconds },
{ "scope", "signature" }
};
var rsaPrivateKey = new RSAParameters();
using (var ms = new MemoryStream(privateKeybyteArray))
{
using (var sr = new StreamReader(ms))
{
var pemReader = new PemReader(sr);
var keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair;
rsaPrivateKey = DotNetUtilities.ToRSAParameters(keyPair.Private as RsaPrivateCrtKeyParameters);
}
}
var csprivate = new RSACryptoServiceProvider();
csprivate.ImportParameters(rsaPrivateKey);
var algorithm = new RS256Algorithm(csprivate, csprivate);
var serializer = new JsonNetSerializer();
var urlEncoder = new JwtBase64UrlEncoder();
var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
var token = encoder.Encode(payload, privateKeybyteArray);
我使用了 JWT-dotnet 包。我发现网站 jsonwebtoken.io 非常好,因为它生成了生成令牌所需的 .NET 代码,它不太好用,但它有助于找出我做错了什么
答案 4 :(得分:0)
GetRSAPrivateKey仅在.NET 4.6中可用。请参阅以下网址。
答案 5 :(得分:0)
如果使用公共证书和.NET 4.6,则可以使用:
进行解码string token = "eyJhbGciOiJSUzI1NiIsInR....";
string certificate = "MIICnzCCAYcCBgFd2yEPx....";
var publicKey = new X509Certificate2(Convert.FromBase64String(certificate )).GetRSAPublicKey();
string decoded = JWT.Decode(token, publicKey, JwsAlgorithm.RS256);
答案 6 :(得分:0)
以下是创建加密JWT的代码:
var cert = new X509Certificate2(".\\key.cer");
var rsa = (RSACryptoServiceProvider) cert.PublicKey.Key;
var payload = new Dictionary<string, object>()
{
{"sub", "mr.x@contoso.com"},
{"exp", 1300819380}
};
var encryptedToken =
JWT.Encode(
payload,
rsa,
JweAlgorithm.RSA_OAEP,
JweEncryption.A256CBC_HS512,
null);
答案 7 :(得分:0)
这个问题的关键是使用JWT和Bouncy城堡库分别对令牌进行编码和签名。
首先,您需要将私钥转换为RSA参数的形式。然后,您需要将RSA参数作为私钥传递给RSA算法。最后,您使用JWT库对令牌进行编码和签名。
public string GenerateJWTToken(string rsaPrivateKey)
{
var rsaParams = GetRsaParameters(rsaPrivateKey);
var encoder = GetRS256JWTEncoder(rsaParams);
// create the payload according to your need
var payload = new Dictionary<string, object>
{
{ "iss", ""},
{ "sub", "" },
// and other key-values
};
// add headers. 'alg' and 'typ' key-values are added automatically.
var header = new Dictionary<string, object>
{
{ "{header_key}", "{your_private_key_id}" },
};
var token = encoder.Encode(header,payload, new byte[0]);
return token;
}
private static IJwtEncoder GetRS256JWTEncoder(RSAParameters rsaParams)
{
var csp = new RSACryptoServiceProvider();
csp.ImportParameters(rsaParams);
var algorithm = new RS256Algorithm(null, csp);
var serializer = new JsonNetSerializer();
var urlEncoder = new JwtBase64UrlEncoder();
var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
return encoder;
}
private static RSAParameters GetRsaParameters(string rsaPrivateKey)
{
var byteArray = Encoding.ASCII.GetBytes(rsaPrivateKey);
using (var ms = new MemoryStream(byteArray))
{
using (var sr = new StreamReader(ms))
{
// use Bouncy Castle to convert the private key to RSA parameters
var pemReader = new PemReader(sr);
var keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair;
return DotNetUtilities.ToRSAParameters(keyPair.Private as RsaPrivateCrtKeyParameters);
}
}
}
ps:RSA私钥应具有以下格式:
-----开始使用RSA私钥-----
{base64格式的值}
-----结束RSA私钥-----
答案 8 :(得分:0)
使用服务帐户JSON密钥-:发布代码以为GCP OAuth令牌API调用创建RS256 JWT令牌:
using JWT;
using JWT.Algorithms;
using JWT.Serializers;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
namespace GCP
{
class JWTTokenGenerationForGCPOAuthTokenAPI
{
public static string GenerateJWTToken()
{
var rsaParams = ReadAsymmetricKeyParameter();
var encoder = GetRS256JWTEncoder(rsaParams);
var iat = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var exp = DateTimeOffset.UtcNow.AddMinutes(60).ToUnixTimeSeconds();
// create the payload according to your need
// iss is the Service Account Email ID
var payload = new Dictionary<string, object>
{
{ "iss", "<service-account>@<project-id>.iam.gserviceaccount.com"},
{ "scope", "https://www.googleapis.com/auth/cloud-platform" },
{ "aud", "https://oauth2.googleapis.com/token" },
{ "exp", exp},
{ "iat", iat}
};
//Final token
var token = encoder.Encode(payload, new byte[0]);
return token;
}
private static IJwtEncoder GetRS256JWTEncoder(RSAParameters rsaParams)
{
var csp = new RSACryptoServiceProvider();
csp.ImportParameters(rsaParams);
var algorithm = new RS256Algorithm(csp, csp);
var serializer = new JsonNetSerializer();
var urlEncoder = new JwtBase64UrlEncoder();
var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
return encoder;
}
public static RSAParameters ReadAsymmetricKeyParameter()
{
\\ This key is fetched from the GCP Service Account JSON File.
\\"private_key": "-----BEGIN PRIVATE KEY-----\n<long-code>-----END PRIVATE KEY-----\n",
\\ pick <long-code> from above. Replace all \n with actual new line like shown below.
string pkey = @"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDSoGKK/Dzb8MBy
################################################################
################################################################
################################################################
################################################################
twySMqKKWnIC/zZljrvp4w==";
RsaPrivateCrtKeyParameters rsaPrivateCrtKeyParameters1;
var keyBytes = Convert.FromBase64String(pkey);
var asymmetricKeyParameter = PrivateKeyFactory.CreateKey(keyBytes);
rsaPrivateCrtKeyParameters1 = (RsaPrivateCrtKeyParameters)asymmetricKeyParameter;
RSAParameters r = DotNetUtilities.ToRSAParameters(rsaPrivateCrtKeyParameters1);
return r;
}
}
}
在.NET Framework 4.6.1中完成的代码
Nuget软件包:
Bounty Castle-安装软件包BouncyCastle-版本1.8.6.1