I'm using a bcryptjs to generate a computationally slow hash function for storing passwords:

BCRYPT.hash(plainTextPassword, HASH_ROUNDS_NUM);

Now I want to add a pepper before a hash is calculated:

BCRYPT.hash(pepperedPassword, HASH_ROUNDS_NUM);

where pepperedPassword = plainTextPassword + PEPPER;


  1. Should I represent a PEPPER as a string or as a buffer?

  2. To calculate a pepperedPassword I can either just concatenate two values:

pepperedPassword = concate(plainTextPassword, PEPPER);

or concatenate them and then calculate a fast hash of it (in addition to bcrypt):

const concatPassPepp = concate(plainTextPassword, PEPPER);

const hashedConcatPassPepp  = crypto.createHash("SHA3-512").update(concatPassPepp, "utf8").digest("base64");

Is it a useful idea to calculate a fast hash of password-pepper concatenation before sending it to bcrypt? Which scenario should I prefer?

Both questions are asked from security and performance point of view.

  • $\begingroup$ @kelalaka, I'm using bcryptjs , so no homemade, no new, regarding complexity I'm not sure if bcrypt(hash(pass+pepper)); can still be considered as keep it simple solution. Should I move the question to OS? $\endgroup$ – Mike B. Sep 28 '19 at 8:53
  • $\begingroup$ @kelalaka, the point of salt — to fight the repeating hashes due to pass entropy and, as a result, to protect against dictionary attack. The point of pepper — additional protection based on a «not put all eggs one basket» principle, do not store everything required for a hashing in on place, in a DB. Please fix me, if I'm getting wrong. $\endgroup$ – Mike B. Sep 28 '19 at 8:58
  • $\begingroup$ @kelalaka, regarding "You used pepper instead of salt", as far as i understand, bcryptjs.hash() generates salt automatically, at least that what's written in documentation: npmjs.com/package/bcryptjs#usage---async (Auto-gen a salt and hash). So, the only thing I need to add — the pepper, which must come from a secret place, e.g. app. configuration file. $\endgroup$ – Mike B. Sep 28 '19 at 9:10
  • 1
    $\begingroup$ Sorry, I've miss read. Here a question from Information Security and it is very similar to yours. $\endgroup$ – kelalaka Sep 28 '19 at 9:18
  1. To calculate a pepperedPassword I can either just concatenate two values:

Bcrypt limits the password. This means that if the password is too long (longer than 56 bytes), it will simply be truncated. If you just attach the pepper to the password, there is a high risk that this will happen. Then the pepper's security gain could even be lost without being noticed.

Use HMAC or even a hash function to combine a password and a pepper.

  1. Should I represent a PEPPER as a string or as a buffer?

That's up to you, but if you use HMAC or a hash function, it's obvious not to use a string.

  • $\begingroup$ Thanks for the detailed explanation. Regarding "it's obvious not to use a string", what is the problem to send a plain string to a hash function, e.g. crypto.createHash(ALG_HASH).update(data, ENC_IN).digest(ENC_OUT)? Should I always send a data to update() as Buffer? Does it give a performance boost? $\endgroup$ – Mike B. Sep 28 '19 at 10:13
  • 1
    $\begingroup$ There is no problem to use a string, if the hash function provides it. Otherwise you must always use the same character set (e.g. UTF-8) or the hash will fail. I think using a buffer is less error prone. $\endgroup$ – BeloumiX Sep 28 '19 at 10:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.