Search code examples
phpnode.jsrsaphpseclibphp-openssl

Encrypt and sign in Nodejs, validate signature in php


I would like to encrypt and sign certain data in nodejs and validate the signature in php. I keep on getting this error:

error:04091077:rsa routines:int_rsa_verify:wrong signature length

I have tried to change the algorithm being used, Also tried php extension such as phpseclib. In Nodejs am using the "crypto": "^1.0.1". Also this openssl_verify in php.

Here is my nodejs code

const crypto = require('crypto');

module.exports = {

    generateKey: () => {


    return   { publicKey, privateKey } = generateKeyPairSync('rsa', {
            modulusLength: 2048,
            publicKeyEncoding: {
                type: 'spki',
                format: 'pem'
            },
            privateKeyEncoding: {
                type: 'pkcs8',
                format: 'pem',

            }

      });
    },

    encryptMessage: (message) => {
        const config = new Configstore(packageJson.name);
        const algorithm = 'aes-256-cbc';
        const key = config.get('serverKey');
        const iv = crypto.randomBytes(16);
        let cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv);
        let encrypted = cipher.update(message);
        encrypted = Buffer.concat([encrypted, cipher.final()]);

        return { iv: iv.toString('hex'), encryptedData: encrypted.toString('hex')};

    },

    signMessage: (message) => {
        console.log(message);
        const config = new Configstore(packageJson.name);
        const sign = crypto.createSign('SHA256');
        sign.update(message);
        sign.end();
        const signature = sign.sign(config.get('privateKey'),'base64');

        const verify = crypto.createVerify('SHA256');
        verify.update(message);
        verify.end();
        console.log(config.get('publicKey'));
        console.log('Its working: ' + verify.verify(config.get('publicKey'), signature, 'base64'));
        return signature;
    }

}

Here is php:

public function saveSecreteMessage(Request $request) {

        $request->validate([
            'username' => 'required',
            'secretName' => 'required',
            'secretMessage' => 'required'
        ]);

        $publicKey = User::where('username', $request->input('username'))->first();

        if (!$publicKey) {
            return response()->json('Not allowed', 401);
        }

        $data = $request->input('secretMessage')['encryptedData'];
        $signature = $request->input('secretMessage')['signature'];

    /*    $rsa = new RSA();
        $rsa->loadKey($publicKey->publicKey); // public key;
        return $rsa->verify('message', $signature, 'base64') ? 'verified' : 'unverified';*/

        $ok = openssl_verify(base64_encode($data),  base_path($signature), $publicKey->publicKey, 'SHA256');

        if ($ok == 1) {
            return response()->json('', 200);
        } else {
            return response()->json(openssl_error_string(), 400);
        }

        $pet = $request->all();
        return $pet;
    }

I expect the php code to validate the signature sent over from nodejs. I can't seem to get it to work. The error I get is:

error:04091077:rsa routines:int_rsa_verify:wrong signature length


Solution

  • I got it working.

    JS code:

    const crypto = require('crypto');
    
    keyPair = crypto.generateKeyPairSync('rsa', {
                modulusLength: 2048,
                publicKeyEncoding: {
                    type: 'spki',
                    format: 'pem'
                },
                privateKeyEncoding: {
                    type: 'pkcs8',
                    format: 'pem',
    
                }
    
          });
    
    var message = "zzzz";
    
    const sign = crypto.createSign('SHA256');
    sign.update(message);
    sign.end();
    
    const signature = sign.sign(keyPair.privateKey,'base64');
    
    console.log(keyPair.publicKey);
    console.log(signature);
    

    PHP code:

    $rsa = new RSA;
    $rsa->loadKey('-----BEGIN PUBLIC KEY-----
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1e4Gi38Dlyl41RSGnQAK
    UsHONpX806tFD3fuOby3JQlhlDM+Pe/H8y6E/zMDtNSZXtO+QCqghtMLDVG2br9e
    i8uvGFwxLFUaWVkOYY7Tz21vJYYclvn67y0fJE8jgKUOdl3fgv/H3IGRVTROOetH
    4oMpHMTGRpjZFfI6mi7CSDiaR8D1EpmPeXJn8yYPHK4uDn5srhZDQTvXXwbYkskX
    FjbSx3yKvu1wkwKbKU5GkbBCzsFlNDhlCN4fvZ9SjinnV1iARgB80qIQlQ6JAUpp
    xM/bTUntjI73DHCF3dXv9pbwn6w/vfjoyxstwAzgp+7C8HuaVm12KOeKG5Lsbj/L
    XwIDAQAB
    -----END PUBLIC KEY-----');
    
    $plaintext = 'zzzz';
    $signature = base64_decode('Vzc+63A5nAZWwIPD99pJQkzR7JfOhG0xyaTQh+Pel2wWklnzN9lTibwhliJs7tyZlJzjZrhgS2reTDd26HqLw11RDbqMCxim/InOiuFPbOg8EgNt55mNyfICszt+2ZVa1Mjm8zXpFBvNee5EPPFbqoCRKUpulDiGwRVz8v6rgSrx+Ptl11dIXyQuTa90bTdJEHiGK73F/uPh/B9AQOVYkoJKA4GC8H7pC3+AiTBREeBfRZp7gMF3wq2pYS5ffGemxsIkKuVoDurVNSJL9xWF10H3nn0egpIDwDQLYdilrVAUW7z+Qu6lQ2FxNiFSX0TT6gL02WN5/UxCVokCSnufkg==');
    
    $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
    $rsa->setHash('sha256');
    
    echo $rsa->verify($plaintext, $signature) ? 'good' : 'bad';