简体   繁体   English

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

[英]c# JWT load ES256 PEM file into CngKey (jose-jwt)

As a quick overview I am attempting to generate a ES256 algorithm -JWT token via C# using the https://github.com/dvsekhvalnov/jose-jwt library. 作为快速概述,我试图使用https://github.com/dvsekhvalnov/jose-jwt库通过C#生成ES256算法-JWT令牌。

As the directions state: 正如指示所述:

ES256, ES384, ES256 ECDSA signatures requires CngKey (usually private) elliptic curve key of corresponding length. ES256,ES384,ES256 ECDSA签名需要相应长度的CngKey(通常为私有)椭圆曲线键。 Normally existing CngKey loaded via CngKey.Open(..) method from Key Storage Provider. 通常,现有的CngKey通过密钥存储提供程序的CngKey.Open(..)方法加载。 But if you want to use raw key material (x,y) and d, jose-jwt provides convenient helper EccKey.New(x,y,d). 但是如果你想使用原始密钥材料(x,y)和d,jose-jwt提供了方便的帮助器EccKey.New(x,y,d)。

The CngKey.Open() states it opens an existing key, but by the sounds of it I should be using the CngKey.Import() instead? CngKey.Open()声明它打开一个现有的键,但通过它的声音我应该使用CngKey.Import()而不是? When I attempt to call the CngKey.Import() it returns the following error: 当我尝试调用CngKey.Import()时,它返回以下错误:

The parameter is incorrect. 参数不正确。

Basically what I am asking is what is the simplest way to convert an existing PEM file into the CngKey object which is required for the Jose.JWT.Encode() function? 基本上我要问的是将现有PEM文件转换为Jose.JWT.Encode()函数所需的CngKey对象的最简单方法是什么? Any help would be highly appreciated. 任何帮助将受到高度赞赏。 Thanks! 谢谢!

Below is my code(for security purposed that is not the real private key): 下面是我的代码(出于安全目的,这不是真正的私钥):

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;
        }

I had the same problem with jose-jwt and got it working using my own implementation of GetECDsaPrivateKey() . 我和jose-jwt有同样的问题,并使用我自己的GetECDsaPrivateKey()实现工作。 Note that your project should target .NET 4.6.1 . 请注意,您的项目应以.NET 4.6.1为目标。 Please follow the steps below: 请按照以下步骤操作:

1.Generate a p12 X509Certificate2 using openssl 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.Generate a JWT by reading private key from above generated certificate: 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);
        }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM