Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Digital signature with node.js crypto

Could someone provide a basic walkthrough on how to implement digital signature with node.js? I've googled but didn't get it yet. Say, I have an API and I wanna sign and verify every http request to it and response from it. That's how I currently imagine it, plz correct me where I'm wrong:

1) I need to generate a random enough key for client, which will be used to sign requests;

2) Resulting signature (provided via header) is an encrypted with that key hash of a string, which has to include:

  • hash of the request body (to prevent tampering);
  • timestamp;
  • nonce;
  • url;
  • HTTP verb

Then, the server would be able to check the authenticity of a message.

Questions:

1) What is the difference in this context between a nonce (some random value) and a timestamp (I've read a post where using both at the same time was advised)?

2) Do I need to include eTag header to that string?

3) What else, not listed above, should be included?

4) Should I keep the same key on the API server, as on client and decrypt and check requests with it, or should the key, stored on the API server, and the key, stored on the server, which communicates with API for a private-public keys pair? If they do need to be a private-public keys keypair, how do I decrypt what was encrypted with private key, using public key (and vice versa) in node?

Plz, correct what was wrong in my description and add, what I've missed. Thank you.

like image 709
Tristan Tzara Avatar asked Oct 23 '25 21:10

Tristan Tzara


2 Answers

Below code sample uses crypto library(now built in with nodejs) to generate digital signature for a document.

const crypto = require('crypto');
const fs = require('fs');

// See keys/README.md on how to generate this key
const private_key = fs.readFileSync('keys/privateKey.pem', 'utf-8');

// File/Document to be signed
const doc = fs.readFileSync('sample-doc.txt');

// Signing
const signer = crypto.createSign('RSA-SHA256');
signer.write(doc);
signer.end();

// Returns the signature in output_format which can be 'binary', 'hex' or 'base64'
const signature = signer.sign(private_key, 'base64')

console.log('Digital Signature: ', signature);

Here is the full code example from github : digital-signature-for-document-signing

like image 200
Nuwan Attanayake Avatar answered Oct 26 '25 12:10

Nuwan Attanayake


Amazon REST Authentication is good example to answer your question. AWS requires to "sign the request" applying a HMAC hash on the request data using a set of rules:canonicalization, encoding or timestamping. The signature is included in a Authorization header of the HTTP request

HMAC is a symmetric algorithm, client and server share the secret key, that is used in both sides to calculate the hash. If they match, then the request has been sent for an authorized party

An assymetric key also makes sense in this scenario. e.g. creating keypair at client side and sending the public key during registration. It is not needed that the server signs the response. Just using a TLS channel the client can trust in server validating server certificate ( TLS also provides channel privacity through encryption)

Using shared keys, it is needed to consider how to store secrets in a safe way, For example (as you propose), using a database, or encrypting secrets instead of plain ones with a master-key

All security solutions have a risk, even using HSM hardware. Consider risk-benefit. If you store the secret keys in DB, the system admin or someone who steals the DB password could get all of them. In some cases I've seen that is used a master encryption key stored in the machine (in fact some HSMs just manage this master key)

like image 31
pedrofb Avatar answered Oct 26 '25 10:10

pedrofb