Serious Security: How to store your users' passwords safely

Filed Under: Adobe, Cryptography, Featured

You probably didn't miss the news - and the fallout that followed - about Adobe's October 2013 data breach.

Not only was it one of the largest breaches of username databases ever, with 150,000,000 records exposed, it was also one of the most embarrassing.

The leaked data revealed that Adobe had been storing its users' passwords ineptly - something that was surprising, because storing passwords much more safely would have been no more difficult.

Following our popular article explaining what Adobe did wrong, a number of readers asked us, "Why not publish an article showing the rest of us how to do it right?"

Here you are!

Just to clarify: this article isn't a programming tutorial with example code you can copy to use on your own server.

Firstly, we don't know whether your're using PHP, MySQL, C#, Java, Perl, Python or whatever, and secondly, there are lots of articles already available that tell you what to do with passwords.

We thought that we'd explain, instead.

Attempt One - store the passwords unencrypted

On the grounds that you intend - and, indeed, you ought - to prevent your users' passwords from being stolen in the first place, it's tempting just to keep your user database in directly usable form, like this:

If you are running a small network, with just a few users whom you known well, and whom you support in person, you might even consider it an advantage to store passwords unencrypted.

That way, if someone forgets their password, you can just look it up and tell them what it is.

Don't do this, for the simple reason that anyone who gets to peek at the file immediately knows how to login as any user.

Worse still, they get a glimpse into the sort of password that each user seems to favour, which could help them guess their way into other accounts belonging to that user.

Alfred, for example, went for his name followed by a short sequence number; David used a date that probably has some personal significance; Eric Cleese followed a Monty Python theme; while Charlie and Duck didn't seem to care at all.

The point is that neither you, nor any of your fellow system administrators, should be able to look up a user's password.

It's not about trust, it's about definition: a password ought to be like a PIN, treated as a personal identification detail that is no-one else's business.

Attempt Two - encrypt the passwords in the database

Encrypting the passwords sounds much better.

You could even arrange to have the decryption key for the database stored on another server, get your password verification server to retrieve it only when needed, and only ever keep it in memory.

That way, users' passwords never need to be written to disk in unencrypted form; you can't accidentally view them in the database; and if the password data should get stolen, it would just be shredded cabbage to the crooks.

This is the approach Adobe took, ending up with something similar to this:

→ For the sample data above we chose the key DESPAIR and encrypted each of the passwords with straight DES. Using DES for anything in the real world is a bad idea, because it only uses 56-bit keys, or seven characters' worth. Even though 56 bits gives close to 100,000 million million possible passwords, modern cracking tools can get through that many DES passwords within a day.

You might consider this sort of symmetric encryption an advantage because you can automatically re-encrypt every password in the database if ever you decide to change the key (you may even have policies that require that), or to shift to a more secure algorithm to keep ahead of cracking tools.

But don't encrypt your password databases reversibly like this.

You haven't solved the problem we mentioned in Attempt One, namely that neither you, nor any of your fellow system administrators, should be able to recover a user's password.

Worse still, if crooks manage to steal your database and to acquire the password at the same time, for example by logging into your server remotely, then Attempt Two just turns into Attempt One.

By the way, the password data above has yet another problem, namely that we used DES in such a way that the same password produces the same data every time.

We can therefore tell automatically that Charlie and Duck have the same password, even without the decryption key, which is a needless information leak - as is the fact that the length of the encrypted data gives us a clue about the length of the unencrypted password.

We will therefore insist on the following requirements:

  1. Users' passwords should not be recoverable from the database.
  2. Identical, or even similar, passwords should have different hashes.
  3. The database should give no hints as to password lengths.

Attempt Three - hash the passwords

Requirement One above specifies that "users' passwords should not be recoverable from the database."

At first glance, this seems to demand some sort of "non-reversible" encryption, which sounds somewhere between impossible and pointless.

But it can be done with what's known as a cryptographic hash, which takes an input of arbitrary length, and mixes up the input bits into a sort of digital soup.

As it runs, the algorithms strains off a fixed amount of random-looking output data, finishing up with a hash that acts as a digital fingerprint for its input.

Mathematically, a hash is a one-way function: you can work out the hash of any message, but you can't go backwards from the final hash to the input data.

A cryptographic hash is carefully designed to resist even deliberate attempts to subvert it, by mixing, mincing, shredding and liquidising its input so thoroughly that, at least in theory:

  • You can't create a file that comes out with a predefined hash by any method better than chance.
  • You can't find two files that "collide", i.e. have the same hash (whatever it might be), by any method better than chance.
  • You can't work out anything about the structure of the input, including its length, from the hash alone.

Well-known and commonly-used hashing algorithms are MD5, SHA-1 and SHA-256.

Of these, MD5 has been found not to have enough "mix-mince-shred-and-liquidise" in its algorithm, with the result that you can find two files with the same hash very much faster than by chance.

This means it does not meet its original cryptographic promise - so do not use it in any new project.

SHA-1 is computationally quite similar to MD5, and many experts consider that it might soon be found to have similar problems to MD5 - so you may as well avoid it.

We'll use SHA-256, which gives us this if we apply it directly to our sample data (the hash has been truncated to make it fit neatly in the diagram):

The hashes are all the same length, so we aren't leaking any data about the size of the password.

Also, because we can predict in advance how much password data we will need to store for each password, there is now no excuse for needlessly limiting the length of a user's password. (All SHA-256 values have 256 bits, or 32 bytes.)

→ It's OK to set a high upper bound on password length, e.g. 128 or 256 characters, to prevent malcontents from burdening your server with pointlessly large chunks of password data. But limits such as "no more than 16 characters" are overly restrictive and should be avoided.

To verify a user's password at login, we keep the user's submitted password in memory - so it never needs to touch the disk - and compute its hash.

If the computed hash matches the stored hash, the user has fronted up with the right password, and we can let him login.

But Attempt Three still isn't good enough, because Charlie and Duck still have the same hash, leaking that they chose the same password.

Indeed, the text password will always come out as 5E884898DA28..EF721D1542D8, whenever anyone chooses it.

That means the crooks can pre-calculate a table of hashes for popular passwords - or even, given enough disk space, of all passwords up to a certain length - and thus crack any password already on their list with a single database lookup.

Attempt Four - salt and hash

We can adapt the hash that comes out for each password by mixing in some additional data known as a salt, so called because it "seasons" the hash output.

A salt is also known as a nonce, which is short for "number used once."

Simply put, we generate a random string of bytes that we include in our hash calculation along with the actual password.

The easiest way is to put the salt in front of the password and hash the combined text string.

The salt is not an encryption key, so it can be stored in the password database along with the username - it serves merely to prevent two users with the same password getting the same hash.

For that to happen they would need the same password and the same salt, so if we use 16 bytes or more of salt, the chance of that happening is small enough to be ignored.

Our database now looks like this (the 16-byte salts and the hashes have been truncated to fit neatly):

The hashes in this list, being the last field in each line, are calculated by creating a text string consisting of the salt followed by the password, and calculating its SHA-256 hash - so Charlie and Duck now get completely different password data.

Make sure you choose random salts - never use a counter such as 000001, 000002, and so forth, and don't use a low-quality random number generator like C's random().

If you do, your salts may match those in other password databases you keep, and could in any case be predicted by an attacker.

By using sufficiently many bytes from a decent source of random numbers - if you can, use CryptoAPI on Windows or /dev/urandom on Unix-like systems - you as good as guarantee that each salt is unique, and thus that it really is a "number used once."

Are we there yet?

Nearly, but not quite.

Although we have satisfied our three requirements (non-reversibility, no repeated hashes, and no hint of password length), the hash we have chosen - a single SHA-256 of salt+password - can be calculated very rapidly.

In fact, modern hash-cracking servers costing under $20,000 can compute 100,000,000,000 or more SHA-256 hashes each second.

We need to slow things down a bit to stymie the crackers.

Attempt Five - hash stretching

The nature of a cryptographic hash means that attackers can't go backwards, but with a bit of luck - and some poor password choices - they can often achieve the same result simply by trying to go forwards over and over again.

Indeed, if the crooks manage to steal your password database and can work offline, there is no limit other than CPU power to how fast they can guess passwords and see how they hash.

By this, we mean that they can try combining every word in a dictionary (or every password from AA..AA to ZZ..ZZ) with every salt in your database, calculating the hashes and seeing if they get any hits.

And password dictionaries, or algorithms to generate passwords for cracking, tend to be organised so that the most commonly-chosen passwords come out as early as possible.

That means that users who have chosen uninventively will tend to get cracked sooner.

→ Note that even at one million million password hash tests per second, a well-chosen password will stay out of reach pretty much indefinitely. There are more than one thousand million million million 12-character passwords based on the character set A-Za-z0-9.

It therefore makes sense to slow down offline attacks by running our password hashing algorithm as a loop that requires thousands of individual hash calculations.

That won't make it so slow to check an individual user's password during login that the user will complain, or even notice.

But it will reduce the rate at which a crook can carry out an offline attack, in direct proportion to the number of iterations you choose.

However, don't try to invent your own algorithm for repeated hashing.

Choose one of these three well-known ones: PBKDF2, bcrypt or scrypt.

We'll recommend PBKDF2 here because it is based on hashing primitives that satisfy many national and international standards.

We'll recommend using it with the HMAC-SHA-256 hashing algorithm, repeated 10,000 times or more.

HMAC-SHA-256 is a special way of using the SHA-256 algorithm that isn't just a straight hash, but allows the hash to be combined comprehensively with a key or salt:

  • Take a random key or salt K, and flip some bits, giving K1.
  • Compute the SHA-256 hash of K1 plus your data, giving H1.
  • Flip a different set of bits in K, giving K2.
  • Compute the SHA-256 hash of K2 plus H1, giving the final hash, H2.

In short, you hash a key plus your message, and then rehash a permuted version of the key plus the first hash.

In PBKDF2 with 10,000 iterations, we feed the user's password and our salt into HMAC-SHA-256 and make the first of the 10,000 loops.

Then we feed the password and the previously-computed HMAC hash back into HMAC-SHA-256 for the remaining 9999 times round the loop.

Every time round the loop, the latest output is XORed with the previous one to keep a running "hash accumulator"; when we are done, the accumulator becomes the final PBKDF2 hash.

Now we need to add the iteration count, the salt and the final PBKDF2 hash to our password database:

As the computing power available to attackers increases, you can increase the number of iterations you use - for example, by doubling the count every year.

When users with old-style hashes log in successfully, you simply regenerate and update their hashes using the new iteration count. (During successful login is the only time you can tell what a user's password actually is.)

For users who haven't logged in for some time, and whose old hashes you now considered insecure, you can disable the accounts and force the users through a password reset procedure if ever they do log on again.

The last word

In summary, here is our minimum recommendation for safe storage of your users' passwords:

  • Use a strong random number generator to create a salt of 16 bytes or longer.
  • Feed the salt and the password into the PBKDF2 algorithm.
  • Use HMAC-SHA-256 as the core hash inside PBKDF2.
  • Perform 10,000 iterations or more. (November 2013.)
  • Take 32 bytes (256 bits) of output from PBKDF2 as the final password hash.
  • Store the iteration count, the salt and the final hash in your password database.
  • Increase your iteration count regularly to keep up with faster cracking tools.

Whatever you do, don't try to knit your own password storage algorithm.

It didn't end well for Adobe, and it is unlikely to end well for you.

Image of magnifying glass outline courtesy of Shutterstock.

, , , , , , ,

You might like

45 Responses to Serious Security: How to store your users' passwords safely

  1. Jeroen · 647 days ago

    "Also, because we can predict in advance how much password data we will need to store for each password, there is now no excuse for limiting the length of a user's password. (All SHA-256 values have 256 bits, or 32 bytes.)"

    Wouldn't you limit the maximum password length to say 128 or so to prevent a denial of service attack? If the verification code allows for unbounded passwords and an attacker sends a megabyte of garbage in place of the password, then pkbdf2 with 10k rounds might well become the site's Achilles' heel.

    • Paul Ducklin · 647 days ago

      Good points. I probably ought to have dealt with them in the article, but it had got long enough already, so I committed what I think you call a "sin of omission."

      I agree that allowing, say, a 1MB passphrase is pointless - and potentially time-consuming - especially as the hash you finally store if you follow my guidelines is only 32 bytes.

      I think I shall change the wording to say something like, "There is no excuse for needlessly limiting password lengths as some sites do, e.g. to 10 or to 16 characters." (I have seen both.)

      I'd agree that, say, 128 or even 256 characters is hardly a limit - it's more a sort of test of reasonableness :-)

  2. A nice and easy to digest explanation.
    Good job Paul!

  3. Peter · 647 days ago

    Excellent article!

  4. Alan · 647 days ago

    Also see OWASP Password Storage Cheat Sheet (and linked "Secure Password Storage Threat Model"):

  5. Anonymous · 647 days ago

    Very good plain english explanation. Thank you!

  6. Benjamin · 647 days ago

    Why couldn't we use some of the user's information as salt? For example, the hash could be calculated from the concatenation of information with one of these methods:

    (login name)(password)
    (subscription date)(password)
    (subscription date)(a fixed key, like the name of the site)(password)
    (login name minus x letters)(subscription date)(password)

    Of course, this algorithm should be known only by the developer. What would be wrong with that method?

    Also, would it be OK to store users details and the password hashes on separate servers? Thank you for your answers!

    • Paul Ducklin · 647 days ago

      The point is that the salt isn't supposed to mean anything - in fact, it shouldn't mean anything, or be guessable, so that it really is a nonce - "number used once."

      Its purpose is to make the combination of salt+yourpassword unique *even if you choose a password that is commonplace*.

      In your example, you suggest "salt = subscription date + a fixed key." So everyone who signs up on that day will have the same salt.

      In short: use a decent-quality random string, and that's that.

      And never rely on algorithms known only to the developer. Firstly, that's poor software engineering, because it makes the code unmaintainable. Secondly, it's security through obscurity, which fails totally as soon as the obscurity is removed.

      Lastly, as for storing the usernames and the hashes in separate databases - why not? (As long as you remember that the combined security generally equals the security of the weaker server, not the stronger one :-)

      • Benjamin · 647 days ago

        OK, thank you for your explanation! It's very clear, as well as your article. I know that your article is meant for every language, but as for PHP, I found a function that already implements your advice for handling passwords: hash_pbkdf2(), so that's perfect. Great article!

        • Paul Ducklin · 647 days ago

          That was our plan - read, understand the back-story, and then find a trusted implementation that's already available. You did the right thing.

          So many people seem to read up about cryptography, realise it's actually quite hard, start looking for ready-written libraries...and then say, "Nah, it'll be more fun to try to carve my own algorithm out of string and some offcuts of wood I've been keeping at the back of the shed :-)

          By the way, if you are looking for test output (to verify that your PBKDF2 calculations are probably working OK), you will only find "official" results for PBKDF2-HMAC-SHA-1, published as an RFC:

          You may have to shop around a bit - searching for PBKDF2-HMAC-SHA-256 test vectors" is a way to start.

      • artur · 89 days ago

        but date could be much more granulated, microseconds differences would make the salt completely different from a subscription to other

  7. 4caster · 647 days ago

    You lost me as soon as you mentioned the word "hash". I thought it meant Number, symbol #.

  8. Randy · 647 days ago

    What services does Adobe provide that require it's customers to have a username and password? In other words, who exactly is at risk?

    • Software purchases, cloud storage, software as a service, discussion and support forums, training, conferences for software developers, graphic designers, artists, managers, etc. Anyone who writes software for Flash or ColdFusion, anyone designing with Illustrator or Photoshop, anyone in charge of purchasing said software for a company, etc. is likely to have an account.

      • Randy · 646 days ago

        Thanks Kelson. My only association with Adobe is the fact that I use their free reader and flash player. I did get an email from them recently warning me that my username/password may have been compromised and it contained a link to a page where I could reset my login credentials. It looked legit but the purpose of the email sounded like Phishing to me. Since I wasn't aware that I even had an account with them I ignored their email.

  9. Walter Wood · 647 days ago

    Thanks for a well written explanation.

    I am working on my first Joomla (3.2) site and I am not real familiar with how passwords are stored in Joomla. As I understand it, Joomla uses an MD5 hash and it is salted. If my understanding is correct, since the MD5 hash is not safe, does it become safe once it is salted?

    • Paul Ducklin · 647 days ago

      MD5 bcomes safe against collisions if it is used in an HMAC (key-hash-key-hash) construction.

      Thing is, there is simply no need to use MD5 when less controversial alternatives exist, with or without HMAC. Since one of MD5's stated design goals was to be collision resistant, the fact that it is not means that cryptographic prudence says: assume it is insecure in general.

      That's why any crypto expert (and any number of standards bodies) will tell you, "Do not use MD5 for anything new."

      As far as I can see, Joomla seems to consider salting passwords to be the sort of thing that deserves the name "Enhanced Password System," which doesn't fill me with much confidence about the cryptographic aptitude of the Joomla creators - to me, salting passwords deserves the name "heading in the right cryptographic direction but not there yet" :-)

  10. Nigel Pentland · 647 days ago

    Nice article. Also, something tells me it's no coincidence that Sourceforge's Project of the month for November 2013 is Password Safe - well deserved -

    • Paul Ducklin · 647 days ago

      Well, between Adobe (150,000,000 password records ineptly stored) and Loyaltybuild (actually even worse - close to 500,000 records, including credit card numbers *and CVV codes* not encrypted at all) it is quite the month for revisiting data storage safety!

      The LoyaltyBuild story is here if you want to indulge yourself in some righteous indignation and a spot of huffing-and-puffing:

  11. Bevin · 647 days ago

    I would have thought storing the salt and iterations in the password file would make it pointless. If the bad guy knows the salt he could just add it himself.

    • Paul Ducklin · 647 days ago

      As explained, the salt is not a secret or a "key". It's there so that if two users choose the same password, they get a different hash.

      Yes, a crook can add it himself - but the point is he *has* to add it himself, a different salt for each user. So he can't use a lookup table (e.g. a rainbow table).

      You can certainly store the salts somewhere else if you like, though you need them accessible at the same time as the rest of the database, so they're likely to end up on the same server, where they would likely be stolen at the same time by the same method. So it is not poor practice to keep them in with the hashes and the usernames.

      Now, if you wanted to encrypt *the whole database as well*, with a remotely stored key, that would give additional protection in the case that a crook stole the database file without the key. But inside the database you'd still want salted hashes and a multi-iteration hashing algorithm.

  12. Andrew Yeomans · 646 days ago

    A good summary of generally accepted practice today, Paul, but I think we need to go further.

    [This comment edited for length]

    Attempt Six - Protect from theft of database or backup tapes with a secret

    Insiders or hackers may steal the entire file, and have all the information needed to crack it off-line with their parallel GPU systems. So make it harder, by not providing all the information. "Security by obscurity" should not be the entire defence, but it does make it harder for the attacker.

    Attempt Seven - Protect additional information

    The Adobe breach revealed far too much information as the email addresses and password hints were completely unprotected.

    Attempt Eight - Protect and detect breach attempts

    Only a small set of programs ought to be able to access the password database. So use operating system level protections to their fullest.

    Attempt Nine - Isolate system and use hardware protection

    Rather than keep the password hashes on the same system as the web server (etc), have a dedicated system that just performs authentication requests.

    If done well, it should be infeasible for even the server administrators to get access to the password hash file. If you've gone to this level of protection, you could then consider reducing your password complexity rules, as those cracking attacks just won't happen!

    • Paul Ducklin · 646 days ago

      Ah! Perhaps this might be Part Two. (I know it's a one part article. But if "The Matrix" can have a sequel - wasn't that silly, though? they told you how it all ends at the close of the first film! - perhaps this one can too.)

      I disagree strongly with one thing, though: "you could then consider reducing your password complexity rules, as those cracking attacks just won't happen."

      Reducing the complexity rules just sets a low standard for your users. And never say never.

      • Andrew Yeomans · 646 days ago

        Rule complexity? Well, credit / debit card PINs are 4 digits and pragmatically work pretty well still. But they use hardware protection coupled with blocking access after a few wrong attempts.

        It depends whch threat you are defending against. For online systems, long complex passwords basically defend against the failure of suppliers to implement the above rules, i.e defend against poor practice. (Complex passwords are still needed for static data, e.g. encrypted files, where blocking access isn't possible.)

  13. Gregory · 646 days ago

    I keep seeing that Adobe lost credit card data too, but not a lot of sites are making a big deal out of the stolen credit cards, just the stolen passwords. After reading conflicting stories, now I don't know if credit card number were actually stolen or not. If they were stolen, is there any reason to think Adobe did a better job encrypting my credit card than they did my password?

    • Paul Ducklin · 646 days ago

      A very good question! (Sadly, a rhetorical one, I expect, even if you were hoping for an answer.)

      For the record, we were pretty keen to remind people that the credit card data breach could be considered worse than that of the passwords. And we asked exactly the same question that you did - what if the CC data was encrypted as shabbily as the about how well they did. We don't know the answer. We may never know, unless Adobe decide to tell us more.

      Some of our thoughts on this can be found in amongst these (one article and one podcast):

      • Andrew Yeomans · 646 days ago

        Adobe claimed to be notifying people whose credit card details were stolen. But not the others in the stolen file.

        Note also that some email addresses in the file contain typos. In these cases I doubt any notification would succeed, unless Adobe did it through the credit card companies.

  14. Anonymous · 623 days ago

    Just a small note that nonce does not mean "number used once" but means ... nonces (

    • Paul Ducklin · 623 days ago

      Errrrrrr, you can't have a definition that says "nonce means...nonces" (it's circular :-)

      There are three distinct meanings that I know of for the word "nonce," viz:

      1. nonce [n]: short for "nonsense word".

      2. nonce [n]: (cryptography) contraction of "number used once" .

      3. nonce [n]: (British slang) a child sex offender.

      The correct meaning in this case ought to be obvious.

      • Anonymous · 620 days ago

        Did you clicked on the link ?

        What I meant is: the regular English word "nonce" exactly matches the cryptographic usage, making any other etymology highly suspect.

        "A nonce word is a lexeme created for a single occasion to solve an immediate problem of communication."

        It's an 800-year-old word (

        You missing one definition (the good one) in your list. Number two is an "uncited" definition that people constantly copy without knowing...

  15. Naz · 623 days ago

    question, regardless of the hashing algorithm (MD5 or stronger), if someone obtains my database and php code, will they be able to reverse the hash no matter how strong it is?


    • Danny · 597 days ago

      The hash cannot be reversed. If they get your PHP file, they will just see that you use the iteration algorithm + salt to create the final hash. In order to find a user's password they will still need to run through all possible password combinations, attach the salt, do the 10000 iterations per each combination of password + salt per user...

  16. MickTravels · 606 days ago

    Great article. I have a question from the other side:

    I have to use a website that doesn't follow these procedures. I can point them to this article and explain until the cows come home, they won't change. How can I protect myself and my information on this site?

    • Paul Ducklin · 606 days ago

      Difficult question. Assuming that this site actually retains PII (personally identifiable information) such as your date of birth, credit card number, home address...there isn't a lot you can do, except to be aware that if they can't be bothered to store your password correctly, it's reasonable to assume they'll be careless with your other information.

      Do you give bogus information so they can't leak genuine PII about you? (You shouldn't have to, but it might be prudent in this case.) Do you get a debit card specifically for this site, and keep it at a low balance? (Again, this could be prudent.)

      I guess it all depends on how much is at stake...

  17. Randy · 417 days ago

    A friend of mine writes his passwords down on a sheet of paper and stores it in his desk. A hacker would have to find his physical address, break into his house and search it to get his passwords. That's something most hackers are not willing to do.Sometimes simpler is better.

    • GJ · 319 days ago

      Randy.. We're talking from the point of view of the website where the username and password are required. The article tells websites how they must write code to make sure a hacker can't steal your friend's password from the website's database.

      Were you being sarcastic?

  18. Richard · 409 days ago

    Fantastic article, well explained.

    As a side topic, and related to MickTravels' question - given a database that upholds all of these password techniques, and stores some personally identifiable information about me (email, DOB, address, etc) - if the database is breached, then sure, it seems fairly safe that a hacker would not be able to discover my password and protects my account - but if they have the database, they can likely read all of that other information about me (I would guess in most systems these fields are stored in plaintext / datetime fields) and have the potential to commit other crimes (ie identity theft).

    Is there a way of protecting this PII further? (In most cases you want this data reversible so it can be displayed in account summaries in a web application for example, but reversible is not much better than plaintext).

  19. Randy · 278 days ago

    How about users making random passwords maybe 50 characters long, upper case, lower case, numbers, symbols, etc.
    Put them on a spreadsheet and store it on a USB drive. Use the USB (copy and paste) when accessing your accounts and immediately remove the USB stick when you are done.
    Keep the USB stick in a safe when you are not using it along with a printed copy of the spreadsheet in case of data corruption in the flash drive.
    Small electronicly locked pistol safes are available that could be bolted on top of (or under) a workstation to keep the USB stick within easy reach. I've seen them on sale for under $80 US.

  20. André M Santos · 234 days ago

    Thanks for the article. I've read about safe storage of passwords, but never really understood about the 2 last attempts (salt & iterated hash). This did a great job not only to understand, but which algorithms to search for.

  21. Bhanu · 148 days ago

    what happens if a bad(rogue) administrator /DBA notes down the salt and count for any user

    • Paul Ducklin · 148 days ago

      With the salt+count+hash you can mount an offline dictionary attack. A rogue sysadmin could indeed abuse the data for that purpose.


      1. The count makes each dictionary attempt take longer.

      2. The salt makes each hash different, even for the same password.

  22. Steve · 108 days ago

    Can anyone comment on their approach to storing the TYPE of algorithm used? Think about this, say our primary application is built entirely on a Java 1.6 framework and there's no option to upgrade immediately. With Java 1.6, we only have access to PBKDF2WithHmacSHA1. The plan for the next 3 months includes a move to Java 7 then in 9-12 months to Java 8.

    With Java 8, we're presented with even more secure hashing options including PBKDF2WithHmacSHA512 and for whatever reason we've decided to move to this new option. We now have a need to somehow know the TYPE of algorithm(s) used for each user login.

    Today there are users with salted, hashed passwords constructed using PBKDF2WithHmacSHA1 -- today they log in, we do the match using that algorithm type, access is permitted if matched. Consider what happens to that same that's gone dormant for a while, but shows back up after 9 months where we're on Java 8 and have moved to this new algorithm.

    There's a few options obviously, but is there an approach that would be recommended, perhaps new logic that enables today's login match but also, once matched successfully, uses the cleartext to construct a new PBKDF2WithHmacSHA512-based password that's then stored along with it's updated algorithm TYPE. I'm not sure how I feel about that.


    • Paul Ducklin · 108 days ago

      Linux supports a number of different password salt-and-hash schemes. The hash that was used is stored along with the hash itsaelf, denoted by a special substring at the start of the password hash field, e.g. $1$ means MD5, $6$ means SHA-512. You could do something similar.

      Or, in your case, because the only choices are SHA-1 and SHA-512, you could differentiate between the two sorts simply from the length of the hash.

      Any, yes, you could run both mechanisms in parallel for a while, and transparently update users' hash types (and hash values) when they next login. That's a clean way to leave the past behind. The only potential SNAFU I can see with that, from an audit or change control point of view, is that you will probably need to give write access to the password file to a part of the system that didn't need it before.

      After a reasonable time, you can identify all the accounts that have old hashes, and invalidate them for inactivity...

  23. Steve · 108 days ago

    BTW, really enjoyed the detail in this article -- unparalleled explanation of a difficult subject! Thanks so much Paul...

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

About the author

Paul Ducklin is a passionate security proselytiser. (That's like an evangelist, but more so!) He lives and breathes computer security, and would be happy for you to do so, too. Paul won the inaugural AusCERT Director's Award for Individual Excellence in Computer Security in 2009. Follow him on Twitter: @duckblog