How to Sign data and Verify signature in Node.JS

Another example that occurred to me. Very useful.

What will we need?

  • Private key in PEM format
  • Public key in PEM format

To get those you will have use OpenSSL, please take a look at this post How to generate RSA public and private keys with OpenSSL.

For this example I am using the following 2048 bit RSA key pair:

E:\NodeJS>more RSA_2048_Private_Key.pem
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAumzAyljzEcgO/xxbyXn8oy5lj2rhfSj/NitpHBHJcapytHb8
D9VaFibhZgtkbb5iPCn4vx1IWRdwdMtdKvtzUEqvPuAxSJmyE/zs/VRgxID5AWT/
ZJQ6ikM+wHN0fwIJu2Ue/AhWPDZVuQvUhkh+wU5jd0qtXBuQybHRnGAKtvae9Nyq
52I6azbIwZ1x7auHoyC5RaYayW7WLrqVQPQeUL87uPe/P1g/9aQP4r5egXsCeWyn
eK1GDwhxGKqHj/cfwwGBi5S1QxDM72XoJmh2x+OoGFQ5menCUKFSacRTHxac1uQZ
4Z1MxHvA3qBIYB3ip853+rXSGXrGVkn4C5OyTwIDAQABAoIBAQCiBuOI+sZILhja
oUslUWDCcxDSFZLltTwbWJ+CRfNPV1VahA+Ps18Y4bIFfuFKgK3gnJoVgN3gkP6s
hBP1x5XxsvedLj2nW+3qcWmIxE1WfMHu9FkEkdBPWyKvIameuaa7uKe1ZYmNy6u1
qRKNo3SHjhnlFIKYC11L78C+qLqnSTYbcjn25D7pDcNc50vjxKFiXb6Vj10WlD7l
KUjI5AixerWR7XKeYC11l3YB2fWtgUqOC8bbjd9LrT9+bY1TrSnEOR+ZgWd1AI1F
6Gna9KkcUZ6NR2N6JWp13Lf+fUyjI3dRPqwlXWuDb7KsbxRsX1SeI59E2EV9XHPT
wXsGa6gBAoGBANyRSfW4HfxPMmyyk27khPHLcZ8pVbjOZG7wrdUlPNsJbTXz67qt
mp+aa0V2LXeUPBSGls4VkWtXptpqxERltYdIH5I6LdWhMNCd8SsteBLzlD/7QVTi
qIODR6onjVkLoLijxDpEDbACUgr3xinQ/uy9wm36EOBv2f/A1RZtRzoZAoGBANhf
XWXmEfONALVSuwPZVAJlNP6N3omBJaHzXs8gsSSxKCOgpZjwSjq4rtCjbv+hWW2X
jY62JMtbR6aXQtRrAAZsoaFIn9JxqL+Y1lI+H4tyiT7XlPm06ez9WpoKv45aSqBe
ByXs6CE2iPbINd9xQulE+e3rZZ3crOxV76MqNKynAoGAXcYrcpuXrAijwJDfm7ru
RrqfEPMK7epZyszqqv8M83b7hn+wzgo2/fox9zM6O2e7b2KVRQLoc4Gtf5j63rV7
Swu/2HSBvhys21T7DsdjEHOcqOMSsJs418j9s/ri3mPSLg36RGdghl9GMEGNb4Pa
jh5TRlyVxkXnohOCxOkq6ikCgYEAuYNaUsmlzomwd8aM7cniC4O2oiIFESQXnflJ
6pD/EJSL87ADC1PKcPpzeBMIUkiGoj30cs2cUnbaweyisfljth5hniTkUsx8gHmM
GEuHREpZffXclxQUFMtMaRKaFnU30rOLsWqjxAY7/ErAVemIEvS+zMys/WJ9KMyt
f9np+7UCgYAQYdD2w4L2Sj6XSHawNnWCkwvSgBGyWTm9O38AmVmPRZqnqJRzFQak
hvBbU2xLM0SxpzFjSilcep30sxL2nuZxJ0PNiMrbVnaBkfZa1Z7qWQhwpwYYVaOW
TyHY5ro31mmlF/dJ+APvD/DHbgFG9R/dKcf9fZ+MXEunci17cRpbzw==
-----END RSA PRIVATE KEY-----

E:\NodeJS>more RSA_2048_Public_Key.pem
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAumzAyljzEcgO/xxbyXn8
oy5lj2rhfSj/NitpHBHJcapytHb8D9VaFibhZgtkbb5iPCn4vx1IWRdwdMtdKvtz
UEqvPuAxSJmyE/zs/VRgxID5AWT/ZJQ6ikM+wHN0fwIJu2Ue/AhWPDZVuQvUhkh+
wU5jd0qtXBuQybHRnGAKtvae9Nyq52I6azbIwZ1x7auHoyC5RaYayW7WLrqVQPQe
UL87uPe/P1g/9aQP4r5egXsCeWyneK1GDwhxGKqHj/cfwwGBi5S1QxDM72XoJmh2
x+OoGFQ5menCUKFSacRTHxac1uQZ4Z1MxHvA3qBIYB3ip853+rXSGXrGVkn4C5Oy
TwIDAQAB
-----END PUBLIC KEY-----

How to do it?

Easy, here is the code:

var crypto = require('crypto');
var fs = require('fs');
var ALGORITHM = "sha384"; // Accepted: any result of crypto.getHashes(), check doc dor other options
var SIGNATURE_FORMAT = "hex"; // Accepted: hex, latin1, base64

function getPublicKeySomehow() {

    var pubKey = fs.readFileSync('RSA_2048_Public_Key.pem', 'utf8');
    console.log("\n>>> Public key: \n\n" + pubKey);

    return pubKey;
}

function getPrivateKeySomehow() {

    var privKey = fs.readFileSync('RSA_2048_Private_Key.pem', 'utf8');
    console.log(">>> Private key: \n\n" + privKey);

    return privKey;
}

function getSignatureToVerify(data) {

    var privateKey = getPrivateKeySomehow();
    var sign = crypto.createSign(ALGORITHM);
    sign.update(data);
    var signature = sign.sign(privateKey, SIGNATURE_FORMAT);

    console.log(">>> Signature:\n\n" + signature);

    return signature;
}

var publicKey = getPublicKeySomehow();
var verify = crypto.createVerify(ALGORITHM);
var data = "This message will be signed with a RSA private key in PEM format and then verified with a RSA public key in PEM format.";
var signature = getSignatureToVerify(data);

console.log('\n>>> Message:\n\n' + data);

verify.update(data);

var verification = verify.verify(publicKey, signature, SIGNATURE_FORMAT);

console.log('\n>>> Verification result: ' + verification.toString().toUpperCase());

Your console output should look similar to this:

E:\NodeJS>node verifySignature.js

>>> Public key:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAumzAyljzEcgO/xxbyXn8
oy5lj2rhfSj/NitpHBHJcapytHb8D9VaFibhZgtkbb5iPCn4vx1IWRdwdMtdKvtz
UEqvPuAxSJmyE/zs/VRgxID5AWT/ZJQ6ikM+wHN0fwIJu2Ue/AhWPDZVuQvUhkh+
wU5jd0qtXBuQybHRnGAKtvae9Nyq52I6azbIwZ1x7auHoyC5RaYayW7WLrqVQPQe
UL87uPe/P1g/9aQP4r5egXsCeWyneK1GDwhxGKqHj/cfwwGBi5S1QxDM72XoJmh2
x+OoGFQ5menCUKFSacRTHxac1uQZ4Z1MxHvA3qBIYB3ip853+rXSGXrGVkn4C5Oy
TwIDAQAB
-----END PUBLIC KEY-----

>>> Private key:

-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAumzAyljzEcgO/xxbyXn8oy5lj2rhfSj/NitpHBHJcapytHb8
D9VaFibhZgtkbb5iPCn4vx1IWRdwdMtdKvtzUEqvPuAxSJmyE/zs/VRgxID5AWT/
ZJQ6ikM+wHN0fwIJu2Ue/AhWPDZVuQvUhkh+wU5jd0qtXBuQybHRnGAKtvae9Nyq
52I6azbIwZ1x7auHoyC5RaYayW7WLrqVQPQeUL87uPe/P1g/9aQP4r5egXsCeWyn
eK1GDwhxGKqHj/cfwwGBi5S1QxDM72XoJmh2x+OoGFQ5menCUKFSacRTHxac1uQZ
4Z1MxHvA3qBIYB3ip853+rXSGXrGVkn4C5OyTwIDAQABAoIBAQCiBuOI+sZILhja
oUslUWDCcxDSFZLltTwbWJ+CRfNPV1VahA+Ps18Y4bIFfuFKgK3gnJoVgN3gkP6s
hBP1x5XxsvedLj2nW+3qcWmIxE1WfMHu9FkEkdBPWyKvIameuaa7uKe1ZYmNy6u1
qRKNo3SHjhnlFIKYC11L78C+qLqnSTYbcjn25D7pDcNc50vjxKFiXb6Vj10WlD7l
KUjI5AixerWR7XKeYC11l3YB2fWtgUqOC8bbjd9LrT9+bY1TrSnEOR+ZgWd1AI1F
6Gna9KkcUZ6NR2N6JWp13Lf+fUyjI3dRPqwlXWuDb7KsbxRsX1SeI59E2EV9XHPT
wXsGa6gBAoGBANyRSfW4HfxPMmyyk27khPHLcZ8pVbjOZG7wrdUlPNsJbTXz67qt
mp+aa0V2LXeUPBSGls4VkWtXptpqxERltYdIH5I6LdWhMNCd8SsteBLzlD/7QVTi
qIODR6onjVkLoLijxDpEDbACUgr3xinQ/uy9wm36EOBv2f/A1RZtRzoZAoGBANhf
XWXmEfONALVSuwPZVAJlNP6N3omBJaHzXs8gsSSxKCOgpZjwSjq4rtCjbv+hWW2X
jY62JMtbR6aXQtRrAAZsoaFIn9JxqL+Y1lI+H4tyiT7XlPm06ez9WpoKv45aSqBe
ByXs6CE2iPbINd9xQulE+e3rZZ3crOxV76MqNKynAoGAXcYrcpuXrAijwJDfm7ru
RrqfEPMK7epZyszqqv8M83b7hn+wzgo2/fox9zM6O2e7b2KVRQLoc4Gtf5j63rV7
Swu/2HSBvhys21T7DsdjEHOcqOMSsJs418j9s/ri3mPSLg36RGdghl9GMEGNb4Pa
jh5TRlyVxkXnohOCxOkq6ikCgYEAuYNaUsmlzomwd8aM7cniC4O2oiIFESQXnflJ
6pD/EJSL87ADC1PKcPpzeBMIUkiGoj30cs2cUnbaweyisfljth5hniTkUsx8gHmM
GEuHREpZffXclxQUFMtMaRKaFnU30rOLsWqjxAY7/ErAVemIEvS+zMys/WJ9KMyt
f9np+7UCgYAQYdD2w4L2Sj6XSHawNnWCkwvSgBGyWTm9O38AmVmPRZqnqJRzFQak
hvBbU2xLM0SxpzFjSilcep30sxL2nuZxJ0PNiMrbVnaBkfZa1Z7qWQhwpwYYVaOW
TyHY5ro31mmlF/dJ+APvD/DHbgFG9R/dKcf9fZ+MXEunci17cRpbzw==
-----END RSA PRIVATE KEY-----

>>> Signature:

2c8f6080b990da4a3949d5ecafa48f7eab76ae7bfe2b64613fc00351ff1243fe5dc147a54a66f104567e9982894e99193836892b37666a2ca633269c282083eb9b4e601acd962ce5543737
33c36fd0aefeb96e08e4ee6eef64068730824a723cdb8b0ed0815dbbceccaa350020d060208d4751b103d39accc607fff1f52c1eb4d79b0b0f60f66f0ee8107ee71a10dc3b1d5123d1fac1
4c2092c668043f82ed2d1d7a8b73e502d2115c0cc7f9800d84611d5fe4a47e57715676776eb3278caa9de5a4bbb6719ab4c90e950b427981aa7cadb0e7f10fe0cf27601b96c0b9a17f7762
450351902397a731712d86e675c4a7e5328fd415f911d974be5f8b0617d911

>>> Message:

This message will be signed with a RSA private key in PEM format and then verified with a RSA public key in PEM format.

>>> Verification result: TRUE

Please make sure you read carefully the Crypto documentation. You can learn a lot and save a lot of time solving a problem by just reading carefully. I hope this is helpful.

Sources: