使用 Ed25519 KeyPair 签署和验证 JWSjson 网络签名

问题描述

我想使用通过 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 类型,唯一接受的类型是 KeyObjectCryptoKey 但我不不知道如何将 Uint8Arrays 转换为 KeyObjectsCryptoKeys

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

解决方法

您需要采用 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))
})()

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...