Does putting salt first make it easier for attacker to bruteforce the hash?Hosting company advised us to avoid PHP for security reasons. Are they right?Does bcrypt have a maximum password length?Is there more to password hashing?Client side password hashingImproving Digest Authentication using PBKDF2How can I make sure password hashing is secure on computers while not being prohibitively slow on mobile devices?What is the right way to implement Keyed Password Hashing?How much does knowing the zxcvbn password strength help an attacker?Does having a salted password hash make cracking an unsalted hash of the same password easier?Generating salt for hash that occurs on server and clientIs storing the bcrypt salt in isolated database a good idea?Is password dependent iteration count a good practice?

Animation advice please

What are the benefits of using the X Card safety tool in comparison to plain communication?

When is it ok to add filler to a story?

Can the US president have someone sent to jail?

Is there any set of 2-6 notes that doesn't have a chord name?

Is there any evidence that the small canisters (10 liters) of 95% oxygen actually help with altitude sickness?

Should I include salary information on my CV?

How to split an equation over two lines?

What happens when I sacrifice a creature when my Teysa Karlov is on the battlefield?

Going to get married soon, should I do it on Dec 31 or Jan 1?

Can ADFS connect to other SSO services?

Do equal angles necessarily mean a polygon is regular?

Intuitively, why does putting capacitors in series decrease the equivalent capacitance?

Is this one of the engines from the 9/11 aircraft?

Require advice on power conservation for backpacking trip

How risky is real estate?

How to append a matrix element by element

Unusual mail headers, evidence of an attempted attack. Have I been pwned?

Cascading Repair Costs following Blown Head Gasket on a 2004 Subaru Outback

Distance Matrix (plugin) - QGIS

How can I repair scratches on a painted French door?

What sort of mathematical problems are there in AI that people are working on?

90s (or earlier) cross-world fantasy book with a circular river and character-class tattoos

Why is Madam Hooch not a professor?



Does putting salt first make it easier for attacker to bruteforce the hash?


Hosting company advised us to avoid PHP for security reasons. Are they right?Does bcrypt have a maximum password length?Is there more to password hashing?Client side password hashingImproving Digest Authentication using PBKDF2How can I make sure password hashing is secure on computers while not being prohibitively slow on mobile devices?What is the right way to implement Keyed Password Hashing?How much does knowing the zxcvbn password strength help an attacker?Does having a salted password hash make cracking an unsalted hash of the same password easier?Generating salt for hash that occurs on server and clientIs storing the bcrypt salt in isolated database a good idea?Is password dependent iteration count a good practice?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








26















Many recommendations for storing passwords recommend hash(salt + password) rather than hash(password + salt).



Doesn't putting the salt first make it much faster for the attacker to bruteforce the password, because they can precompute the state of the hashing function with the bytes of the salt, and then each time of their billions and trillions attempts they only need to finish calculating the hash using the bytes of the password.



In other words, each bruteforce iteration needs to calculate only the hash of the password intermediateHashState(password) instead of the whole hash(salt + password).



And if the salt was placed after the password, the attacker wouldn't have this shortcut.



Does this advantage exist and is it significant?










share|improve this question

















  • 14





    Resources that recommend either of those two options are wrong.

    – Future Security
    Jun 8 at 1:49











  • @FutureSecurity: hash(salt + password + salt) doesn't seem outright wrong...

    – Mehrdad
    Jun 10 at 20:15

















26















Many recommendations for storing passwords recommend hash(salt + password) rather than hash(password + salt).



Doesn't putting the salt first make it much faster for the attacker to bruteforce the password, because they can precompute the state of the hashing function with the bytes of the salt, and then each time of their billions and trillions attempts they only need to finish calculating the hash using the bytes of the password.



In other words, each bruteforce iteration needs to calculate only the hash of the password intermediateHashState(password) instead of the whole hash(salt + password).



And if the salt was placed after the password, the attacker wouldn't have this shortcut.



Does this advantage exist and is it significant?










share|improve this question

















  • 14





    Resources that recommend either of those two options are wrong.

    – Future Security
    Jun 8 at 1:49











  • @FutureSecurity: hash(salt + password + salt) doesn't seem outright wrong...

    – Mehrdad
    Jun 10 at 20:15













26












26








26


5






Many recommendations for storing passwords recommend hash(salt + password) rather than hash(password + salt).



Doesn't putting the salt first make it much faster for the attacker to bruteforce the password, because they can precompute the state of the hashing function with the bytes of the salt, and then each time of their billions and trillions attempts they only need to finish calculating the hash using the bytes of the password.



In other words, each bruteforce iteration needs to calculate only the hash of the password intermediateHashState(password) instead of the whole hash(salt + password).



And if the salt was placed after the password, the attacker wouldn't have this shortcut.



Does this advantage exist and is it significant?










share|improve this question














Many recommendations for storing passwords recommend hash(salt + password) rather than hash(password + salt).



Doesn't putting the salt first make it much faster for the attacker to bruteforce the password, because they can precompute the state of the hashing function with the bytes of the salt, and then each time of their billions and trillions attempts they only need to finish calculating the hash using the bytes of the password.



In other words, each bruteforce iteration needs to calculate only the hash of the password intermediateHashState(password) instead of the whole hash(salt + password).



And if the salt was placed after the password, the attacker wouldn't have this shortcut.



Does this advantage exist and is it significant?







passwords hash password-cracking






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jun 7 at 12:07









K48K48

2563 silver badges7 bronze badges




2563 silver badges7 bronze badges







  • 14





    Resources that recommend either of those two options are wrong.

    – Future Security
    Jun 8 at 1:49











  • @FutureSecurity: hash(salt + password + salt) doesn't seem outright wrong...

    – Mehrdad
    Jun 10 at 20:15












  • 14





    Resources that recommend either of those two options are wrong.

    – Future Security
    Jun 8 at 1:49











  • @FutureSecurity: hash(salt + password + salt) doesn't seem outright wrong...

    – Mehrdad
    Jun 10 at 20:15







14




14





Resources that recommend either of those two options are wrong.

– Future Security
Jun 8 at 1:49





Resources that recommend either of those two options are wrong.

– Future Security
Jun 8 at 1:49













@FutureSecurity: hash(salt + password + salt) doesn't seem outright wrong...

– Mehrdad
Jun 10 at 20:15





@FutureSecurity: hash(salt + password + salt) doesn't seem outright wrong...

– Mehrdad
Jun 10 at 20:15










4 Answers
4






active

oldest

votes


















16














Hash functions recommended for password use do not have this advantage - I'm not sure that any non-trivial hashing functions do, in fact, but wouldn't want to make a blanket statement there.



Instead, hashing functions mix parts from the whole input in each stage. For example, given the input ABCDEFGHIJKLMNOPQRSTUVWXYZ, the first step could be something like pairing the first character with the last, and iterating until no input is left. This would give AZBYCXDWEVFUGTHSIRJQKPLOMN. Assume the "salt" was ABCDEF, and the password was the rest, then change the password to PASSWORD - the output of this example first step would be ADBRCODWESFSPA, which wouldn't help you with the original hash in the slightest.



This is just an example - real hash functions work on binary values, and perform more complex mixing, for a couple of differences - but you can see that it doesn't matter where the salt is for the output to change at a very early point.



There is even a principle (the Avalanche Effect) which suggests that a single bit being changed in the input to a hash function should change about 50% of the output bits, and most hash functions, even ones which are now considered unsafe such as MD5, follow this (while my example above does not!).



Essentially, you can't pre-compute part of a hash in the way you suggest, unless there are other flaws in the system. If you, for some reason, hashed the salt, took the first half of the output, and bolted it onto the second half of the hash of the password for storage, that would introduce the theoretical weakness so you'd only need to compute the hashes of passwords.






share|improve this answer


















  • 24





    I don't quite agree with the explanation. Hash functions do usually work in blocks, so they don't mix parts from the whole input in each stage. If you have two plaintexts that share a common prefix of blocks, the hash state of the common blocks can be re-used. However, the block size of even SHA-256 is 64 bytes, so this is not an issue for this application.

    – wrtlprnft
    Jun 7 at 21:27







  • 13





    The explanation in paragraph two is nothing like real world hash functions. Plus it doesn't follow from a hash function exhibiting the avalanche effect that there is no way to use partial evaluation to optimize brute force.

    – Future Security
    Jun 8 at 1:48











  • Aha. So a 64-byte salt could actually make it easier to bruteforce.

    – K48
    Jun 8 at 5:43






  • 3





    @Voo, that’s just one of the reasons why you shouldn’t be using any SHA variant for hashing passwords. You want a specialized password hashing algorithm which doesn’t have that problem.

    – cjm
    Jun 9 at 0:12






  • 4





    @cjm : PBKDF2 is not a perfect password hashing function, but the fact it is based on SHAx is not seen as one of its weaknesses.

    – Martin Bonner
    Jun 10 at 9:02


















34














Actually, you are tackling it the opposite way.



It is true that doing hash(salt + password) would allow you to precompute the salt (but see note below) and only hash each password candidate for all those trials. The cost be the same you would bear if you were not using a salt at all.



However, the goal of the salt is not to make bruteforcing a single hash harder, but to ensure that the hashes for different users are different even if they chose the same password and so the cracking effort can't be applied for multiple users.



Let's assume you dumped a PayPal database hashes where they were using MD5 hashes. You want to check passwords 'paypal', 'PayPal', 'PayPal123'...



  1. If they used MD5(password), you can trivially hash any of them and find out if anyone is using such weak password.


  2. If they used MD5(salt + password), you could precompute the partial MD5(salt) for everyone, but still need to hash each password candidate for each user.


  3. If they used MD5(password + salt), you could precompute the partial MD5(password) for each candidate password, and then apply their salt for each user.


#1 is clearly the worst here. You could argue between #2 and #3 based on the different lengths of passwords and salts, as well as the number of users, but I would consider #2 to be preferable. Based on length alone, the enforced minimum length for your passwords is probably higher than the salt size. But I suspect there could be other weakness with the #3 construct, too.



Is it a significant advantage?



Not really.



First of all, many hash functions work in blocks, and the precomputation for values smaller than the block size simply store a copy of the "precomputed bytes". In 99% of the cases the length of both salt and password will be shorter than the block size, so actually there would be no real precomputation being performed. You would need to be using really long strings there for that to be of use.



Additionally, any modern password hash function will at the very minimum use many iterations, if not using more advanced means to make bruteforcing expensive, and your optimization is only applicable the initial iteration.



In any case, rather than simply concatenating salt and password, the most secure way to combine them would be to do an HMAC over them, which mixes them in a better way.






share|improve this answer




















  • 5





    Are you sure about the ability to precompute MD5(password) and later add the salt (or vice versa)? If the password is the size of an MD5 block I wouldn't doubt it, but MD5 uses a 512 bit block and most passwords (or salts) aren't exactly 64 characters.

    – AndrolGenhald
    Jun 8 at 0:10











  • @AndrolGenhald it would partially precompute, up to the working register that requires salt bytes

    – Richie Frame
    Jun 8 at 0:12






  • 1





    @Ángel MD5_update() will not precompute unless you have a full block, anything less and it will just keep it in a buffer

    – Richie Frame
    Jun 8 at 0:28






  • 1





    @Ángel Then don't you think it's a little bit misleading to say you can precompute the partial MD5(salt)? A salt or password by itself is almost never going to be large enough to compute the first block.

    – AndrolGenhald
    Jun 8 at 0:45






  • 2





    @AndrolGenhald you are completely right. My answer was in a different line, and I didn't take into account this. I have edited the answer adding a paragraph about this on the part discussing if it would be a significant advantage.

    – Ángel
    Jun 8 at 0:59



















25















Many recommendations for storing passwords recommend hash(salt + password) rather than hash(password + salt).




Those recommendations are evidently bad, because what they should be telling you is to use a password hashing function that's been specially designed for the purpose, like (in rough order of newer and betterish to older and worse-ish):



  • Argon2 (best)

  • scrypt

  • bcrypt (not bad but beginning to look dated)

  • PBKDF2 (far from ideal but much better than homebrew password hashing)

These functions either:



  1. Take the password and the salt as separate arguments, and thus take care of your question internally;

  2. Give you a higher-level API that takes care of salt generation and management internally:

    • An "enrollment" function that takes a password, generates a salt, and outputs a verification string that encapsulates both salt and hash (e.g., password_hash() in PHP);

    • A "verification" function that takes a password and verification string, and verifies that the password matches the latter (e.g., password_verify() in PHP).


If you're manually concatenating passwords and salts, you're doing it wrong.




That said, it's generally better for a password hashing function to absorb the salt first and the password after. Why? Because that order is generically better at resisting precomputation attacks. In the password-first order, the attacker can precompute the intermediate states that correspond to common passwords, and perhaps there is some clever way of building some sort of big table that exploits this to compute their salted hashes quicker than they could otherwise. Whereas the salt-first order makes this impossible, more so if salts are random.




Doesn't putting the salt first make it much faster for the attacker to bruteforce the password, because they can precompute the state of the hashing function with the bytes of the salt, and then each time of their billions and trillions attempts they only need to finish calculating the hash using the bytes of the password.




No, because the point is that the attacker is not supposed to learn the salts before they steal the password database. That bit of precomputation you mention only gives a tiny speedup relative to the cost of a well-designed password hashing function, and the precomputed state is only good for attacking one individual password entry (assuming no duplicate salts, which is a requirement anyway).



In contrast, with the password-first order, they can:



  • Precompute and store hash function states for large numbers of common passwords before they ever steal the password database;

  • Reuse the precomputed tables across password entries hashed with different salts, even across multiple password databases.





share|improve this answer




















  • 3





    PBKDF2 should be retired. If a developer has the freedom to choose what algorithm to use then they shouldn't use it. Or any function that only stretches passwords by iterating an easily parallelized hash many times. Bcrypt is a step up - it's a simple algorithm iterated many times, but it's not one that GPUs can do easily - but many-core computers and FPGAs can attack it much more efficiently

    – Future Security
    Jun 8 at 2:01






  • 2





    @forest Even if you have SHA-1 acceleration, you should not use SHA-1. The objective here is to minimize the ratio of (attacker's hash rate)/(your hash rate). A memory-hard hash scores better than SHA-1 no matter what hardware acceleration you have. Recall that you're hashing one password at a time while the attacker isn't.

    – Navin
    Jun 8 at 15:30







  • 2





    @jpmc26: I don't actually disagree with your take on PHP, but strangely enough its modern password hashing API is exemplary and making more people aware of it does the world a lot of good.

    – Luis Casillas
    Jun 9 at 4:55






  • 2





    @Navin You're absolutely correct, and a proper memory-hard KDF beats hardware-accelerated SHA-1 any day. I was just pointing out that I disagree with the idea that one of PBKDF2's problems is its flexibility. While normally I do agree that flexibility is a bad thing in cryptography and developers shouldn't be given access to complex APIs, in this specific case, I think PBKDF2's flexibility is actually a positive for the aforementioned reasons. Also technically you could probably make PBKDF2 memory-hard since it works with any keyed PRF, not just HMAC. Consider a memory-hard keyed PRF.

    – forest
    Jun 9 at 7:24







  • 3





    One key advantage that PBKDF2 still has is that it's the only one that's NIST approved, which is relevant in orgs where compliance is important. Hopefully they'll publish a new recommendation soon, though.

    – James_pic
    Jun 10 at 10:34


















1














While the above answers do raise some valid points they do not seem to be entirely correct and it should be noted that there do in fact exist weaknesses in certain hash functions that make a significant difference in the cracking speeds for "$pass.$salt" or "$salt.$pass".



See for example md5. According to atom (https://hashcat.net/forum/thread-8365.html), creator of the hashcat password cracking software:




The way how hashcat exploits some weakness in MD5 to get additional acceleration requires it to change only the first 4 bytes of the input data. Since this part is fixed (because of the salt) it cannot use the acceleration.




That does reflect significantly in the cracking speed.

On a Titan RTX the speed for md5($pass.$salt) is with 63819.9 MH/s almost double the speed as for md5($salt.$pass) with "only" 34696.2 MH/s.



Similar differences exist for other hash algorithms. The developers and community of password cracking software spend a significant amount of time to find weaknesses and shortcuts to improve speed. So from a cracking perspective it can be a good idea to look at current hashcat benchmarks like this one https://gist.github.com/Chick3nman/5d261c5798cf4f3867fe7035ef6dd49f and compare the speeds for the different Salt-Password-Variants.

If that link goes missing, you can also generate your own benchmark with the following command:



hashcat -b





share|improve this answer

























    Your Answer








    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "162"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    noCode: true, onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsecurity.stackexchange.com%2fquestions%2f211478%2fdoes-putting-salt-first-make-it-easier-for-attacker-to-bruteforce-the-hash%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    4 Answers
    4






    active

    oldest

    votes








    4 Answers
    4






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    16














    Hash functions recommended for password use do not have this advantage - I'm not sure that any non-trivial hashing functions do, in fact, but wouldn't want to make a blanket statement there.



    Instead, hashing functions mix parts from the whole input in each stage. For example, given the input ABCDEFGHIJKLMNOPQRSTUVWXYZ, the first step could be something like pairing the first character with the last, and iterating until no input is left. This would give AZBYCXDWEVFUGTHSIRJQKPLOMN. Assume the "salt" was ABCDEF, and the password was the rest, then change the password to PASSWORD - the output of this example first step would be ADBRCODWESFSPA, which wouldn't help you with the original hash in the slightest.



    This is just an example - real hash functions work on binary values, and perform more complex mixing, for a couple of differences - but you can see that it doesn't matter where the salt is for the output to change at a very early point.



    There is even a principle (the Avalanche Effect) which suggests that a single bit being changed in the input to a hash function should change about 50% of the output bits, and most hash functions, even ones which are now considered unsafe such as MD5, follow this (while my example above does not!).



    Essentially, you can't pre-compute part of a hash in the way you suggest, unless there are other flaws in the system. If you, for some reason, hashed the salt, took the first half of the output, and bolted it onto the second half of the hash of the password for storage, that would introduce the theoretical weakness so you'd only need to compute the hashes of passwords.






    share|improve this answer


















    • 24





      I don't quite agree with the explanation. Hash functions do usually work in blocks, so they don't mix parts from the whole input in each stage. If you have two plaintexts that share a common prefix of blocks, the hash state of the common blocks can be re-used. However, the block size of even SHA-256 is 64 bytes, so this is not an issue for this application.

      – wrtlprnft
      Jun 7 at 21:27







    • 13





      The explanation in paragraph two is nothing like real world hash functions. Plus it doesn't follow from a hash function exhibiting the avalanche effect that there is no way to use partial evaluation to optimize brute force.

      – Future Security
      Jun 8 at 1:48











    • Aha. So a 64-byte salt could actually make it easier to bruteforce.

      – K48
      Jun 8 at 5:43






    • 3





      @Voo, that’s just one of the reasons why you shouldn’t be using any SHA variant for hashing passwords. You want a specialized password hashing algorithm which doesn’t have that problem.

      – cjm
      Jun 9 at 0:12






    • 4





      @cjm : PBKDF2 is not a perfect password hashing function, but the fact it is based on SHAx is not seen as one of its weaknesses.

      – Martin Bonner
      Jun 10 at 9:02















    16














    Hash functions recommended for password use do not have this advantage - I'm not sure that any non-trivial hashing functions do, in fact, but wouldn't want to make a blanket statement there.



    Instead, hashing functions mix parts from the whole input in each stage. For example, given the input ABCDEFGHIJKLMNOPQRSTUVWXYZ, the first step could be something like pairing the first character with the last, and iterating until no input is left. This would give AZBYCXDWEVFUGTHSIRJQKPLOMN. Assume the "salt" was ABCDEF, and the password was the rest, then change the password to PASSWORD - the output of this example first step would be ADBRCODWESFSPA, which wouldn't help you with the original hash in the slightest.



    This is just an example - real hash functions work on binary values, and perform more complex mixing, for a couple of differences - but you can see that it doesn't matter where the salt is for the output to change at a very early point.



    There is even a principle (the Avalanche Effect) which suggests that a single bit being changed in the input to a hash function should change about 50% of the output bits, and most hash functions, even ones which are now considered unsafe such as MD5, follow this (while my example above does not!).



    Essentially, you can't pre-compute part of a hash in the way you suggest, unless there are other flaws in the system. If you, for some reason, hashed the salt, took the first half of the output, and bolted it onto the second half of the hash of the password for storage, that would introduce the theoretical weakness so you'd only need to compute the hashes of passwords.






    share|improve this answer


















    • 24





      I don't quite agree with the explanation. Hash functions do usually work in blocks, so they don't mix parts from the whole input in each stage. If you have two plaintexts that share a common prefix of blocks, the hash state of the common blocks can be re-used. However, the block size of even SHA-256 is 64 bytes, so this is not an issue for this application.

      – wrtlprnft
      Jun 7 at 21:27







    • 13





      The explanation in paragraph two is nothing like real world hash functions. Plus it doesn't follow from a hash function exhibiting the avalanche effect that there is no way to use partial evaluation to optimize brute force.

      – Future Security
      Jun 8 at 1:48











    • Aha. So a 64-byte salt could actually make it easier to bruteforce.

      – K48
      Jun 8 at 5:43






    • 3





      @Voo, that’s just one of the reasons why you shouldn’t be using any SHA variant for hashing passwords. You want a specialized password hashing algorithm which doesn’t have that problem.

      – cjm
      Jun 9 at 0:12






    • 4





      @cjm : PBKDF2 is not a perfect password hashing function, but the fact it is based on SHAx is not seen as one of its weaknesses.

      – Martin Bonner
      Jun 10 at 9:02













    16












    16








    16







    Hash functions recommended for password use do not have this advantage - I'm not sure that any non-trivial hashing functions do, in fact, but wouldn't want to make a blanket statement there.



    Instead, hashing functions mix parts from the whole input in each stage. For example, given the input ABCDEFGHIJKLMNOPQRSTUVWXYZ, the first step could be something like pairing the first character with the last, and iterating until no input is left. This would give AZBYCXDWEVFUGTHSIRJQKPLOMN. Assume the "salt" was ABCDEF, and the password was the rest, then change the password to PASSWORD - the output of this example first step would be ADBRCODWESFSPA, which wouldn't help you with the original hash in the slightest.



    This is just an example - real hash functions work on binary values, and perform more complex mixing, for a couple of differences - but you can see that it doesn't matter where the salt is for the output to change at a very early point.



    There is even a principle (the Avalanche Effect) which suggests that a single bit being changed in the input to a hash function should change about 50% of the output bits, and most hash functions, even ones which are now considered unsafe such as MD5, follow this (while my example above does not!).



    Essentially, you can't pre-compute part of a hash in the way you suggest, unless there are other flaws in the system. If you, for some reason, hashed the salt, took the first half of the output, and bolted it onto the second half of the hash of the password for storage, that would introduce the theoretical weakness so you'd only need to compute the hashes of passwords.






    share|improve this answer













    Hash functions recommended for password use do not have this advantage - I'm not sure that any non-trivial hashing functions do, in fact, but wouldn't want to make a blanket statement there.



    Instead, hashing functions mix parts from the whole input in each stage. For example, given the input ABCDEFGHIJKLMNOPQRSTUVWXYZ, the first step could be something like pairing the first character with the last, and iterating until no input is left. This would give AZBYCXDWEVFUGTHSIRJQKPLOMN. Assume the "salt" was ABCDEF, and the password was the rest, then change the password to PASSWORD - the output of this example first step would be ADBRCODWESFSPA, which wouldn't help you with the original hash in the slightest.



    This is just an example - real hash functions work on binary values, and perform more complex mixing, for a couple of differences - but you can see that it doesn't matter where the salt is for the output to change at a very early point.



    There is even a principle (the Avalanche Effect) which suggests that a single bit being changed in the input to a hash function should change about 50% of the output bits, and most hash functions, even ones which are now considered unsafe such as MD5, follow this (while my example above does not!).



    Essentially, you can't pre-compute part of a hash in the way you suggest, unless there are other flaws in the system. If you, for some reason, hashed the salt, took the first half of the output, and bolted it onto the second half of the hash of the password for storage, that would introduce the theoretical weakness so you'd only need to compute the hashes of passwords.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Jun 7 at 12:35









    MatthewMatthew

    26.3k7 gold badges83 silver badges97 bronze badges




    26.3k7 gold badges83 silver badges97 bronze badges







    • 24





      I don't quite agree with the explanation. Hash functions do usually work in blocks, so they don't mix parts from the whole input in each stage. If you have two plaintexts that share a common prefix of blocks, the hash state of the common blocks can be re-used. However, the block size of even SHA-256 is 64 bytes, so this is not an issue for this application.

      – wrtlprnft
      Jun 7 at 21:27







    • 13





      The explanation in paragraph two is nothing like real world hash functions. Plus it doesn't follow from a hash function exhibiting the avalanche effect that there is no way to use partial evaluation to optimize brute force.

      – Future Security
      Jun 8 at 1:48











    • Aha. So a 64-byte salt could actually make it easier to bruteforce.

      – K48
      Jun 8 at 5:43






    • 3





      @Voo, that’s just one of the reasons why you shouldn’t be using any SHA variant for hashing passwords. You want a specialized password hashing algorithm which doesn’t have that problem.

      – cjm
      Jun 9 at 0:12






    • 4





      @cjm : PBKDF2 is not a perfect password hashing function, but the fact it is based on SHAx is not seen as one of its weaknesses.

      – Martin Bonner
      Jun 10 at 9:02












    • 24





      I don't quite agree with the explanation. Hash functions do usually work in blocks, so they don't mix parts from the whole input in each stage. If you have two plaintexts that share a common prefix of blocks, the hash state of the common blocks can be re-used. However, the block size of even SHA-256 is 64 bytes, so this is not an issue for this application.

      – wrtlprnft
      Jun 7 at 21:27







    • 13





      The explanation in paragraph two is nothing like real world hash functions. Plus it doesn't follow from a hash function exhibiting the avalanche effect that there is no way to use partial evaluation to optimize brute force.

      – Future Security
      Jun 8 at 1:48











    • Aha. So a 64-byte salt could actually make it easier to bruteforce.

      – K48
      Jun 8 at 5:43






    • 3





      @Voo, that’s just one of the reasons why you shouldn’t be using any SHA variant for hashing passwords. You want a specialized password hashing algorithm which doesn’t have that problem.

      – cjm
      Jun 9 at 0:12






    • 4





      @cjm : PBKDF2 is not a perfect password hashing function, but the fact it is based on SHAx is not seen as one of its weaknesses.

      – Martin Bonner
      Jun 10 at 9:02







    24




    24





    I don't quite agree with the explanation. Hash functions do usually work in blocks, so they don't mix parts from the whole input in each stage. If you have two plaintexts that share a common prefix of blocks, the hash state of the common blocks can be re-used. However, the block size of even SHA-256 is 64 bytes, so this is not an issue for this application.

    – wrtlprnft
    Jun 7 at 21:27






    I don't quite agree with the explanation. Hash functions do usually work in blocks, so they don't mix parts from the whole input in each stage. If you have two plaintexts that share a common prefix of blocks, the hash state of the common blocks can be re-used. However, the block size of even SHA-256 is 64 bytes, so this is not an issue for this application.

    – wrtlprnft
    Jun 7 at 21:27





    13




    13





    The explanation in paragraph two is nothing like real world hash functions. Plus it doesn't follow from a hash function exhibiting the avalanche effect that there is no way to use partial evaluation to optimize brute force.

    – Future Security
    Jun 8 at 1:48





    The explanation in paragraph two is nothing like real world hash functions. Plus it doesn't follow from a hash function exhibiting the avalanche effect that there is no way to use partial evaluation to optimize brute force.

    – Future Security
    Jun 8 at 1:48













    Aha. So a 64-byte salt could actually make it easier to bruteforce.

    – K48
    Jun 8 at 5:43





    Aha. So a 64-byte salt could actually make it easier to bruteforce.

    – K48
    Jun 8 at 5:43




    3




    3





    @Voo, that’s just one of the reasons why you shouldn’t be using any SHA variant for hashing passwords. You want a specialized password hashing algorithm which doesn’t have that problem.

    – cjm
    Jun 9 at 0:12





    @Voo, that’s just one of the reasons why you shouldn’t be using any SHA variant for hashing passwords. You want a specialized password hashing algorithm which doesn’t have that problem.

    – cjm
    Jun 9 at 0:12




    4




    4





    @cjm : PBKDF2 is not a perfect password hashing function, but the fact it is based on SHAx is not seen as one of its weaknesses.

    – Martin Bonner
    Jun 10 at 9:02





    @cjm : PBKDF2 is not a perfect password hashing function, but the fact it is based on SHAx is not seen as one of its weaknesses.

    – Martin Bonner
    Jun 10 at 9:02













    34














    Actually, you are tackling it the opposite way.



    It is true that doing hash(salt + password) would allow you to precompute the salt (but see note below) and only hash each password candidate for all those trials. The cost be the same you would bear if you were not using a salt at all.



    However, the goal of the salt is not to make bruteforcing a single hash harder, but to ensure that the hashes for different users are different even if they chose the same password and so the cracking effort can't be applied for multiple users.



    Let's assume you dumped a PayPal database hashes where they were using MD5 hashes. You want to check passwords 'paypal', 'PayPal', 'PayPal123'...



    1. If they used MD5(password), you can trivially hash any of them and find out if anyone is using such weak password.


    2. If they used MD5(salt + password), you could precompute the partial MD5(salt) for everyone, but still need to hash each password candidate for each user.


    3. If they used MD5(password + salt), you could precompute the partial MD5(password) for each candidate password, and then apply their salt for each user.


    #1 is clearly the worst here. You could argue between #2 and #3 based on the different lengths of passwords and salts, as well as the number of users, but I would consider #2 to be preferable. Based on length alone, the enforced minimum length for your passwords is probably higher than the salt size. But I suspect there could be other weakness with the #3 construct, too.



    Is it a significant advantage?



    Not really.



    First of all, many hash functions work in blocks, and the precomputation for values smaller than the block size simply store a copy of the "precomputed bytes". In 99% of the cases the length of both salt and password will be shorter than the block size, so actually there would be no real precomputation being performed. You would need to be using really long strings there for that to be of use.



    Additionally, any modern password hash function will at the very minimum use many iterations, if not using more advanced means to make bruteforcing expensive, and your optimization is only applicable the initial iteration.



    In any case, rather than simply concatenating salt and password, the most secure way to combine them would be to do an HMAC over them, which mixes them in a better way.






    share|improve this answer




















    • 5





      Are you sure about the ability to precompute MD5(password) and later add the salt (or vice versa)? If the password is the size of an MD5 block I wouldn't doubt it, but MD5 uses a 512 bit block and most passwords (or salts) aren't exactly 64 characters.

      – AndrolGenhald
      Jun 8 at 0:10











    • @AndrolGenhald it would partially precompute, up to the working register that requires salt bytes

      – Richie Frame
      Jun 8 at 0:12






    • 1





      @Ángel MD5_update() will not precompute unless you have a full block, anything less and it will just keep it in a buffer

      – Richie Frame
      Jun 8 at 0:28






    • 1





      @Ángel Then don't you think it's a little bit misleading to say you can precompute the partial MD5(salt)? A salt or password by itself is almost never going to be large enough to compute the first block.

      – AndrolGenhald
      Jun 8 at 0:45






    • 2





      @AndrolGenhald you are completely right. My answer was in a different line, and I didn't take into account this. I have edited the answer adding a paragraph about this on the part discussing if it would be a significant advantage.

      – Ángel
      Jun 8 at 0:59
















    34














    Actually, you are tackling it the opposite way.



    It is true that doing hash(salt + password) would allow you to precompute the salt (but see note below) and only hash each password candidate for all those trials. The cost be the same you would bear if you were not using a salt at all.



    However, the goal of the salt is not to make bruteforcing a single hash harder, but to ensure that the hashes for different users are different even if they chose the same password and so the cracking effort can't be applied for multiple users.



    Let's assume you dumped a PayPal database hashes where they were using MD5 hashes. You want to check passwords 'paypal', 'PayPal', 'PayPal123'...



    1. If they used MD5(password), you can trivially hash any of them and find out if anyone is using such weak password.


    2. If they used MD5(salt + password), you could precompute the partial MD5(salt) for everyone, but still need to hash each password candidate for each user.


    3. If they used MD5(password + salt), you could precompute the partial MD5(password) for each candidate password, and then apply their salt for each user.


    #1 is clearly the worst here. You could argue between #2 and #3 based on the different lengths of passwords and salts, as well as the number of users, but I would consider #2 to be preferable. Based on length alone, the enforced minimum length for your passwords is probably higher than the salt size. But I suspect there could be other weakness with the #3 construct, too.



    Is it a significant advantage?



    Not really.



    First of all, many hash functions work in blocks, and the precomputation for values smaller than the block size simply store a copy of the "precomputed bytes". In 99% of the cases the length of both salt and password will be shorter than the block size, so actually there would be no real precomputation being performed. You would need to be using really long strings there for that to be of use.



    Additionally, any modern password hash function will at the very minimum use many iterations, if not using more advanced means to make bruteforcing expensive, and your optimization is only applicable the initial iteration.



    In any case, rather than simply concatenating salt and password, the most secure way to combine them would be to do an HMAC over them, which mixes them in a better way.






    share|improve this answer




















    • 5





      Are you sure about the ability to precompute MD5(password) and later add the salt (or vice versa)? If the password is the size of an MD5 block I wouldn't doubt it, but MD5 uses a 512 bit block and most passwords (or salts) aren't exactly 64 characters.

      – AndrolGenhald
      Jun 8 at 0:10











    • @AndrolGenhald it would partially precompute, up to the working register that requires salt bytes

      – Richie Frame
      Jun 8 at 0:12






    • 1





      @Ángel MD5_update() will not precompute unless you have a full block, anything less and it will just keep it in a buffer

      – Richie Frame
      Jun 8 at 0:28






    • 1





      @Ángel Then don't you think it's a little bit misleading to say you can precompute the partial MD5(salt)? A salt or password by itself is almost never going to be large enough to compute the first block.

      – AndrolGenhald
      Jun 8 at 0:45






    • 2





      @AndrolGenhald you are completely right. My answer was in a different line, and I didn't take into account this. I have edited the answer adding a paragraph about this on the part discussing if it would be a significant advantage.

      – Ángel
      Jun 8 at 0:59














    34












    34








    34







    Actually, you are tackling it the opposite way.



    It is true that doing hash(salt + password) would allow you to precompute the salt (but see note below) and only hash each password candidate for all those trials. The cost be the same you would bear if you were not using a salt at all.



    However, the goal of the salt is not to make bruteforcing a single hash harder, but to ensure that the hashes for different users are different even if they chose the same password and so the cracking effort can't be applied for multiple users.



    Let's assume you dumped a PayPal database hashes where they were using MD5 hashes. You want to check passwords 'paypal', 'PayPal', 'PayPal123'...



    1. If they used MD5(password), you can trivially hash any of them and find out if anyone is using such weak password.


    2. If they used MD5(salt + password), you could precompute the partial MD5(salt) for everyone, but still need to hash each password candidate for each user.


    3. If they used MD5(password + salt), you could precompute the partial MD5(password) for each candidate password, and then apply their salt for each user.


    #1 is clearly the worst here. You could argue between #2 and #3 based on the different lengths of passwords and salts, as well as the number of users, but I would consider #2 to be preferable. Based on length alone, the enforced minimum length for your passwords is probably higher than the salt size. But I suspect there could be other weakness with the #3 construct, too.



    Is it a significant advantage?



    Not really.



    First of all, many hash functions work in blocks, and the precomputation for values smaller than the block size simply store a copy of the "precomputed bytes". In 99% of the cases the length of both salt and password will be shorter than the block size, so actually there would be no real precomputation being performed. You would need to be using really long strings there for that to be of use.



    Additionally, any modern password hash function will at the very minimum use many iterations, if not using more advanced means to make bruteforcing expensive, and your optimization is only applicable the initial iteration.



    In any case, rather than simply concatenating salt and password, the most secure way to combine them would be to do an HMAC over them, which mixes them in a better way.






    share|improve this answer















    Actually, you are tackling it the opposite way.



    It is true that doing hash(salt + password) would allow you to precompute the salt (but see note below) and only hash each password candidate for all those trials. The cost be the same you would bear if you were not using a salt at all.



    However, the goal of the salt is not to make bruteforcing a single hash harder, but to ensure that the hashes for different users are different even if they chose the same password and so the cracking effort can't be applied for multiple users.



    Let's assume you dumped a PayPal database hashes where they were using MD5 hashes. You want to check passwords 'paypal', 'PayPal', 'PayPal123'...



    1. If they used MD5(password), you can trivially hash any of them and find out if anyone is using such weak password.


    2. If they used MD5(salt + password), you could precompute the partial MD5(salt) for everyone, but still need to hash each password candidate for each user.


    3. If they used MD5(password + salt), you could precompute the partial MD5(password) for each candidate password, and then apply their salt for each user.


    #1 is clearly the worst here. You could argue between #2 and #3 based on the different lengths of passwords and salts, as well as the number of users, but I would consider #2 to be preferable. Based on length alone, the enforced minimum length for your passwords is probably higher than the salt size. But I suspect there could be other weakness with the #3 construct, too.



    Is it a significant advantage?



    Not really.



    First of all, many hash functions work in blocks, and the precomputation for values smaller than the block size simply store a copy of the "precomputed bytes". In 99% of the cases the length of both salt and password will be shorter than the block size, so actually there would be no real precomputation being performed. You would need to be using really long strings there for that to be of use.



    Additionally, any modern password hash function will at the very minimum use many iterations, if not using more advanced means to make bruteforcing expensive, and your optimization is only applicable the initial iteration.



    In any case, rather than simply concatenating salt and password, the most secure way to combine them would be to do an HMAC over them, which mixes them in a better way.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Jun 10 at 0:30

























    answered Jun 7 at 22:53









    ÁngelÁngel

    10.1k2 gold badges15 silver badges41 bronze badges




    10.1k2 gold badges15 silver badges41 bronze badges







    • 5





      Are you sure about the ability to precompute MD5(password) and later add the salt (or vice versa)? If the password is the size of an MD5 block I wouldn't doubt it, but MD5 uses a 512 bit block and most passwords (or salts) aren't exactly 64 characters.

      – AndrolGenhald
      Jun 8 at 0:10











    • @AndrolGenhald it would partially precompute, up to the working register that requires salt bytes

      – Richie Frame
      Jun 8 at 0:12






    • 1





      @Ángel MD5_update() will not precompute unless you have a full block, anything less and it will just keep it in a buffer

      – Richie Frame
      Jun 8 at 0:28






    • 1





      @Ángel Then don't you think it's a little bit misleading to say you can precompute the partial MD5(salt)? A salt or password by itself is almost never going to be large enough to compute the first block.

      – AndrolGenhald
      Jun 8 at 0:45






    • 2





      @AndrolGenhald you are completely right. My answer was in a different line, and I didn't take into account this. I have edited the answer adding a paragraph about this on the part discussing if it would be a significant advantage.

      – Ángel
      Jun 8 at 0:59













    • 5





      Are you sure about the ability to precompute MD5(password) and later add the salt (or vice versa)? If the password is the size of an MD5 block I wouldn't doubt it, but MD5 uses a 512 bit block and most passwords (or salts) aren't exactly 64 characters.

      – AndrolGenhald
      Jun 8 at 0:10











    • @AndrolGenhald it would partially precompute, up to the working register that requires salt bytes

      – Richie Frame
      Jun 8 at 0:12






    • 1





      @Ángel MD5_update() will not precompute unless you have a full block, anything less and it will just keep it in a buffer

      – Richie Frame
      Jun 8 at 0:28






    • 1





      @Ángel Then don't you think it's a little bit misleading to say you can precompute the partial MD5(salt)? A salt or password by itself is almost never going to be large enough to compute the first block.

      – AndrolGenhald
      Jun 8 at 0:45






    • 2





      @AndrolGenhald you are completely right. My answer was in a different line, and I didn't take into account this. I have edited the answer adding a paragraph about this on the part discussing if it would be a significant advantage.

      – Ángel
      Jun 8 at 0:59








    5




    5





    Are you sure about the ability to precompute MD5(password) and later add the salt (or vice versa)? If the password is the size of an MD5 block I wouldn't doubt it, but MD5 uses a 512 bit block and most passwords (or salts) aren't exactly 64 characters.

    – AndrolGenhald
    Jun 8 at 0:10





    Are you sure about the ability to precompute MD5(password) and later add the salt (or vice versa)? If the password is the size of an MD5 block I wouldn't doubt it, but MD5 uses a 512 bit block and most passwords (or salts) aren't exactly 64 characters.

    – AndrolGenhald
    Jun 8 at 0:10













    @AndrolGenhald it would partially precompute, up to the working register that requires salt bytes

    – Richie Frame
    Jun 8 at 0:12





    @AndrolGenhald it would partially precompute, up to the working register that requires salt bytes

    – Richie Frame
    Jun 8 at 0:12




    1




    1





    @Ángel MD5_update() will not precompute unless you have a full block, anything less and it will just keep it in a buffer

    – Richie Frame
    Jun 8 at 0:28





    @Ángel MD5_update() will not precompute unless you have a full block, anything less and it will just keep it in a buffer

    – Richie Frame
    Jun 8 at 0:28




    1




    1





    @Ángel Then don't you think it's a little bit misleading to say you can precompute the partial MD5(salt)? A salt or password by itself is almost never going to be large enough to compute the first block.

    – AndrolGenhald
    Jun 8 at 0:45





    @Ángel Then don't you think it's a little bit misleading to say you can precompute the partial MD5(salt)? A salt or password by itself is almost never going to be large enough to compute the first block.

    – AndrolGenhald
    Jun 8 at 0:45




    2




    2





    @AndrolGenhald you are completely right. My answer was in a different line, and I didn't take into account this. I have edited the answer adding a paragraph about this on the part discussing if it would be a significant advantage.

    – Ángel
    Jun 8 at 0:59






    @AndrolGenhald you are completely right. My answer was in a different line, and I didn't take into account this. I have edited the answer adding a paragraph about this on the part discussing if it would be a significant advantage.

    – Ángel
    Jun 8 at 0:59












    25















    Many recommendations for storing passwords recommend hash(salt + password) rather than hash(password + salt).




    Those recommendations are evidently bad, because what they should be telling you is to use a password hashing function that's been specially designed for the purpose, like (in rough order of newer and betterish to older and worse-ish):



    • Argon2 (best)

    • scrypt

    • bcrypt (not bad but beginning to look dated)

    • PBKDF2 (far from ideal but much better than homebrew password hashing)

    These functions either:



    1. Take the password and the salt as separate arguments, and thus take care of your question internally;

    2. Give you a higher-level API that takes care of salt generation and management internally:

      • An "enrollment" function that takes a password, generates a salt, and outputs a verification string that encapsulates both salt and hash (e.g., password_hash() in PHP);

      • A "verification" function that takes a password and verification string, and verifies that the password matches the latter (e.g., password_verify() in PHP).


    If you're manually concatenating passwords and salts, you're doing it wrong.




    That said, it's generally better for a password hashing function to absorb the salt first and the password after. Why? Because that order is generically better at resisting precomputation attacks. In the password-first order, the attacker can precompute the intermediate states that correspond to common passwords, and perhaps there is some clever way of building some sort of big table that exploits this to compute their salted hashes quicker than they could otherwise. Whereas the salt-first order makes this impossible, more so if salts are random.




    Doesn't putting the salt first make it much faster for the attacker to bruteforce the password, because they can precompute the state of the hashing function with the bytes of the salt, and then each time of their billions and trillions attempts they only need to finish calculating the hash using the bytes of the password.




    No, because the point is that the attacker is not supposed to learn the salts before they steal the password database. That bit of precomputation you mention only gives a tiny speedup relative to the cost of a well-designed password hashing function, and the precomputed state is only good for attacking one individual password entry (assuming no duplicate salts, which is a requirement anyway).



    In contrast, with the password-first order, they can:



    • Precompute and store hash function states for large numbers of common passwords before they ever steal the password database;

    • Reuse the precomputed tables across password entries hashed with different salts, even across multiple password databases.





    share|improve this answer




















    • 3





      PBKDF2 should be retired. If a developer has the freedom to choose what algorithm to use then they shouldn't use it. Or any function that only stretches passwords by iterating an easily parallelized hash many times. Bcrypt is a step up - it's a simple algorithm iterated many times, but it's not one that GPUs can do easily - but many-core computers and FPGAs can attack it much more efficiently

      – Future Security
      Jun 8 at 2:01






    • 2





      @forest Even if you have SHA-1 acceleration, you should not use SHA-1. The objective here is to minimize the ratio of (attacker's hash rate)/(your hash rate). A memory-hard hash scores better than SHA-1 no matter what hardware acceleration you have. Recall that you're hashing one password at a time while the attacker isn't.

      – Navin
      Jun 8 at 15:30







    • 2





      @jpmc26: I don't actually disagree with your take on PHP, but strangely enough its modern password hashing API is exemplary and making more people aware of it does the world a lot of good.

      – Luis Casillas
      Jun 9 at 4:55






    • 2





      @Navin You're absolutely correct, and a proper memory-hard KDF beats hardware-accelerated SHA-1 any day. I was just pointing out that I disagree with the idea that one of PBKDF2's problems is its flexibility. While normally I do agree that flexibility is a bad thing in cryptography and developers shouldn't be given access to complex APIs, in this specific case, I think PBKDF2's flexibility is actually a positive for the aforementioned reasons. Also technically you could probably make PBKDF2 memory-hard since it works with any keyed PRF, not just HMAC. Consider a memory-hard keyed PRF.

      – forest
      Jun 9 at 7:24







    • 3





      One key advantage that PBKDF2 still has is that it's the only one that's NIST approved, which is relevant in orgs where compliance is important. Hopefully they'll publish a new recommendation soon, though.

      – James_pic
      Jun 10 at 10:34















    25















    Many recommendations for storing passwords recommend hash(salt + password) rather than hash(password + salt).




    Those recommendations are evidently bad, because what they should be telling you is to use a password hashing function that's been specially designed for the purpose, like (in rough order of newer and betterish to older and worse-ish):



    • Argon2 (best)

    • scrypt

    • bcrypt (not bad but beginning to look dated)

    • PBKDF2 (far from ideal but much better than homebrew password hashing)

    These functions either:



    1. Take the password and the salt as separate arguments, and thus take care of your question internally;

    2. Give you a higher-level API that takes care of salt generation and management internally:

      • An "enrollment" function that takes a password, generates a salt, and outputs a verification string that encapsulates both salt and hash (e.g., password_hash() in PHP);

      • A "verification" function that takes a password and verification string, and verifies that the password matches the latter (e.g., password_verify() in PHP).


    If you're manually concatenating passwords and salts, you're doing it wrong.




    That said, it's generally better for a password hashing function to absorb the salt first and the password after. Why? Because that order is generically better at resisting precomputation attacks. In the password-first order, the attacker can precompute the intermediate states that correspond to common passwords, and perhaps there is some clever way of building some sort of big table that exploits this to compute their salted hashes quicker than they could otherwise. Whereas the salt-first order makes this impossible, more so if salts are random.




    Doesn't putting the salt first make it much faster for the attacker to bruteforce the password, because they can precompute the state of the hashing function with the bytes of the salt, and then each time of their billions and trillions attempts they only need to finish calculating the hash using the bytes of the password.




    No, because the point is that the attacker is not supposed to learn the salts before they steal the password database. That bit of precomputation you mention only gives a tiny speedup relative to the cost of a well-designed password hashing function, and the precomputed state is only good for attacking one individual password entry (assuming no duplicate salts, which is a requirement anyway).



    In contrast, with the password-first order, they can:



    • Precompute and store hash function states for large numbers of common passwords before they ever steal the password database;

    • Reuse the precomputed tables across password entries hashed with different salts, even across multiple password databases.





    share|improve this answer




















    • 3





      PBKDF2 should be retired. If a developer has the freedom to choose what algorithm to use then they shouldn't use it. Or any function that only stretches passwords by iterating an easily parallelized hash many times. Bcrypt is a step up - it's a simple algorithm iterated many times, but it's not one that GPUs can do easily - but many-core computers and FPGAs can attack it much more efficiently

      – Future Security
      Jun 8 at 2:01






    • 2





      @forest Even if you have SHA-1 acceleration, you should not use SHA-1. The objective here is to minimize the ratio of (attacker's hash rate)/(your hash rate). A memory-hard hash scores better than SHA-1 no matter what hardware acceleration you have. Recall that you're hashing one password at a time while the attacker isn't.

      – Navin
      Jun 8 at 15:30







    • 2





      @jpmc26: I don't actually disagree with your take on PHP, but strangely enough its modern password hashing API is exemplary and making more people aware of it does the world a lot of good.

      – Luis Casillas
      Jun 9 at 4:55






    • 2





      @Navin You're absolutely correct, and a proper memory-hard KDF beats hardware-accelerated SHA-1 any day. I was just pointing out that I disagree with the idea that one of PBKDF2's problems is its flexibility. While normally I do agree that flexibility is a bad thing in cryptography and developers shouldn't be given access to complex APIs, in this specific case, I think PBKDF2's flexibility is actually a positive for the aforementioned reasons. Also technically you could probably make PBKDF2 memory-hard since it works with any keyed PRF, not just HMAC. Consider a memory-hard keyed PRF.

      – forest
      Jun 9 at 7:24







    • 3





      One key advantage that PBKDF2 still has is that it's the only one that's NIST approved, which is relevant in orgs where compliance is important. Hopefully they'll publish a new recommendation soon, though.

      – James_pic
      Jun 10 at 10:34













    25












    25








    25








    Many recommendations for storing passwords recommend hash(salt + password) rather than hash(password + salt).




    Those recommendations are evidently bad, because what they should be telling you is to use a password hashing function that's been specially designed for the purpose, like (in rough order of newer and betterish to older and worse-ish):



    • Argon2 (best)

    • scrypt

    • bcrypt (not bad but beginning to look dated)

    • PBKDF2 (far from ideal but much better than homebrew password hashing)

    These functions either:



    1. Take the password and the salt as separate arguments, and thus take care of your question internally;

    2. Give you a higher-level API that takes care of salt generation and management internally:

      • An "enrollment" function that takes a password, generates a salt, and outputs a verification string that encapsulates both salt and hash (e.g., password_hash() in PHP);

      • A "verification" function that takes a password and verification string, and verifies that the password matches the latter (e.g., password_verify() in PHP).


    If you're manually concatenating passwords and salts, you're doing it wrong.




    That said, it's generally better for a password hashing function to absorb the salt first and the password after. Why? Because that order is generically better at resisting precomputation attacks. In the password-first order, the attacker can precompute the intermediate states that correspond to common passwords, and perhaps there is some clever way of building some sort of big table that exploits this to compute their salted hashes quicker than they could otherwise. Whereas the salt-first order makes this impossible, more so if salts are random.




    Doesn't putting the salt first make it much faster for the attacker to bruteforce the password, because they can precompute the state of the hashing function with the bytes of the salt, and then each time of their billions and trillions attempts they only need to finish calculating the hash using the bytes of the password.




    No, because the point is that the attacker is not supposed to learn the salts before they steal the password database. That bit of precomputation you mention only gives a tiny speedup relative to the cost of a well-designed password hashing function, and the precomputed state is only good for attacking one individual password entry (assuming no duplicate salts, which is a requirement anyway).



    In contrast, with the password-first order, they can:



    • Precompute and store hash function states for large numbers of common passwords before they ever steal the password database;

    • Reuse the precomputed tables across password entries hashed with different salts, even across multiple password databases.





    share|improve this answer
















    Many recommendations for storing passwords recommend hash(salt + password) rather than hash(password + salt).




    Those recommendations are evidently bad, because what they should be telling you is to use a password hashing function that's been specially designed for the purpose, like (in rough order of newer and betterish to older and worse-ish):



    • Argon2 (best)

    • scrypt

    • bcrypt (not bad but beginning to look dated)

    • PBKDF2 (far from ideal but much better than homebrew password hashing)

    These functions either:



    1. Take the password and the salt as separate arguments, and thus take care of your question internally;

    2. Give you a higher-level API that takes care of salt generation and management internally:

      • An "enrollment" function that takes a password, generates a salt, and outputs a verification string that encapsulates both salt and hash (e.g., password_hash() in PHP);

      • A "verification" function that takes a password and verification string, and verifies that the password matches the latter (e.g., password_verify() in PHP).


    If you're manually concatenating passwords and salts, you're doing it wrong.




    That said, it's generally better for a password hashing function to absorb the salt first and the password after. Why? Because that order is generically better at resisting precomputation attacks. In the password-first order, the attacker can precompute the intermediate states that correspond to common passwords, and perhaps there is some clever way of building some sort of big table that exploits this to compute their salted hashes quicker than they could otherwise. Whereas the salt-first order makes this impossible, more so if salts are random.




    Doesn't putting the salt first make it much faster for the attacker to bruteforce the password, because they can precompute the state of the hashing function with the bytes of the salt, and then each time of their billions and trillions attempts they only need to finish calculating the hash using the bytes of the password.




    No, because the point is that the attacker is not supposed to learn the salts before they steal the password database. That bit of precomputation you mention only gives a tiny speedup relative to the cost of a well-designed password hashing function, and the precomputed state is only good for attacking one individual password entry (assuming no duplicate salts, which is a requirement anyway).



    In contrast, with the password-first order, they can:



    • Precompute and store hash function states for large numbers of common passwords before they ever steal the password database;

    • Reuse the precomputed tables across password entries hashed with different salts, even across multiple password databases.






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Jun 9 at 5:04

























    answered Jun 8 at 1:29









    Luis CasillasLuis Casillas

    7,5422 gold badges19 silver badges30 bronze badges




    7,5422 gold badges19 silver badges30 bronze badges







    • 3





      PBKDF2 should be retired. If a developer has the freedom to choose what algorithm to use then they shouldn't use it. Or any function that only stretches passwords by iterating an easily parallelized hash many times. Bcrypt is a step up - it's a simple algorithm iterated many times, but it's not one that GPUs can do easily - but many-core computers and FPGAs can attack it much more efficiently

      – Future Security
      Jun 8 at 2:01






    • 2





      @forest Even if you have SHA-1 acceleration, you should not use SHA-1. The objective here is to minimize the ratio of (attacker's hash rate)/(your hash rate). A memory-hard hash scores better than SHA-1 no matter what hardware acceleration you have. Recall that you're hashing one password at a time while the attacker isn't.

      – Navin
      Jun 8 at 15:30







    • 2





      @jpmc26: I don't actually disagree with your take on PHP, but strangely enough its modern password hashing API is exemplary and making more people aware of it does the world a lot of good.

      – Luis Casillas
      Jun 9 at 4:55






    • 2





      @Navin You're absolutely correct, and a proper memory-hard KDF beats hardware-accelerated SHA-1 any day. I was just pointing out that I disagree with the idea that one of PBKDF2's problems is its flexibility. While normally I do agree that flexibility is a bad thing in cryptography and developers shouldn't be given access to complex APIs, in this specific case, I think PBKDF2's flexibility is actually a positive for the aforementioned reasons. Also technically you could probably make PBKDF2 memory-hard since it works with any keyed PRF, not just HMAC. Consider a memory-hard keyed PRF.

      – forest
      Jun 9 at 7:24







    • 3





      One key advantage that PBKDF2 still has is that it's the only one that's NIST approved, which is relevant in orgs where compliance is important. Hopefully they'll publish a new recommendation soon, though.

      – James_pic
      Jun 10 at 10:34












    • 3





      PBKDF2 should be retired. If a developer has the freedom to choose what algorithm to use then they shouldn't use it. Or any function that only stretches passwords by iterating an easily parallelized hash many times. Bcrypt is a step up - it's a simple algorithm iterated many times, but it's not one that GPUs can do easily - but many-core computers and FPGAs can attack it much more efficiently

      – Future Security
      Jun 8 at 2:01






    • 2





      @forest Even if you have SHA-1 acceleration, you should not use SHA-1. The objective here is to minimize the ratio of (attacker's hash rate)/(your hash rate). A memory-hard hash scores better than SHA-1 no matter what hardware acceleration you have. Recall that you're hashing one password at a time while the attacker isn't.

      – Navin
      Jun 8 at 15:30







    • 2





      @jpmc26: I don't actually disagree with your take on PHP, but strangely enough its modern password hashing API is exemplary and making more people aware of it does the world a lot of good.

      – Luis Casillas
      Jun 9 at 4:55






    • 2





      @Navin You're absolutely correct, and a proper memory-hard KDF beats hardware-accelerated SHA-1 any day. I was just pointing out that I disagree with the idea that one of PBKDF2's problems is its flexibility. While normally I do agree that flexibility is a bad thing in cryptography and developers shouldn't be given access to complex APIs, in this specific case, I think PBKDF2's flexibility is actually a positive for the aforementioned reasons. Also technically you could probably make PBKDF2 memory-hard since it works with any keyed PRF, not just HMAC. Consider a memory-hard keyed PRF.

      – forest
      Jun 9 at 7:24







    • 3





      One key advantage that PBKDF2 still has is that it's the only one that's NIST approved, which is relevant in orgs where compliance is important. Hopefully they'll publish a new recommendation soon, though.

      – James_pic
      Jun 10 at 10:34







    3




    3





    PBKDF2 should be retired. If a developer has the freedom to choose what algorithm to use then they shouldn't use it. Or any function that only stretches passwords by iterating an easily parallelized hash many times. Bcrypt is a step up - it's a simple algorithm iterated many times, but it's not one that GPUs can do easily - but many-core computers and FPGAs can attack it much more efficiently

    – Future Security
    Jun 8 at 2:01





    PBKDF2 should be retired. If a developer has the freedom to choose what algorithm to use then they shouldn't use it. Or any function that only stretches passwords by iterating an easily parallelized hash many times. Bcrypt is a step up - it's a simple algorithm iterated many times, but it's not one that GPUs can do easily - but many-core computers and FPGAs can attack it much more efficiently

    – Future Security
    Jun 8 at 2:01




    2




    2





    @forest Even if you have SHA-1 acceleration, you should not use SHA-1. The objective here is to minimize the ratio of (attacker's hash rate)/(your hash rate). A memory-hard hash scores better than SHA-1 no matter what hardware acceleration you have. Recall that you're hashing one password at a time while the attacker isn't.

    – Navin
    Jun 8 at 15:30






    @forest Even if you have SHA-1 acceleration, you should not use SHA-1. The objective here is to minimize the ratio of (attacker's hash rate)/(your hash rate). A memory-hard hash scores better than SHA-1 no matter what hardware acceleration you have. Recall that you're hashing one password at a time while the attacker isn't.

    – Navin
    Jun 8 at 15:30





    2




    2





    @jpmc26: I don't actually disagree with your take on PHP, but strangely enough its modern password hashing API is exemplary and making more people aware of it does the world a lot of good.

    – Luis Casillas
    Jun 9 at 4:55





    @jpmc26: I don't actually disagree with your take on PHP, but strangely enough its modern password hashing API is exemplary and making more people aware of it does the world a lot of good.

    – Luis Casillas
    Jun 9 at 4:55




    2




    2





    @Navin You're absolutely correct, and a proper memory-hard KDF beats hardware-accelerated SHA-1 any day. I was just pointing out that I disagree with the idea that one of PBKDF2's problems is its flexibility. While normally I do agree that flexibility is a bad thing in cryptography and developers shouldn't be given access to complex APIs, in this specific case, I think PBKDF2's flexibility is actually a positive for the aforementioned reasons. Also technically you could probably make PBKDF2 memory-hard since it works with any keyed PRF, not just HMAC. Consider a memory-hard keyed PRF.

    – forest
    Jun 9 at 7:24






    @Navin You're absolutely correct, and a proper memory-hard KDF beats hardware-accelerated SHA-1 any day. I was just pointing out that I disagree with the idea that one of PBKDF2's problems is its flexibility. While normally I do agree that flexibility is a bad thing in cryptography and developers shouldn't be given access to complex APIs, in this specific case, I think PBKDF2's flexibility is actually a positive for the aforementioned reasons. Also technically you could probably make PBKDF2 memory-hard since it works with any keyed PRF, not just HMAC. Consider a memory-hard keyed PRF.

    – forest
    Jun 9 at 7:24





    3




    3





    One key advantage that PBKDF2 still has is that it's the only one that's NIST approved, which is relevant in orgs where compliance is important. Hopefully they'll publish a new recommendation soon, though.

    – James_pic
    Jun 10 at 10:34





    One key advantage that PBKDF2 still has is that it's the only one that's NIST approved, which is relevant in orgs where compliance is important. Hopefully they'll publish a new recommendation soon, though.

    – James_pic
    Jun 10 at 10:34











    1














    While the above answers do raise some valid points they do not seem to be entirely correct and it should be noted that there do in fact exist weaknesses in certain hash functions that make a significant difference in the cracking speeds for "$pass.$salt" or "$salt.$pass".



    See for example md5. According to atom (https://hashcat.net/forum/thread-8365.html), creator of the hashcat password cracking software:




    The way how hashcat exploits some weakness in MD5 to get additional acceleration requires it to change only the first 4 bytes of the input data. Since this part is fixed (because of the salt) it cannot use the acceleration.




    That does reflect significantly in the cracking speed.

    On a Titan RTX the speed for md5($pass.$salt) is with 63819.9 MH/s almost double the speed as for md5($salt.$pass) with "only" 34696.2 MH/s.



    Similar differences exist for other hash algorithms. The developers and community of password cracking software spend a significant amount of time to find weaknesses and shortcuts to improve speed. So from a cracking perspective it can be a good idea to look at current hashcat benchmarks like this one https://gist.github.com/Chick3nman/5d261c5798cf4f3867fe7035ef6dd49f and compare the speeds for the different Salt-Password-Variants.

    If that link goes missing, you can also generate your own benchmark with the following command:



    hashcat -b





    share|improve this answer



























      1














      While the above answers do raise some valid points they do not seem to be entirely correct and it should be noted that there do in fact exist weaknesses in certain hash functions that make a significant difference in the cracking speeds for "$pass.$salt" or "$salt.$pass".



      See for example md5. According to atom (https://hashcat.net/forum/thread-8365.html), creator of the hashcat password cracking software:




      The way how hashcat exploits some weakness in MD5 to get additional acceleration requires it to change only the first 4 bytes of the input data. Since this part is fixed (because of the salt) it cannot use the acceleration.




      That does reflect significantly in the cracking speed.

      On a Titan RTX the speed for md5($pass.$salt) is with 63819.9 MH/s almost double the speed as for md5($salt.$pass) with "only" 34696.2 MH/s.



      Similar differences exist for other hash algorithms. The developers and community of password cracking software spend a significant amount of time to find weaknesses and shortcuts to improve speed. So from a cracking perspective it can be a good idea to look at current hashcat benchmarks like this one https://gist.github.com/Chick3nman/5d261c5798cf4f3867fe7035ef6dd49f and compare the speeds for the different Salt-Password-Variants.

      If that link goes missing, you can also generate your own benchmark with the following command:



      hashcat -b





      share|improve this answer

























        1












        1








        1







        While the above answers do raise some valid points they do not seem to be entirely correct and it should be noted that there do in fact exist weaknesses in certain hash functions that make a significant difference in the cracking speeds for "$pass.$salt" or "$salt.$pass".



        See for example md5. According to atom (https://hashcat.net/forum/thread-8365.html), creator of the hashcat password cracking software:




        The way how hashcat exploits some weakness in MD5 to get additional acceleration requires it to change only the first 4 bytes of the input data. Since this part is fixed (because of the salt) it cannot use the acceleration.




        That does reflect significantly in the cracking speed.

        On a Titan RTX the speed for md5($pass.$salt) is with 63819.9 MH/s almost double the speed as for md5($salt.$pass) with "only" 34696.2 MH/s.



        Similar differences exist for other hash algorithms. The developers and community of password cracking software spend a significant amount of time to find weaknesses and shortcuts to improve speed. So from a cracking perspective it can be a good idea to look at current hashcat benchmarks like this one https://gist.github.com/Chick3nman/5d261c5798cf4f3867fe7035ef6dd49f and compare the speeds for the different Salt-Password-Variants.

        If that link goes missing, you can also generate your own benchmark with the following command:



        hashcat -b





        share|improve this answer













        While the above answers do raise some valid points they do not seem to be entirely correct and it should be noted that there do in fact exist weaknesses in certain hash functions that make a significant difference in the cracking speeds for "$pass.$salt" or "$salt.$pass".



        See for example md5. According to atom (https://hashcat.net/forum/thread-8365.html), creator of the hashcat password cracking software:




        The way how hashcat exploits some weakness in MD5 to get additional acceleration requires it to change only the first 4 bytes of the input data. Since this part is fixed (because of the salt) it cannot use the acceleration.




        That does reflect significantly in the cracking speed.

        On a Titan RTX the speed for md5($pass.$salt) is with 63819.9 MH/s almost double the speed as for md5($salt.$pass) with "only" 34696.2 MH/s.



        Similar differences exist for other hash algorithms. The developers and community of password cracking software spend a significant amount of time to find weaknesses and shortcuts to improve speed. So from a cracking perspective it can be a good idea to look at current hashcat benchmarks like this one https://gist.github.com/Chick3nman/5d261c5798cf4f3867fe7035ef6dd49f and compare the speeds for the different Salt-Password-Variants.

        If that link goes missing, you can also generate your own benchmark with the following command:



        hashcat -b






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Jun 16 at 12:00









        DenisDenis

        3,3832 gold badges13 silver badges15 bronze badges




        3,3832 gold badges13 silver badges15 bronze badges



























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Information Security Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsecurity.stackexchange.com%2fquestions%2f211478%2fdoes-putting-salt-first-make-it-easier-for-attacker-to-bruteforce-the-hash%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Wikipedia:Vital articles Мазмуну Biography - Өмүр баян Philosophy and psychology - Философия жана психология Religion - Дин Social sciences - Коомдук илимдер Language and literature - Тил жана адабият Science - Илим Technology - Технология Arts and recreation - Искусство жана эс алуу History and geography - Тарых жана география Навигация менюсу

            Bruxelas-Capital Índice Historia | Composición | Situación lingüística | Clima | Cidades irmandadas | Notas | Véxase tamén | Menú de navegacióneO uso das linguas en Bruxelas e a situación do neerlandés"Rexión de Bruxelas Capital"o orixinalSitio da rexiónPáxina de Bruselas no sitio da Oficina de Promoción Turística de Valonia e BruxelasMapa Interactivo da Rexión de Bruxelas-CapitaleeWorldCat332144929079854441105155190212ID28008674080552-90000 0001 0666 3698n94104302ID540940339365017018237

            What should I write in an apology letter, since I have decided not to join a company after accepting an offer letterShould I keep looking after accepting a job offer?What should I do when I've been verbally told I would get an offer letter, but still haven't gotten one after 4 weeks?Do I accept an offer from a company that I am not likely to join?New job hasn't confirmed starting date and I want to give current employer as much notice as possibleHow should I address my manager in my resignation letter?HR delayed background verification, now jobless as resignedNo email communication after accepting a formal written offer. How should I phrase the call?What should I do if after receiving a verbal offer letter I am informed that my written job offer is put on hold due to some internal issues?Should I inform the current employer that I am about to resign within 1-2 weeks since I have signed the offer letter and waiting for visa?What company will do, if I send their offer letter to another company