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
    Sep 28, 2019 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
    Sep 28, 2019 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
    Sep 28, 2019 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, 2019 at 9:18

1 Answer 1

  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
    Sep 28, 2019 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, 2019 at 10:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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