1
$\begingroup$

Assume that, in the available environment, it is not possible to use modern password hashing functions (bcrypt, scrypt, Argon2, PBKDF2, etc.), so it is necessary to roll my own stand-in, until they become available. (Or call it a theoretical question, because either way I'll learn something from your answers.)

With a simple (uniterated) SHA256 of the password and a random 256-bit salt, when concatenating the salt and password, is it better to use the binary form of the salt, or is a base64 representation just as secure?

For example, with the salt, hard-wired to 256 bits, it will always end in a '=' in base64 (if the extra character isn't dropped). That seems like it's not ideal.

(Assume the salt is stored with the hashed password, both as base64, so concatenation is easy with that form.)

I Googled and searched here, without much that seemed related to the specific format of the salt when it's being concatenated. This question mentions a length extension attack, which I would think might be easier with the textual base64 salt. (Oh, and this question talks about nested hashes to address the length extension attack as well, but that doesn't seem to apply? and doesn't address the salt format.)

Is the salt format moot because the entropy of 32 binary bytes is the same as 42.7 base64 characters, or is one format really a better choice?

$\endgroup$
4
$\begingroup$

Is the salt format moot because the entropy of 32 binary bytes is the same as 42.7 base64 characters, or is one format really a better choice?

TLDR: moot, for the reason stated, as long as the whole thing is hashed and not otherwise used, and the hash used is secure, and the iterated hash construction on top of that is otherwise sound.

The fear that hashing constant bytes like =, or hashing characters from a reduced set such that of Base64, or hashing more bytes, could cause a cryptographic issue like a loss of entropy or increased risk of collision, is unfounded as long as all the data enters a good hash like SHA-256, and is not otherwise used: the loss of entropy, if any, is computationally undetectable. If it was, it would allow to distinguish the hash from a random function¹. Even though SHA-1 and MD5 are broken, they are sill safe from such problem, thus we can be quite confident about this for the stronger SHA-256.

Introducing a binary-to-text transformation (e.g. Base64) as a pre-processigng of the salt:

  • Slow downs the function, and that slow down benefits the attacker (which will perform the transformation only once in a password search attack). But for a well-parametrized function, that slowdown is negligible.
  • Increases the length of the salt as effectively used (at least it should: again truncation would be bad). If the salt was repeatedly hashed in the iterated hash (wjich is possible but not usual), that may slow down the iterated hash sizably (especially if the transformation reaches a threshold requiring more compression rounds per iteration), both for the attacker and legitimate user, thus
    • if the number of iterations is kept identical, the binary-to-text transformation will make the iterated hash slower, thus safer, but more costly for the legitimate user.
    • if the number of iterations is adjusted for constant duration, then there will be less difference in security (and we can't tell in which direction)

There can be other side effects. For example, when the key input of HMAC-SHA-256 (a common building block in iterate hash function) exceeds 64 bytes, that key is replaced by its 32-byte SHA-256 hash, requiring at least two extra compression rounds. Thus adding one byte to the key input can abruptly increase duration (and reduce the entropy from up to 512 bit to less than 256, but it's not a worrying security issue).


Notice that since Colin Percival's Stronger Key Derivation via Sequential Memory-Hard Functions (presented at BSDCan 2009), a decent iterated password hashing function must use sizable RAM memory, and ideally be memory-hard (that is, massively parallel implementation should require that same sizable amount of memory for each instance running). It considerably raises the cost of a password search setup, because RAM is expensive, and thus make iterated password hashes sizably more secure. Nowadays, using constructions that require little RAM, like PBKDF2, is either incompetent, or a deliberate way to make the system breakable by well-funded attackers, who can use ASICs to outrun legitimate users by a very large factor.


¹ Modern hashes are expected to be undistinguishable from a random function. SHA-256 is believed to match this except for its length-extension property, and there's reason to believe that it is not an issue in the context.

| improve this answer | |
$\endgroup$
  • 1
    $\begingroup$ "Nowadays, using constructions that require little RAM, like PBKDF2, is either incompetent, or a deliberate way to make the system breakable by well-funded attackers, who can use ASICs to outrun legitimate users by a very large factor." Or a desire to sell to a certain customer set, such as public sector, that requires comformance with FIPS 140. $\endgroup$ – Swashbuckler May 2 at 1:18
  • $\begingroup$ @Swashbuckler: if you are pointing to the lack of support for modern password hashes in key encapsulation mechanism, I'm ready to believe that there is a large amount of lack of economic pressure for change. Also, in my experience, in these fields, when there is a password, it is a competently drawn one, The problem is more with end-user-facing applications. $\endgroup$ – fgrieu May 2 at 8:14
  • $\begingroup$ Thank you @fgrieu. That makes sense. I did post a followup related to this (acknowledged inferior) approach, about the concatenation order, as well. $\endgroup$ – rtillery May 3 at 17:25
1
$\begingroup$

With a simple (uniterated) SHA256 of the password and a random 256-bit salt, when concatenating the salt and password, is it better to use the binary form of the salt, or is a base64 representation just as secure?

That doesn't really matter in the attacker's view since they will do what you applied. For them, it is just an intermediate function that maps the current search string into your encoding while executing Bruteforce like in John the ripper or Hashcat.

Is the salt format moot because the entropy of 32 binary bytes is the same as 42.7 base64 characters, or is one format really a better choice?

Technically entropy is a property of a generation process. It is not the property of the string.

Encoding doesn't change the entropy. With the encoding one change how the characters are represented. The encoding doesn't change the value of the input bits. The entropy value in the bits.

What format should a salt be when it is concatenated with the password?

That is depending on your need. Hex encoding, Base64, Radix 64, etc. Nowadays, Base64 is more common. Just encode when storing and decode into binary when processing. Remember the Hash functions are operating with bits and bytes.

Note that bcrypt is old (1999), however, if there is SHA-256, one can implement that easily.

| improve this answer | |
$\endgroup$

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.