使用JavaScript中的EDDSA算法签署消息以获取JWT
我需要使用EDDSA算法获得JWT才能使用API。我有一个私钥可以签署消息,可以在下一个库中使用PHP来做到这一点: https:/https:/ /Github.com/firebase/php-jwt (您可以在readme看到EDDSA的示例)。现在我需要在JS中进行同样的操作,但是我找不到使用给定的秘密键(编码基础64)获得JWT的方法(只有一个示例不是真正的SecretKey):
const secretKey = Dm2xriMD6riJagld4WCA6zWqtuWh40UzT/ZKO0pZgtHATOt0pGw90jG8BQHCE3EOjiCkFR2/gaW6JWi+3nZp8A==
我尝试了很多像这样的库Jose,JS-NACL,Crypto,libsodium等。我真的很接近使用libodium库获得JWT,现在我附加了代码:
const base64url = require("base64url");
const _sodium = require("libsodium-wrappers");
const moment = require("moment");
const getJWT = async () => {
await _sodium.ready;
const sodium = _sodium;
const privateKey =
"Dm2xriMD6riJagld4WCA6zWqtuWh40UzT/ZKO0pZgtHATOt0pGw90jG8BQHCE3EOjiCkFR2/gaW6JWi+3nZp8A==";
const payload = {
iss: "test",
aud: "test.com",
iat: 1650101178,
exp: 1650101278,
sub: "12345678-1234-1234-1234-123456789123"
};
const { msg, keyAscii} = encode(payload, privateKey, "EdDSA");
const signature = sodium.crypto_sign_detached(msg, keyDecoded); //returns Uint8Array(64)
//Here is the problem.
};
const encode = (payload, key, alg) => {
const header = {
typ: "JWT",
alg //'EdDSA'
};
const headerBase64URL = base64url(JSON.stringify(header));
const payloadBase64URL = base64url(JSON.stringify(payload));
const headerAndPayloadBase64URL = `${headerBase64URL}.${payloadBase64URL}`;
const keyAscii= Buffer.from(key, "base64").toString("ascii");
return {headerAndPayloadBase64URL , keyAscii}
};
问题是在钠中我需要这样的JWT:
eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSJ9.eyJpc3MiOiJ0ZXN0IiwiYXVkIjoidGVzdC5jb20iLCJpYXQiOjE2NTAxMDExNzgsImV4cCI6MTY1MDEwMTI3OCwic3ViIjoiMTIzNDU2NzgtMTIzNC0xMjM0LTEyMzQtMTIzNDU2Nzg5MTIzIn0.f7WG_02UKljrMeVVOTNNBAGxtLXJUT_8QAnujNhomV18Pn5cU-0lHRgVlmRttOlqI7Iol_fHut3C4AOXxDGnAQ
如何更改Uint8array(64)以正确格式获得签名以获取JWT?我尝试使用base64,base64url,十六进制,文本,ASCII等尝试,最终的JWT无效(因为签名是错误的)。 如果将我的代码与我提到的PHP的代码进行比较,则非常相似,但是函数钠.crypto_sign_detached returns返回uint8array(64)在JS库中,并且PHP中的相同函数返回字符串,我可以获取令牌。 或者,也许有一种方法可以调整我给定的私钥在其他库中使用(例如我收到私有密钥格式错误的加密货币或何塞) 谢谢你!
I need to get JWT with EdDSA algorithm to be able to use an API. I have the private key to sign the message and I could do that with PHP with the next library: https://github.com/firebase/php-jwt (you can see the example with EdDSA at README). Now I need to do the same in JS but I didn't find the way to get JWT with a given secret key (encoded base 64) like that (only an example is not the real secretKey):
const secretKey = Dm2xriMD6riJagld4WCA6zWqtuWh40UzT/ZKO0pZgtHATOt0pGw90jG8BQHCE3EOjiCkFR2/gaW6JWi+3nZp8A==
I tried a lot of libraries like jose, js-nacl, crypto, libsodium, etc. And I am really close to get the JWT with libsodium library, now I attach the code:
const base64url = require("base64url");
const _sodium = require("libsodium-wrappers");
const moment = require("moment");
const getJWT = async () => {
await _sodium.ready;
const sodium = _sodium;
const privateKey =
"Dm2xriMD6riJagld4WCA6zWqtuWh40UzT/ZKO0pZgtHATOt0pGw90jG8BQHCE3EOjiCkFR2/gaW6JWi+3nZp8A==";
const payload = {
iss: "test",
aud: "test.com",
iat: 1650101178,
exp: 1650101278,
sub: "12345678-1234-1234-1234-123456789123"
};
const { msg, keyAscii} = encode(payload, privateKey, "EdDSA");
const signature = sodium.crypto_sign_detached(msg, keyDecoded); //returns Uint8Array(64)
//Here is the problem.
};
const encode = (payload, key, alg) => {
const header = {
typ: "JWT",
alg //'EdDSA'
};
const headerBase64URL = base64url(JSON.stringify(header));
const payloadBase64URL = base64url(JSON.stringify(payload));
const headerAndPayloadBase64URL = `${headerBase64URL}.${payloadBase64URL}`;
const keyAscii= Buffer.from(key, "base64").toString("ascii");
return {headerAndPayloadBase64URL , keyAscii}
};
The problem is in the sodium.crypto_sign_detached function because it returns an Uint8Array(64) signature and and I need the JWT like that:
eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSJ9.eyJpc3MiOiJ0ZXN0IiwiYXVkIjoidGVzdC5jb20iLCJpYXQiOjE2NTAxMDExNzgsImV4cCI6MTY1MDEwMTI3OCwic3ViIjoiMTIzNDU2NzgtMTIzNC0xMjM0LTEyMzQtMTIzNDU2Nzg5MTIzIn0.f7WG_02UKljrMeVVOTNNBAGxtLXJUT_8QAnujNhomV18Pn5cU-0lHRgVlmRttOlqI7Iol_fHut3C4AOXxDGnAQ
How can I change the Uint8Array(64) to get the signature in a right format to get the JWT? I tried with base64, base64url, hex, text, ascii, etc and the final JWT is not valid (because the signature is wrong).
If you compare my code with the code that I mentioned with PHP is very similar but the function sodium.crypto_sign_detached returns Uint8Array(64) at JS library and the same function in PHP returns an string and I can get the token.
Or maybe there a way to adapt my given private key for use in other library (like crypto or jose where I received an error for the private key format)
Thank you!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在发布的nodejs代码中,有以下问题:
crypto_sign_detached()
将签名返回为uint8array
,可以用buffer.from()
代码>并将其转换为带有base64url()
的base64字符串。headerandpayloadbase64url
和base64url编码的签名与。
作为分隔器给您您正在寻找的JWT。'ascii'
解码,因为这通常会损坏数据。相反,它应该简单地作为缓冲区处理。注意:如果由于某些原因需要转换为字符串,请使用'binary'
作为编码,该编码会产生字节字符串(但是,这不是crypto_sign_detached()由于此功能期望缓冲区)。
通过这些更改,以下Nodejs代码结果:
测试:
由于ED25519是确定性的,因此可以通过比较两个JWT来检查NodeJS代码:如果与上述NodeJS代码一样,则使用相同的标头和有效载荷,与PHP代码相同的签名和相同的相同 JWT是通过PHP代码生成的,即:
表明NodeJS代码有效。
请注意,可以使用 package而不是
mongm
date.now()。这将返回以毫秒为单位的时间,因此该值必须除以1000,例如Math.Round(date.now()/1000)
,但保留了依赖关系。In the posted NodeJS code there are the following issues:
crypto_sign_detached()
returns the signature as aUint8Array
, which can be imported withBuffer.from()
and converted to a Base64 string withbase64url()
.headerAndPayloadBase64URL
and the Base64url encoded signature with a.
as separator gives the JWT you are looking for.'ascii'
, as this generally corrupts the data. Instead, it should simply be handled as buffer. Note: If for some reason a conversion to a string is required, use'binary'
as encoding, which produces a byte string (however, this is not an option withcrypto_sign_detached()
as this function expects a buffer).With these changes, the following NodeJS code results:
Test:
Since Ed25519 is deterministic, the NodeJS code can be checked by comparing both JWTs: If, as in the above NodeJS code, the same header and payload are used as in the PHP code, the same signature and thus the same JWT is generated as by the PHP code, namely:
which shows that the NodeJS code works.
Note that instead of the
moment
package,Date.now()
could be used. This will return the time in milliseconds, so the value has to be divided by 1000, e.g.Math.round(Date.now()/1000)
, but saves a dependency.