当前位置: 首页 > 知识库问答 >
问题:

无法验证节点中的RSA-PSS签名。js

孟胤
2023-03-14

我有一个JavaScript客户端和一个Node服务器。JS.我试图在客户端签署一个简单的文本,并将签名与公钥一起发送到服务器,然后服务器可以验证公钥。

客户端的任何东西都可以!但我无法在服务器端验证签名。我认为您没有必要阅读客户机代码,但为了保证,我也会提供它。

客户代码:

let privateKey = 0;
let publicKey = 0;
let encoded = '';
let signatureAsBase64 = '';
let pemExported = ''
function ab2str(buf) {
    return String.fromCharCode.apply(null, new Uint8Array(buf));
}

function str2ab(str) {
  const buf = new ArrayBuffer(str.length);
  const bufView = new Uint8Array(buf);
  for (let i = 0, strLen = str.length; i < strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
}
let keygen = crypto.subtle.generateKey({
  name: 'RSA-PSS',
  modulusLength: 4096,
  publicExponent: new Uint8Array([1,0,1]),
  hash: 'SHA-256'
  }, true, ['sign', 'verify']);

keygen.then((value)=>{
    publicKey = value.publicKey;
    privateKey = value.privateKey;
    let exported = crypto.subtle.exportKey('spki', publicKey);
    return  exported
}).then((value)=>{
    console.log('successful');
    const exportedAsString = ab2str(value);
    const exportedAsBase64 = btoa(exportedAsString);
    pemExported = `-----BEGIN PUBLIC KEY-----\n${exportedAsBase64}\n-----END PUBLIC KEY-----`;
    //signing:
    encoded = new TextEncoder().encode('test');
    let signing = crypto.subtle.sign({
          name: "RSA-PSS",
          saltLength: 32
      },
      privateKey,
      encoded);
    return signing;
}).then((signature)=>{
    const signatureAsString = ab2str(signature);
    signatureAsBase64 = btoa(signatureAsString);
    //verifying just to be sure everything is OK:
    return crypto.subtle.verify({
          name: 'RSA-PSS',
          saltLength: 32
      },
      publicKey,
      signature,
      encoded)
}).then((result)=>{
    console.log(result);
    
    //send information to server:
    let toSend = new XMLHttpRequest();
    toSend.onreadystatechange = ()=>{
       console.log(this.status);
    };
    toSend.open("POST", "http://127.0.0.1:3000/authentication", true);
    let data = {
      signature: signatureAsBase64,
      publicKey: pemExported
    };
    toSend.setRequestHeader('Content-Type', 'application/json');
    toSend.send(JSON.stringify(data));
    
    //to let you see the values, I'll print them to console in result:
    console.log("signature is:\n", signatureAsBase64);
    console.log("publicKey is:\n", pemExported);
}).catch((error)=>{
  console.log("error",error.message);
})

服务器代码(为此我使用express):

const express = require('express');
const crypto = require('crypto');
const router = express.Router(); 

function str2ab(str) {
  const buf = new ArrayBuffer(str.length);
  const bufView = new Uint8Array(buf);
  for (let i = 0, strLen = str.length; i < strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
}

router.post('/authentication',  async (req, res)=>{
    try{
        const publicKey = crypto.createPublicKey({
            key: req.body.publicKey,
            format: 'pem',
            type: 'spki'
        });
        console.log(publicKey.asymmetricKeyType, publicKey.asymmetricKeySize, publicKey.type);
        let signature = Buffer.from(req.body.signature, 'base64').toString();
        signature = str2ab(signature);
        const result = crypto.verify('rsa-sha256', new TextEncoder().encode('test'),
                        publicKey, new Uint8Array(signature));
        console.log(result);
    }catch(error){
        console.log('Error when autheticating user: ', error.message);
    }
})

服务器控制台日志:

rsa undefined public
false

注:

  1. 我认为在服务器中正确导入了公钥,因为当我在服务器中再次导出公钥时,双方(客户端)的pem格式

为什么要验证服务器中的公钥?

为什么不在客户端使用X库?

共有1个答案

孟雪风
2023-03-14

验证失败有两个原因:

>

  • 必须显式地指定PSS填充,因为PKCS#1 v1.5填充是默认的。

    签名转换会损坏数据:行:

    let signature = Buffer.from(req.body.signature, 'base64').toString();
    

    执行UTF8解码,s.here,这将不可逆地更改数据s.here。签名由通常与UTF8不兼容的二进制数据组成。只有使用合适的二进制到文本编码(如Base64、hex等),才能转换为字符串
    但除此之外,实际上根本不需要进行转换,因为签名可以作为缓冲区直接传递。

    以下NodeJS代码执行成功的验证(用于与客户端代码一起生成的签名和公钥):

    const publicKey = crypto.createPublicKey(
        {
            key: req.body.publicKey,
            format: 'pem',
            type: 'spki'
        });
    
    const result = crypto.verify(
        'rsa-sha256', 
        new TextEncoder().encode('test'), 
        {
            key: publicKey, 
            padding: crypto.constants.RSA_PKCS1_PSS_PADDING
        }, 
        Buffer.from(req.body.signature, 'base64'));
    
    console.log(result); // true
    

  •  类似资料:
    • 我正在处理C RPC客户端。我需要使用OpenSSL对mime数据进行签名,并将公钥和签名发送到服务器。Java将尝试使用公钥验证签名。 问题是,JAVA无法验证OpenSSL生成的签名,但可以验证JAVA生成的签名。你知道如何修复我的c客户端代码吗? C客户端代码: JAVA代码:

    • 我已经把它归结为我能做的最简单的测试用例。我需要获取Python中生成的RSASSA-PSS签名,并在Go中验证它们。创建RSA密钥对并用其签名的Python代码如下: 那里引用的pycrypto_keys库可以在这里找到,用于参考函数和的具体实现。 我的Go测试由两个简单的文件组成,这些文件只依赖于核心包。首先是验证功能,verify.go: 第二,一个测试用例。密钥对和签名是使用顶部的Pyth

    • 我无法使用Crypt::RSA和Crypt::RSA::SS::PSS在Perl中验证PSS签名。 字符串“hello”是由设备签名的缓冲区。 “pubkey.pem”是设备的RSA公钥,用PEM_write_RSA_PUBKEY()从设备导出。 “hello.sig”包含由设备生成的二进制(原始)签名。(因为有填充,所以是128字节。) 我试图在Perl中使用crypt::rsa和crypt::

    • 我已经使用Node rsa在Node中生成了一对私钥和公钥,并且可以在Node中使用这些密钥成功地进行签名和验证。 我尝试使用公钥的模和指数来验证中的签名(由节点中的私钥签名)。网 e、 g.我有一个string=“foo”,它有一个由Node生成的签名“abc123”。在里面NET我想使用公钥的模和指数来确认签名“abc123”对“foo”有效。 我想使用模数和指数而不是直接使用公钥的原因是因为

    • 我们为RSA签名创建了调试公钥和私钥,并生成sha256哈希并保存在cp1.bin中。然后我们尝试验证签名,但总是失败。如果我们不使用pss填充,验证命令将通过。任何人都可以帮忙评论吗? 谢谢 C:\Project\pkc C:\Project\pkc

    • 我在理解RSA签名和验证的概念方面有一个小问题。问题是我可以创建密钥对(公钥和私钥),这是完全好的。 签名和验证如下: 当我打印myPrivateKey和myPublicKey时,我看到公钥和私钥的模(n)和公钥指数(e)是相同的。 我已经将公钥和私钥转换为base64和hex,我得到了不同的值,这是非常好的。但是,我不能用base64或十六进制对消息进行签名。我只能用我从这里得到的东西来签名: