作为快速概述,我尝试使用https://github.com/dvsekhvalnov/jose-jwt库通过C#生成ES256算法-JWT令牌。
如指示状态:
ES256,ES384,ES256 ECDSA签名需要CngKey(通常为私有)
相应长度的椭圆曲线键。通常存在的CngKey
通过Key Storage Provider中的CngKey.Open(..)方法加载。但是如果
您想使用原始密钥材料(x,y)和d,jose-jwt提供
方便的帮手EccKey.New(x,y,d)。
CngKey.Open()声明它会打开一个现有的密钥,但是从声音上来说,我应该使用CngKey.Import()代替?当我尝试调用CngKey.Import()时,它返回以下错误:
参数错误。
基本上,我要问的是将现有PEM文件转换为Jose.JWT.Encode()函数所需的CngKey对象的最简单方法是什么?任何帮助将不胜感激。谢谢!
以下是我的代码(出于安全目的,不是真正的私钥):
public string GenerateToken(int contactID, Database _db)
{
var contact = GetContact(contactID, _db);
var payload = new Dictionary<string, object>()
{
{"broker", 1},
{"contact_id", contact.id},
{"name", contact.fname + " " + contact.lname + ""},
{"iss", "www.somewhere.com"},
{"iat", (DateTime.Now - UnixEpoch).TotalSeconds},
{"nbf", (DateTime.Now - UnixEpoch).TotalSeconds},
{"exp", (DateTime.Now.AddDays(30) - UnixEpoch).TotalSeconds}
};
string privateKey =
"MHcCAQEffEIIIHHHHHHHHHHHHHHHffHHHHHHHHHHHHHHHHHHHHHHHoGgCCqGSM49" +
"AwEHhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhI+pRkAxAb13" +
"77vz2Yjjjjjjjjjjjjjjjjjjjjw==";
byte[] b = Convert.FromBase64String(privateKey);
CngKey cng = CngKey.Import(b, CngKeyBlobFormat.EccPrivateBlob);
string token = Jose.JWT.Encode(payload, cng, JwsAlgorithm.ES256);
return token;
}
最佳答案
我在jose-jwt
上遇到了同样的问题,并且使用我自己的GetECDsaPrivateKey()
实现来使其正常工作。请注意,您的项目应以.NET 4.6.1为目标。请按照以下步骤操作:
1,使用openssl生成p12 X509Certificate2
> openssl ecparam -name prime256v1 -genkey > private-key.pem
> openssl ec -in private-key.pem -pubout -out public-key.pem
> openssl req -new -key private-key.pem -x509 -nodes -days 365 -out public.cer
> winpty openssl pkcs12 -export -in public.cer -inkey private-key.pem -out publiccert.p12
2.通过从上面生成的证书中读取私钥来生成JWT:
var claims = new Dictionary<string, object>()
{
{ "sub", "[email protected]" },
{ "exp", 1300819380 }
};
var certificate = new X509Certificate2("publiccert.p12", "passcode");
string token = SignJWTWithCert(certificate, claims);
private static string SignJWTWithCert(X509Certificate2 cert, object claims)
{
var header = new { alg = "ES256", typ = "JWT" };
byte[] headerBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header, Formatting.None));
byte[] claimsBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(claims, Formatting.None));
using (ECDsa ecdsa = cert.GetECDsaPrivateKey())
{
if (ecdsa == null)
throw new ArgumentException("Cert must have an ECDSA private key", nameof(cert));
var payload = Base64UrlEncode(headerBytes) + "." + Base64UrlEncode(claimsBytes);
var signature = ecdsa.SignData(Encoding.UTF8.GetBytes(payload), HashAlgorithmName.SHA256);
return payload + "." + Base64UrlEncode(signature);
}
}