For uniterated SHA-256 of salted password, should the password precede the salt?

This is a follow-up to this question (thanks to answers from @fgrieu and @kelalaka ) about the format of a salt when hashing a salted password.

I realize this is pretty much academic, as the proposed uniterated SHA-256 of a salted password is already acknowledged to be much less secure than trusted password storage algorithms (scrypt, Argon2, PBKDF2, etc.). And, this may be a very obvious point, but I haven't found anything mentioning it (quite the opposite).

Nevertheless, considering the use of this (ill-advised, but currently available) approach, when concatenating salt & password, if the salt precedes the password, wouldn't that allow an attacker to optimize away the salt when doing a dictionary or brute force attack, and speed up the results?

Here's my thought: A SHA-256 hash is a left-to-right processing of the source data. While processing the data, the SHA-256 code could be modified to take a snapshot of the intermediate algorithmic values (variables) as the salt is being processed, but just before the first password character is read. This would be done once to collect the values. Then a further modification of the SHA-256 code, which allowed the hash for each try to begin with the intermediate values previously stored. This would allow only the characters of the test passwords to be processed on each try, eliminating the overhead of processing the (presumably 256-bit) salt, but still providing the correct SHA-256 result.

Again, assuming no iterations, and no nested hashing, wouldn't it be better for the password to precede the salt, so that the attacker had to process the salt data to obtain the correct SHA-256 value for every try?

• From our venerable site Information security How to securely hash passwords? – kelalaka May 3 at 20:22
• @kelalaka, yes, fully read & (mostly) understood. But, as I tried to explain, the environment in which I am working currently does not include the resources for those vetted algorithms. (I'm working on that.) And the information doesn't specify the order of the concatenation. – rtillery May 5 at 0:22
• Well, remember that the accepted answer was old, and Pornin, unfortunately, didn't update that answer. Later, the Argon2 arrived. Also, note that instead of a series of questions it is better to be asked at once about your actual problem as much as possible details. – kelalaka May 5 at 0:26

I think you're right, putting the password first is slightly better than the salt, but given the insecurity of the whole thing I'm not sure it would make any significant difference. You'd just be slightly delaying the attacker.

• It doesn't matter much when brute-forcing. Just the order string concatenation. – kelalaka May 3 at 17:55

We are considering two hypothetical password hashes

1. $$(S_i,P_i)\mapsto H_i=\operatorname{SHA-256}(S_i\mathbin\|P_i)$$
2. $$(S_i,P_i)\mapsto H_i=\operatorname{SHA-256}(P_i\mathbin\|S_i)$$

As pointed in the question, both are un-iterated, thus very weak under the attack model where the salt $$S_i$$ and hashes $$H_i$$ leak, and the adversary is after $$P_i$$ (for a particular $$i$$, or worse for one of any $$i$$).

An important thing is what we put in the salt $$S_i$$: that should include both a fixed string $$F$$ dependent on the instantiation (e.g the name of the server), and a user-unique string (e.g. userid, login, email, random) $$U_i$$. The term $$U_i$$ helps because with $$U_i$$ adversaries can not attack multiple logins simultaneously, they must perform a hash for each password tested for each login. The term $$F$$ prevents amortizing attack work across multiple servers, and makes the hash slower, thus more secure.

The least feeble option is probably $$H_i=\operatorname{SHA-256}(P_i\mathbin\|U_i\mathbin\|F)$$, with $$F$$ as large as possible. The password should be first for the reason in the question: that blocks optimizations where some of the hash's internal operations is reused across multiple $$P_i$$. For the same reason, $$U_i$$ should be second.

But when $$P_i\mathbin\|U_i\mathbin\|F$$ is short (less than 64 bytes), the order is nearly immaterial, because that fits in the same first padded block of message of SHA-256, thus an attacker can not precompute any full compression in SHA-256, at worse some of very few rounds among 64.

Thus if for some strange reason (like a device operated on small battery and very little RAM) one can't go for an iterated password hash and must use plain SHA-256, then put the constant part $$F$$ of the salt last, and make it as long as practical; and rather put the password before the salt.

As an aside, if a long $$F$$ is obtained by repeating a shorter string (which allows arbitrary long $$F$$ with only little RAM), it should have an odd length, in order to reduce the potential for optimization of the message expansion of SHA-256.

P.S. per comment: While the $$U_i$$ part of the salt must be in the database, $$F$$ needs not, at least in each entry, especially if it is long. I have been assuming that $$F$$ is public, not "pepper" (that is, semi-secret). If there is some pepper $$K$$ (that is, a tentatively secret key, by opposition to salt that is assumed fully public), it should be early in the hashed data, in contact with $$P_i$$ or otherwise in the first 64 bytes; and backed up other than in the database in case the whole thing needs to be restored on a different machine.

• Are we talking about pepper as $F$ here? As you know the paper is stored in the application server and that might be helpful only if the attackers have access to DB (most common by an injection attack). If they are control of an application server, all is lost. So, in the sense of more capable attacker adding $F$ doesn't matter against the brute-force searching? – kelalaka May 3 at 18:49
• @fgrieu, I'm not quite sure I understand the addition of the U & F items. If the attacker can get access to the algorithm (which I believe is the assumption if the attacker has obtained the password hashes & salts), how would these help? (Plus, for the F example provided, if the instance was moved, so that the server name changed, wouldn't that make us unable to match the password hash for login?) – rtillery May 4 at 14:18
• @rtillery: I expanded the paragraph introducing $U_i$ and $F$ to include a rationale. Is that clear now? When moving the server to a different machine, $F$ would not change. In the case of e.g. stackexchange.com, $F$ could be the string stackexchange repeated many times. – fgrieu May 4 at 14:47
• @fgrieu, I appreciate your patience. I guess I'm still being a bit dense. You mention that U forces the attacker to focus on 1 login, while F (in the example) forces the attacker to focus on 1 server. But isn't a random salt per user (regenerated for any password change) already more specific than that, forcing the attacker to focus on that 1 specific instance of that specific password? I do understand the lengthening of the combined data, without the need to store a much longer salt, but I'm still not sure I understand the benefit, if it's assumed that the additional data is discoverable. – rtillery May 5 at 0:15