作为快速概述,我尝试使用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);
        }
}

08-06 15:46