在PEM中分发公钥时,如何使用Web加密验证ES256 JWT令牌?

在PEM中分发公钥时,如何使用Web加密验证ES256 JWT令牌?,web,cryptography,jwt,Web,Cryptography,Jwt,我需要在Cloudflare Worker中验证ES256 JWT令牌。据我所知,他们没有在那里运行Node.js,我将不得不使用Web Crypto API(也可以在浏览器中使用,如window.Crypto.sential)。但是,我希望将公钥作为PEM文件接收,并且我认为我在导入它们时遇到了问题 我一直在尝试修改现有的只支持HS256的开源JWT实现,以支持ES256 除了尝试使用实际的令牌和密钥,以及在浏览器和OpenSSL中生成的密钥外,我还尝试使用JWT.io网站上的一个工作示例(使

我需要在Cloudflare Worker中验证ES256 JWT令牌。据我所知,他们没有在那里运行Node.js,我将不得不使用Web Crypto API(也可以在浏览器中使用,如
window.Crypto.sential
)。但是,我希望将公钥作为PEM文件接收,并且我认为我在导入它们时遇到了问题

我一直在尝试修改现有的只支持HS256的开源JWT实现,以支持ES256

除了尝试使用实际的令牌和密钥,以及在浏览器和OpenSSL中生成的密钥外,我还尝试使用JWT.io网站上的一个工作示例(使用node jose将其转换为JWK格式后),因为它应该正确验证。但我没有收到任何错误,我在浏览器中运行的代码只是告诉我令牌无效

下面是我的Node REPL会话,用于将密钥从JWT.io转换为JWK:

>const-jose=require('node-jose')
>const publicKey=`BEGIN PUBLIC KEY-----
... MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEVs/o5+uQbTjL3chynL4wXgUg2R9
... Q9UU8I5MEOVUF86QZ7KOBIJWQNZD1OMAGEEHWHDBO6B+dFabmdT9POxg==
... -----结束公钥-----`
>const keyStore=jose.JWK.createKeyStore()
>keyStore.add(公钥'pem')
>keyStore.toJSON()
{
关键点:[
{
kty:‘EC’,
孩子:“19J8y7Zprt2-QKLjF2I5pVk0OELX6cY2AfaAv1LC_w8”,
crv:‘P-256’,
x:“EVs_o5-uqbtjl3chynl4wxgug2r9q9uuu8i5Meovuf84”,
y:'kge5dgsiyckp8w9ajmohb1sb3qtugfnrwm5nutzsy'
}
]
}
>
以下是根据
webcrypto jwt
软件包中的代码进行的失败验证:

函数utf8ToUint8Array(str){
//改编自https://chromium.googlesource.com/chromium/blink/+/master/LayoutTests/crypto/minute/hmac/sign-verify.html
var Base64URL={
字符串化:功能(a){
var base64string=btoa(String.fromCharCode.apply(0,a));
返回base64string.replace(//=/g',).replace(//\+/g',-').replace(//\//g',-');
},
解析:函数{
s=s.replace(/-/g,“+”)。replace(/g,“/”)。replace(/\s/g,”);
返回新的Uint8Array(Array.prototype.map.call(atob,函数(c){返回c.charCodeAt(0);}));
}
};
str=btoa(unescape(encodeURIComponent,str));
返回Base64URL.parse(str);
}
var cryptodivident=(加密和加密.divident)||
(加密和加密webkit)||
(window.msCrypto&&window.msCrypto.sential);
//来自JWT.io的令牌
var令牌部分=[
“eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9”,
“EyjzdwiiixMj0Nty3ODKwiibmFtzSi6IkPvAg4GrG9LiiWiyWrTaw4IonrydWusimlHdci6mtuxNjizotaymn0”,
“tyh-VFUZIXCYGYDLKBA7DFYJRQMSHU6PQ2HOZUFQUSLPNY20MPHB3NK5K17HWP_3CYHBW7AHALE5WKY6-sVA”
];
//使用Node jose在节点中转换来自JWT.io的公钥
var公钥={
kty:‘EC’,
孩子:“19J8y7Zprt2-QKLjF2I5pVk0OELX6cY2AfaAv1LC_w8”,
crv:‘P-256’,
x:“EVs_o5-uqbtjl3chynl4wxgug2r9q9uuu8i5Meovuf84”,
y:'kge5dgsiyckp8w9ajmohb1sb3qtugfnrwm5nutzsy'
};
变量importAlgorithm={
名称:“ECDSA”,
namedCurve:'P-256',
散列:“SHA-256”,
};
加密密钥(
“jwk”,
公钥,
重要算法,
假,,
[“核实”]
).然后(功能(键){
var partialToken=tokenParts.slice(0,2).join('.');
var signaturePart=tokenParts[2];
加密验证(
重要算法,
钥匙
UTF8ToInt8阵列(签名部分),
UTF8TOUINT8阵列(partialToken)
).然后(函数(ok){
如果(确定){
log(“我认为它是有效的”);
}否则{
log(“我认为它是无效的”);
}
}).catch(函数(err){
日志(“错误验证”,err);
});
}).catch(函数(err){
log(“错误导入”,err);
});
因为我从JWT.io复制了一个有效的密钥和一个有效的令牌,所以我希望代码记录“我认为它是有效的”而没有错误。事实上,它没有显示任何错误,但最终会出现“我认为它无效”分支。

在这里回答

因此,如果我理解正确的话,问题在于开源上游中包含的base64编码在其中一个方向上无法正常工作,因为它使用浏览器的btoa。相反,适应是有效的