c#JWT将ES256 PEM文件加载到CngKey(jose-jwt)

时间:2016-06-30 16:55:08

标签: c# jwt

作为快速概述,我尝试使用https://github.com/dvsekhvalnov/jose-jwt库通过C#生成ES256算法-JWT令牌。

正如指示所述:

  

ES256,ES384,ES256 ECDSA签名需要CngKey(通常为私人)   相应长度的椭圆曲线键。通常存在CngKey   通过密钥存储提供程序的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;
        }

1 个答案:

答案 0 :(得分:2)

我对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", "mr.x@contoso.com" },
    { "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);
        }
}