【问题标题】:Sign and verify JWS (json web signature) with Ed25519 KeyPair使用 Ed25519 KeyPair 对 JWS(json web 签名)进行签名和验证
【发布时间】:2021-10-07 06:20:27
【问题描述】:

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

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

当尝试使用 sign() 函数时,我收到上述错误,因为我的 privateKey 是 Uint8Array 类型,唯一接受的类型是 KeyObjectCryptoKey 但我不知道如何转换我的Uint8Arrays 转换成KeyObjectsCryptoKeys

我从这个answer得到了一些代码sn-ps

【问题讨论】:

标签: javascript node.js jwt ed25519


【解决方案1】:

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

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

这是一个使用 DER 的 sn-p。

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))
})()

【讨论】:

  • 谢谢,“der”格式适用于我的情况。有没有办法从签名密钥中读取有效负载,而无需先验证它?我想将用户的 id 存储在有效负载中,使用该 id 可以获得存储在 DLT 上的 publicKey。
  • 在验证令牌之前处理数据本质上是危险的。因此,该库不提供此类方法。
  • 话虽如此简单,就像JSON.parse(Buffer.from(jwt.split('.')[1], 'base64'))
猜你喜欢
  • 2021-10-07
  • 2020-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-11
  • 2023-04-08
  • 1970-01-01
相关资源
最近更新 更多