Search code examples
node.jscryptographypublic-key-encryptionverification

Verify signature on a file nodejs


I don't understand why verify always returns false for me... running openssl will return that everything is just dandy

$ openssl dgst -md5 -verify mykey.pub -signature signature message.txt
Verified OK

However, running my code in the node results in the verification to be false

var fs = require('fs');
var path = require('path');
var crypto = require('crypto');

//pass in arguments
var args = process.argv.slice(2);
fs.readFile(args[0], 'ascii', function(err,signature){
    if(err){console.log(err);}
    fs.readFile(args[1], 'ascii', function(err,message){
        if(err){console.log(err);}
        fs.readFile(args[2], 'ascii', function(err,publickey){
            if(err){console.log(err);}
            verify(signature, message, publickey);
        });
    });
});

//verify function
var verify = function(signature, message, publickey){
    //everything prints out right
    console.log(signature.toString() + '\n');
    console.log(message.toString() + '\n');
    console.log(publickey.toString() + '\n');

    //using md5
    var verifier = crypto.createVerify('md5');

    verifier.update(message.toString());
    var WHAT = verifier.verify(publickey.toString(), signature.toString(), 'binary');
    console.log(WHAT);
};

Looking at the output results in this

$ node verifyHash signature message.txt mykey.pub
B`⌂ pgfs☼st;3_V1I☻l♂[V5 =C♠~o▲§►rH`KZ7#♦♠LiQ⌂xFw
▼♣"↓d;.H4+↕$WZF▲◄Ow▲r⌂,
j]U↕6►vQm$7v&^^uF↨/ma2F→*n
►¶o'$jN!☼↑☺aV+↔e^qH▲A►rmx.

HEllo

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDgn0PrHxivu0zgG8pp66yMwxJ
MyYsdocVNpZ+673WlRlN0NKQRkI7+F7rYMG4KWL0pDBeOahOggxNVTNV9cxkCKce
Gp37+ZED5HiHKDll4tVoGVSDLaW0BBVe1TzfJSS64fvN/OssyjKffD5ExpLE4O5o
Vv7robQ0JxzYfbz2FQIDAQAB
-----END PUBLIC KEY-----

false

What am I doing wrong?


Solution

  • You cannot read the signature as ASCII, as it contains binary data (byte values > 128). These will get stripped then [1].

    As the verifier is a stream.Writable the easiest solution is to use fs.createReadStream and then pipe to pipe it into the verifier.

    See this REPL transcript:

    > crypto = require('crypto'); undefined
    undefined
    > fs = require('fs'); undefined
    undefined
    > verifier = crypto.createVerify('md5'); undefined
    undefined
    > fs.createReadStream('file').pipe(verifier); undefined
    undefined
    > verifier.verify(fs.readFileSync('publickey.pem'), fs.readFileSync('signature.sign'), 'binary');
    true
    

    [1]

    > new Buffer(fs.readFileSync('signature.sign', 'binary')).toString('hex');
    '3632c3a6c28dc2806fc2bb563dc3bb51c38b537dc2871ac394c288405dc2b87634c2b5c3be53157273c2bfc3acc2b9c398c2a05e506ec3a6c3b2c2a9c3bf4bc280c28133c298c281c39a07c3acc2a612c2b0c2bec38fc28ac2bbc2b941504fc3bc22c2a0c3910325c38c5f581d4c7f4fc3a3c389c2b4c3b72e36c29b3d29c295c2b4c28755c38158c3af0f0e08c3bbc29f3bc3bc5e57c288c29d287ec3bf1bc39864c2867cc3867bc3a03ec3bd5a2806c3bd55c2a0c29a12c3aac2b675c284500504c38832c291c383c3b933222961c2b3c3bac2a3583737c3861cc392c39373c2bac298c2b96b6c1dc29f3fc2b1c387c397c39719c29fc39ec28c02c29d3cc396c2abc3923bc28e621032c3bec298c2a877c3bbc2ae6fc38cc3b4c2b1c387c390c39d03753bc28ac2b0c2b64f3fc3a7c3a254c398c3b91ec2935922c3aac2bdc2aa41c295c39519c2b8c3bdc2a02d74c2bfc38ec3aa60c2b87c433e1dc28b2351c3b8c2b54a237cc29703521dc3a3c2b34958c2a4c3a9c2a410c2b8c39e5dc3af2c6a27c2987e'
    > new Buffer(fs.readFileSync('signature.sign', 'ascii')).toString('hex');
    '3632660d006f3b563d7b514b537d071a5408405d387634357e531572733f6c3958205e506e6672297f4b00013318015a076c2612303e4f0a3b3941504f7c22205103254c5f581d4c7f4f634934772e361b3d291534075541586f0f0e087b1f3b7c5e57081d287e7f1b5864067c467b603e7d5a28067d55201a126a367504500504483211437933222961337a23583737461c5253733a18396b6c1d1f3f31475757191f5e0c021d3c562b523b0e6210327e1828777b2e6f4c743147505d03753b0a30364f3f67625458791e1359226a3d2a41155519387d202d743f4e6a60387c433e1d0b235178354a237c1703521d6333495824692410385e5d6f2c6a27187e'