Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
c#JWT将ES256 PEM文件加载到CngKey(jose JWT)_C#_Jwt - Fatal编程技术网

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

c#JWT将ES256 PEM文件加载到CngKey(jose JWT),c#,jwt,C#,Jwt,作为一个快速概述,我试图通过C#使用库生成一个ES256算法-JWT令牌 如指示所述: ES256、ES384、ES256 ECDSA签名需要CngKey(通常为专用) 对应长度的椭圆曲线密钥。正常存在的CngKey 从密钥存储提供程序通过CngKey.Open(..)方法加载。但如果 jose jwt提供,您需要使用原始关键材料(x,y)和d 方便的助手EccKey.新的(x,y,d) Open()声明它打开了一个现有的键,但是听上去我应该使用CngKey.Import()来代替它?当我尝试调

作为一个快速概述,我试图通过C#使用库生成一个ES256算法-JWT令牌

如指示所述:

ES256、ES384、ES256 ECDSA签名需要CngKey(通常为专用) 对应长度的椭圆曲线密钥。正常存在的CngKey 从密钥存储提供程序通过CngKey.Open(..)方法加载。但如果 jose jwt提供,您需要使用原始关键材料(x,y)和d 方便的助手EccKey.新的(x,y,d)

Open()声明它打开了一个现有的键,但是听上去我应该使用CngKey.Import()来代替它?当我尝试调用CngKey.Import()时,它返回以下错误:

参数不正确

基本上,我要问的是,将现有PEM文件转换为Jose.JWT.Encode()函数所需的CngKey对象的最简单方法是什么?任何帮助都将不胜感激。谢谢

以下是我的代码(出于安全目的,它不是真正的私钥):

publicstringgenerateToken(int-contactID,数据库)
{
var contact=GetContact(contactID,_db);
var payload=newdictionary()
{
{“经纪人”,1},
{“contact_id”,contact.id},
{“名称”,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}
};    
字符串私钥=
“MHCCAQEFFEIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH+
“啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊+
“77VZ2YJJJJW=”;
字节[]b=Convert.FromBase64String(privateKey);
CngKey cng=CngKey.Import(b,CngKeyBlobFormat.eccprovateblob);
字符串令牌=Jose.JWT.Encode(有效载荷,cng,JwsAlgorithm.ES256);
返回令牌;
}

我与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);
        }
}
var声明=新字典()
{
{“sub”,“mr。x@contoso.com" },
{“exp”,1300819380}
};
var证书=新的X509Certificate2(“publiccert.p12”、“密码”);
字符串令牌=SignJWTWithCert(证书、声明);
私有静态字符串SignJWTWithCert(X509Certificate2Cert,对象声明)
{
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));
使用(ECDsa ECDsa=cert.GetECDsaPrivateKey())
{
如果(ecdsa==null)
抛出新的ArgumentException(“证书必须有ECDSA私钥”,nameof(Cert));
var有效负载=Base64UrlEncode(headerBytes)+“+”Base64UrlEncode(claimsBytes);
var signature=ecdsa.SignData(Encoding.UTF8.GetBytes(payload),HashAlgorithmName.SHA256);
返回有效载荷+“+”Base64UrlEncode(签名);
}
}

这似乎非常有用,假设它可以工作,但是否可以共享
Base64UrlEncode()
的确切功能?首先编码到base64,然后url编码?或者相反?还有,你从哪里得到指数(上面的字典键
exp
exp)?有没有办法使用生成的证书找到它?
exp
是exipry(unix时间戳)。您可以使用自己选择的编程生成它,对于
Base64UrlEncode()
,您可以查看
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);
        }
}