Search code examples
javascriptnode.jsrsanode-crypto

How to verify file using rsa public key


I base my work on this answer

I'm trying to verify a file using a public key. Here is my code:

var hash = crypto.createHash("sha256");
hash.setEncoding("hex");
var fd = fs.createReadStream("path/to/my/file");
fd.on("end", function() {
    hash.end();
    var fileHash = hash.read();    
    const publicKey = fs.readFileSync('keys/public_key.pem');
    const verifier = crypto.createVerify('RSA-SHA256');
    const testSignature = verifier.verify(publicKey, fileSignature, 'base64');
    console.log("testSignature: \n" + testSignature);
    if (testSignature === fileHash)
        console.log("ok");
    else
        console.log("not ok");
});
fd.pipe(hash);

I don't know if this code is correct, but testSignature is equal to "false" when i printed it in the console. Why ?

testSignature:
false

The encrypted hash (the fileSignature variable) is correct. The base64 string is the same as I expect.

Any idea about what is wrong in my code ? Thanks

EDIT

Here is the code that generates the signature:

var hash = crypto.createHash("sha256");
hash.setEncoding("hex");
var fd = fs.createReadStream("path/to/file");
fd.on("end", function() {
    hash.end();
    var fileHash = hash.read();
    var privateKey = fs.readFileSync('keys/private_key.pem');
    var signer = crypto.createSign('RSA-SHA256');
    signer.update(fileHash);
    fileSignature = signer.sign(privateKey, 'base64');
});
fd.pipe(hash);

Solution

  • Assuming path/to/my/file is the file of which contents you need to verify, you have to provide its contents to verifier.update(). Try the following:

    const input = fs.readFileSync('path/to/my/file'); // load data contents
    const publicKey = fs.readFileSync('keys/public_key.pem').toString(); // load the signature, as a string!
    const verifier = crypto.createVerify('RSA-SHA256');
    verifier.update(input); // provide data contents to the verifier
    const testSignature = verifier.verify(publicKey, fileSignature, 'base64');
    console.log("testSignature: \n" + testSignature);
    

    Also, make sure that fileSignature is a string value and not a Buffer. For some reason, which I am still trying to figure why, if you pass a Buffer object to verifier.verify it will not work:

    const fileSignatureBuffer = fs.readFileSync('signature.sha256');
    const fileSignatureString = fileSignatureBuffer.toString();
    // load public key, create the verifier, provide data contents to verifier, etc.
    const testSignature = verifier.verify(publicKey, fileSignatureBuffer); // false
    const testSignature = verifier.verify(publicKey, fileSignatureString, 'base64'); // true
    

    EDIT: If you are using a hash as input to the signing step, then you have to pass the same hash in the verify step. Then code would look as follows:

    const publicKey = fs.readFileSync('keys/public_key.pem').toString(); // load the signature, as a string!
    const verifier = crypto.createVerify('RSA-SHA256');
    verifier.update(fileSignature); // provide the file signature to the verifier
    const testSignature = verifier.verify(publicKey, fileSignature, 'base64');
    console.log("testSignature: \n" + testSignature);