gpt4 book ai didi

node.js - NodeJS Crypto 无法验证 Web Crypto API 创建的签名

转载 作者:太空宇宙 更新时间:2023-11-03 22:57:54 30 4
gpt4 key购买 nike

我在验证 Web Crypto API 创建的签名时遇到问题。

这是我用来在浏览器中生成 RSA key 的代码:

let keys;

const generateKeys = async () => {
const options = {
name: 'RSASSA-PKCS1-v1_5',
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: { name: 'SHA-256' },
};

keys = await window.crypto.subtle.generateKey(
options,
false, // non-exportable (public key still exportable)
['sign', 'verify'],
);
};

并导出公钥:

const exportPublicKey = async () => {    
const publicKey = await window.crypto.subtle.exportKey('spki', keys.publicKey);

let body = window.btoa(String.fromCharCode(...new Uint8Array(publicKey)));
body = body.match(/.{1,64}/g).join('\n');

return `-----BEGIN PUBLIC KEY-----\n${body}\n-----END PUBLIC KEY-----`;

// Output:
//
// -----BEGIN PUBLIC KEY-----
// MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAx7J3SUG4sq/HSGIaGZWY
// 8b26cfEpVFYHoDUDUORIJzA/fLE9aj+uOKpGUTSfW69rMm7DAOLDz05KaEJJSI5+
// YbDPr2S82A2ByHHQt+Vu168sGz4noXTTSX2HIdVutaR/IJ0a5pNOa1vRR4MUW/ZO
// YaRir3yC5YXgcFLwwQaifNZ3lZ7WndbYEjTGOcieQQ81IUP2221PZCJI52S95nYm
// VfslsLiPhOFH7XhGSqelGYDi0cKyl0p6dKvYxFswfKKLTuWnu2BEFLjVq4S5Y9Ob
// SGm0KL/8g7pAqjac2sMzzhHtxZ+7k8tynzAf4slJJhHMm5U4DcSelTe5zOkprCJg
// muyv0H1Acb3tfXsBwfURjiE0cvSMhfum5I5epF+f139tsr1zNF24F2WgvEZZbXcG
// g1LveGCJ/0BY0pzE71DU2SYiUhl+HGDv2u32vJO80jCDf2lu7izEt544a+XE+2X0
// zVpwjNQGa2Nd4ApGosa1fbcS5MsEdbyrjMf80SAmOeb9g3y5Zt2MY7M0Njxbvmmd
// mF20PkklpH0L01lhg2AGma4o4ojolYHzDoM5a531xTw1fZIdgbSTowz0SlAHAKD3
// c2KCCsKlBbFcqy4q7yNX63SqmI3sNA3kTH9CQJdBloRvV103Le9C0iY8CAWQmow5
// N/sDJUabgOMqe9yopSjb7LUCAwEAAQ==
// -----END PUBLIC KEY-----
};

要签署消息:

const generateHash = async (message) => {
const encoder = new TextEncoder();
const buffer = encoder.encode(message);

const digest = await window.crypto.subtle.digest('SHA-256', buffer);
return digest;
};

const signMessage = async (message) => {
const { privateKey } = keys;
const digest = await generateHash(message);
const signature = await window.crypto.subtle.sign('RSASSA-PKCS1-v1_5', privateKey, digest);
return signature;
};

要在浏览器中验证消息:

const verifyMessage = async (signature, message) => {
const { publicKey } = keys;
const digest = await generateHash(message);
const result = await window.crypto.subtle.verify('RSASSA-PKCS1-v1_5', publicKey, signature, digest);
return result;
};

创建 key 后,公钥将被导出并发送到服务器。后来:

const message = 'test';
const signature = await signMessage(message);
await verifyMessage(signature, message); // true

sendToServer(message, bufferToHex(signature));

由于签名是一个 ArrayBuffer,我使用以下代码将其转换为十六进制:

const bufferToHex = input => [...new Uint8Array(input)]
.map(v => v.toString(16).padStart(2, '0')).join('');

在服务器上(NodeJS 8.11.0):

const publicKey = getPublicKey(userId);

const verifier = crypto.createVerify('RSA-SHA256');
verifier.update(message, 'utf-8');

const sigBuf = Buffer.from(signature, 'hex');
verifier.verify(publicKey, sigBuf); // false

我已经追查这个问题好几天了,但似乎无法弄清楚。我尝试了 RSA-SHA256sha256WithRSAEncryption 进行验证,但无济于事。此外,不会引发任何错误。任何帮助将不胜感激!

最佳答案

所以我不完全理解为什么会出现这种情况,但为了解决这个问题,我需要将 SHA 哈希值从 ArrayBuffer 转换为十六进制字符串,然后使用 TextEncoder 读回数组缓冲区。

const generateHash = async (message) => {
const encoder = new TextEncoder();
const buffer = encoder.encode(message);

const digest = await window.crypto.subtle.digest('SHA-256', buffer);

// Convert to hex string
return [...new Uint8Array(digest)]
.map(v => v.toString(16).padStart(2, '0')).join('');;
};

然后签名时:

const signMessage = async (message) => {
const encoder = new TextEncoder();
const { privateKey } = keys;
const digest = await generateHash(message);
const signature = await window.crypto.subtle.sign('RSASSA-PKCS1-v1_5', privateKey, encoder.encode(digest));
return signature;
};

签名不再在客户端验证,而是在 Node 验证。 🤷‍♂️

关于node.js - NodeJS Crypto 无法验证 Web Crypto API 创建的签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55189704/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com