问题描述
我想使用通过 Ed25519 在客户端设备上生成的私钥对 JWS(json 网络签名)进行签名。然后将此签名发送到我的后端并使用公钥进行验证。
为了熟悉该过程,我想尝试在节点 js 中签署和验证 JWS。
我的私钥和公钥都已经生成并且在 base58 中可用。这是我目前使用 Ed25519 私钥签署 JWT 的尝试:
const { SignJWT } = require("jose/jwt/sign");
const bs50 = require("bs58");
async function main() {
const publicbase58 = "A77GCUCZ7FAuXVMKtwwXyFhMa158XsaoGKHYNnJ1q3pv";
const privateKeybase58 = "BE1VM7rTRJReLsTLLG4JMNX5ozcp7qpmMuRht9zB1UjU";
const publicKeyBuffer = bs50.decode(publicbase58);
const privateKeyBuffer = bs50.decode(privateKeybase58);
const publicKey = new Uint8Array(publicKeyBuffer);
const privateKey = new Uint8Array(privateKeyBuffer);
const jwt = await new SignJWT({
subject: "uuid",})
.setProtectedHeader({ alg: "EdDSA" })
.setExpirationTime("2h")
.sign(privateKey);
console.log(jwt);
}
错误:类型错误:密钥必须是 KeyObject 或 CryptoKey 类型之一。接收到一个 Uint8Array 实例
当尝试使用 sign()
函数时,我收到上述错误,因为我的私钥是 Uint8Array
类型,唯一接受的类型是 KeyObject
或 CryptoKey
但我不不知道如何将 Uint8Arrays 转换为 KeyObjects
或 CryptoKeys
。
解决方法
您需要采用 Node.js 可识别的格式的密钥。 KeyObject create*Key API 识别并支持该密钥 - 对于 Ed25519 密钥,即假设 Node.js >= 16.0.0:
- SPKI 中的 PEM/DER 公钥
- PKCS8 中的 PEM/DER 用于私钥
- 公钥和私钥的 JWK
这是一个使用 DER 的片段。
import { SignJWT } from "jose/jwt/sign"
import { jwtVerify } from "jose/jwt/verify"
import bs58 from "bs58"
import { createPrivateKey,createPublicKey } from "crypto"
(async function main() {
const publicBase58 = "A77GCUCZ7FAuXVMKtwwXyFhMa158XsaoGKHYNnJ1q3pv";
const privateKeyBase58 = "BE1VM7rTRJReLsTLLG4JMNX5ozcp7qpmMuRht9zB1UjU";
let publicKey = bs58.decode(publicBase58);
let privateKey = bs58.decode(privateKeyBase58);
publicKey = createPublicKey({
key: Buffer.concat([Buffer.from("302a300506032b6570032100","hex"),publicKey]),format: "der",type: "spki",});
privateKey = createPrivateKey({
key: Buffer.concat([
Buffer.from("302e020100300506032b657004220420",privateKey,]),type: "pkcs8",})
const jwt = await new SignJWT({
subject: "uuid",})
.setProtectedHeader({ alg: "EdDSA" })
.setExpirationTime("2h")
.sign(privateKey);
console.log(await jwtVerify(jwt,publicKey))
})()
这是使用 JWK 的一个。
import { SignJWT } from "jose/jwt/sign"
import { jwtVerify } from "jose/jwt/verify"
import bs58 from "bs58"
import { createPrivateKey,createPublicKey } from "crypto"
(async function main() {
const publicBase58 = "A77GCUCZ7FAuXVMKtwwXyFhMa158XsaoGKHYNnJ1q3pv";
const privateKeyBase58 = "BE1VM7rTRJReLsTLLG4JMNX5ozcp7qpmMuRht9zB1UjU";
let publicKey = bs58.decode(publicBase58);
let privateKey = bs58.decode(privateKeyBase58);
publicKey = createPublicKey({
key: {
kty: "OKP",crv: "Ed25519",x: publicKey.toString("base64url")
},format: "jwk"
});
privateKey = createPrivateKey({
key: {
kty: "OKP",x: publicKey.toString("base64url"),d: privateKey.toString("base64url"),},format: "jwk"
})
const jwt = await new SignJWT({
subject: "uuid",publicKey))
})()