使用 Ed25519 KeyPair 签署并验证 JWS(json 网络签名)

Sign and verify JWS (json web signature) with Ed25519 KeyPair

我想在客户端设备上使用通过 Ed25519 生成的私钥签署 JWS(json 网络签名)。然后将此签名发送到我的后端并使用 public 密钥进行验证。 为了熟悉我想尝试在节点 js 中签署和验证 JWS 的过程。
我的私钥和 public 密钥都已经生成并且可以在 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);
}

错误:TypeError:密钥必须是 KeyObject 或 CryptoKey 类型之一。接收到 Uint8Array

的实例

尝试使用 sign() 函数时出现上述错误,因为我的私钥是 Uint8Array 类型,唯一接受的类型是 KeyObjectCryptoKey 但是我不知道如何将 Uint8Arrays 转换为 KeyObjectsCryptoKeys.

我从中得到了一些代码片段

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

  • PEM/DER 在 SPKI 中用于 public 个键
  • PEM/DER 在 PKCS8 中用于私钥
  • public 和私钥的 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))
})()

这是一个使用 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))
})()