使用 Ed25519 密钥对签署并验证 JWS(json Web 签名)

Jon*_*vin 5 javascript node.js jwt ed25519

我想使用通过 Ed25519 在客户端设备上生成的私钥来签署 JWS(json Web 签名)。然后将此签名发送到我的后端并使用公钥进行验证。为了熟悉该过程,我想尝试在 Node 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);
}
Run Code Online (Sandbox Code Playgroud)

错误:类型错误:密钥必须是 KeyObject 或 CryptoKey 类型之一。收到一个 Uint8Array 的实例

当尝试使用该sign()函数时,我收到上面的错误,因为我的 privateKey 类型为Uint8Array,唯一接受的类型是KeyObjector CryptoKey,但我不知道如何将我的 Uint8Arrays 转换为 KeyObjectsor CryptoKeys

我从这个答案中得到了一些代码片段

小智 4

您需要 Node.js 能够识别的格式的密钥。KeyObject create*Key API 可以识别并且该密钥受 - 对于 Ed25519 密钥的支持,即假设 Node.js >= 16.0.0:

  • SPKI 中的 PEM/DER 用于公钥
  • PKCS8 中的 PEM/DER 用于私钥
  • JWK 用于公钥和私钥

这是使用 DER 的代码片段。

import { SignJWT, jwtVerify } from "jose"
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", "hex"),
      privateKey,
    ]),
    format: "der",
    type: "pkcs8",
  })

  const jwt = await new SignJWT({
    subject: "uuid",
  })
    .setProtectedHeader({ alg: "EdDSA" })
    .setExpirationTime("2h")
    .sign(privateKey);

  console.log(await jwtVerify(jwt, publicKey))
})()
Run Code Online (Sandbox Code Playgroud)

这是使用 JWK 的一个。

import { SignJWT, jwtVerify } from "jose"
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",
      crv: "Ed25519",
      x: publicKey.toString("base64url"),
      d: privateKey.toString("base64url"),
    },
    format: "jwk"
  })

  const jwt = await new SignJWT({
    subject: "uuid",
  })
    .setProtectedHeader({ alg: "EdDSA" })
    .setExpirationTime("2h")
    .sign(privateKey);

  console.log(await jwtVerify(jwt, publicKey))
})()
Run Code Online (Sandbox Code Playgroud)