Risks and Challenges of Password Hashing

Miguel Ibarra Romero

In a past article, password hashing was discussed as a way to securely store user credentials in an application. Security is always a very controversial topic, much alike politics and religion, where many points of view exist and a ‘perfect solution’ for someone is not the same to others. In my opinion, breaking an application’s security measures is just a matter of time. With computer power and complexity increasing every day, today’s secure applications will not be so secure tomorrow.

For our readers who are not familiar with what a hash algorithm is, it’s nothing more than a one way function that maps data of variable length to data of fixed length. So if we analyze the above definition we need to understand the following requirements and characteristics of such algorithms:

  • One way function: the output cannot be reversed using an efficient algorithm.
  • Maps data of variable length to data of fixed length: meaning that the input message space can be “infinite”, but the output space is not. This has the implication that 2 or more input messages can have the same hash. The smaller the output space, the greater the probability of a ‘collision’ between two input messages.

md5 has confirmed practical collisions and sha1’s probabilities for reaching a collision are growing every day (more info in collision probability can be found by analyzing the classic Birthday Problem), so if we need to apply a hashing algorithm, we should use the ones that have greater output space (and a negligible collision probability), such as sha256, sha512, whirlpool, etc…

They are also called Pseudo-random functions’, meaning that the output of a hashing function should be indistinguishable from a true random number generator (or TRNG).

Why simple hashing is insecure for storing passwords

The fact that the output of a hash function cannot be reverted back to the input using an efficient algorithm does not mean that it cannot be cracked. Databases containing hashes of common words and short strings are usually within our reach with a simple google search. Also, common strings can be easily and quickly brute-forced or cracked with a dictionary attack.

Demonstration

Here is a quick video on how a tool like sqlmap can crack passwords via sql injection by bruteforcing md5 hashes in a database.

Also, we could have just done the simplest of attacks… just grab the hash and google it… Chances are that the hash exists in an online database. Examples of hash databases are:

We also have to consider that since 2 or more identical passwords will indeed have the same hash value, cracking one hash will automatically give you the passwords of every single user that used the same. Just to be clear, say you have thousands of users, it is very likely that a fair amount of them will use (if passwords policies are not enforced) the infamous ‘123456’ password. The md5 hash value of that password is ‘e10adc3949ba59abbe56e057f20f883e’, so when you crack this hash (if you even have to) and search for all the users who have this value in their password field, you will know that every single one of them used the ‘123456’ password.

Why salted hashes are insecure for storing passwords

To mitigate this attack, salts became common but obviously are not enough for today’s computing power, especially if the salt string is short, which makes it brute-forceable.

The basic password/salt function is defined as:

f(password, salt) = hash(password + salt)

In order to mitigate a brute-force attack, a salt should be as long as 64 characters, however, in order to authenticate a user later on, the salt must be stored in plain text inside the database, so:

if (hash([provided password] + [stored salt]) == [stored hash]) then user is authenticated

Since every user will have a completely different salt, this also avoids the problem with simple hashes, where we could easily tell if 2 or more users are using the same password; now the hashes will be different. We can also no longer take the password hash directly and try to google it. Also, with a long salt, a brute-force attack is improbable. But, if an attacker gets access to this salt either by an sql injection attack or direct access to the database, a brute-force or dictionary attack becomes probable, especially if your users use common passwords (again, like ‘123456’):

Generate some string or get entry from dictionary
Concatenate with salt
Apply hash algorithm
If generated hash == hash in database then Bingo
else continue iterating

But even if one password gets cracked, that will not automatically give you the password for every user who might have used it, since no user should have the same stored hash.

The randomness issue

In order to generate a good salt, we should have a good random number generator. If php’s rand() function automatically popped up in your mind, forget it immediately.

There is an excellent article about randomness in random.org. Simply put, a computer can’t think of random data by itself. Computers are said to be deterministic machines, meaning that every single algorithm a computer is able to run, given the exact same input, will always produce the same output.

When a random number is requested to the computer, it typically gets inputs from several sources, like environment variables (date, time, # of bytes read/written, uptime…), then apply some calculations on them to produce random data. This is the reason why random data given by an algorithm is called pseudo random and thus it is important to differentiate from a true random data source. If we are somehow able to recreate the exact conditions present at the moment of the execution of a pseudo-random number generator (or PRNG), we will automatically have the original generated number.

Additionally, if a PRNG is not properly implemented, it is possible to discover patterns in the generated data. If patterns exist, we can predict the outcome… Take for instance the case of PHP’s rand() function on Windows as documented here. While it is not clear which PHP or Windows version is used, you can immediately tell there is something wrong by looking at the bitmap generated by using rand():

Compare to the output image from a TRNG:

Even though the issue has been addressed on PHP >= 5, rand() and even mt_rand() are still considered highly inadequate for security related purposes.

If you need to generate random data, please use openssl_random_pseudo_bytes() available as of PHP 5 >= 5.3.0, it even has the crypto_strong flag that will tell you if the bytes are secure enough.

Here is a quick code sample to generate random strings using openssl_random_pseudo_bytes()

<?php

function getRandomBytes ($byteLength)
{
    /*
     * Checks if openssl_random_pseudo_bytes is available 
     */
    if (function_exists('openssl_random_pseudo_bytes')) {
        $randomBytes = openssl_random_pseudo_bytes($byteLength, $cryptoStrong);
        if ($cryptoStrong)
            return $randomBytes;
    } 

    /*
     * if openssl_random_pseudo_bytes is not available or its result is not
     * strong, fallback to a less secure RNG
     */
    $hash = '';
    $randomBytes = '';

    /*
     * On linux/unix systems, /dev/urandom is an excellent entropy source, use
     * it to seed initial value of $hash
     */
    if (file_exists('/dev/urandom')) {
        $fp = fopen('/dev/urandom', 'rb');
        if ($fp) {
            if (function_exists('stream_set_read_buffer')) {
                stream_set_read_buffer($fp, 0);
            }
            $hash = fread($fp, $byteLength);
            fclose($fp);
        }
    }

    /*
     * Use the less secure mt_rand() function, but never rand()!
     */
    for ($i = 0; $i < $byteLength; $i ++) {
        $hash = hash('sha256', $hash . mt_rand());
        $char = mt_rand(0, 62);
        $randomBytes .= chr(hexdec($hash[$char] . $hash[$char + 1]));
    }
    return $randomBytes;
}

Password stretching can be effective if done right

To further mitigate brute-force attacks, we can implement the password stretching technique. This is just an iterative or recursive algorithm that calculates a hash value over and over in itself, usually tens of thousands of times (or more).

This algorithm should iterate enough in order to perform all calculations in at least 1 second (slower hashing also means the attacker will have to wait).

In order to crack a password secured by stretching, the attacker should:

  1. Know the exact iteration count, any deviation will produce entirely different hashes.
  2. Should wait at least 1 second between each attempt.

This makes an attack improbable… but not impossible. In order to overcome the 1 second delay, an attacker should have higher hardware specs than the computer for which the algorithm was tuned, something that might mean a high cost, so the attack becomes prohibitively expensive.

You can also use standard algorithms, like PBKDF2 which is a Password Based Key Derivation Function

<?php

/*
 * PHP PBKDF2 implementation The number of rounds can be increased to keep ahead
 * of improvements in CPU/GPU performance. You should use a different salt for
 * each password (it's safe to store it alongside your generated password This
 * function is slow; that's intentional! For more information see: -
 * http://en.wikipedia.org/wiki/PBKDF2 - http://www.ietf.org/rfc/rfc2898.txt
 */
function pbkdf2 ($password, $salt, $rounds = 15000, $keyLength = 32, 
        $hashAlgorithm = 'sha256', $start = 0)
{
    // Key blocks to compute
    $keyBlocks = $start + $keyLength;

    // Derived key
    $derivedKey = '';

    // Create key
    for ($block = 1; $block <= $keyBlocks; $block ++) {
        // Initial hash for this block
        $iteratedBlock = $hash = hash_hmac($hashAlgorithm, 
                $salt . pack('N', $block), $password, true);

        // Perform block iterations
        for ($i = 1; $i < $rounds; $i ++) {
            // XOR each iteration
            $iteratedBlock ^= ($hash = hash_hmac($hashAlgorithm, $hash, 
                    $password, true));
        }

        // Append iterated block
        $derivedKey .= $iteratedBlock;
    }

    // Return derived key of correct length
    return base64_encode(substr($derivedKey, $start, $keyLength));
}

There are also time and memory intensive algorithms like bcrypt (via the crypt() function) and scrypt

<?php
//bcrypt is implemented in php's crypt() function
$hash = crypt($pasword, '$2a$' . $cost . '$' . $salt);

Where $cost is the work factor, and $salt is a random string you can generate using the secure_rand() function above.

The workload factor is totally dependent on the target system. You can start with a factor of ‘09’ and increase it until the operation completes in approx. 1 second.

As of PHP 5 >= 5.5.0 you can use the new password_hash() function, which uses bcrypt as the default method for hashing.

There is no scrypt support in PHP yet, but you can check out Domblack’s scrypt implementation.

What about applying encryption techniques?

Hashing and ciphering (or encrypting) are terms which are often confused. As I mentioned before, hashing is a pseudo-random function, while cyphering is generally a ‘pseudo-random permutation’. This means the input message is sliced and changed in such a way that the output is indistinguishable from a TRNG, however the output CAN be transformed back again into the original input. This transformation is done using an encryption key, without which it should be impossible to transform the output into the original message again.

Ciphering has another big difference compared to hashing. While the output message space of hashing is finite, ciphering output message space is infinite, as the relationship between the input and output is 1:1, thus collisions should not exist.

One has to be very careful on how to correctly apply encryption techniques, thinking that just by applying an encryption algorithm to sensitive data is enough to keep it safe is considered wrong, as many problems exist that could lead to data leaks. As a general rule, you should never consider applying your own encryption implementation

Recently, Adobe had a massive data leak of their users database, since they incorrectly applied encryption techniques and I’ll take them as an example of what not to do. I’ll try to be as straight forward as possible, keeping things really simple.

Consider the following schema:

Let’s say the plain text contents of the table are as follows:

Now, someone at Adobe decided to cipher the passwords, but made two big mistakes:

  1. Used the same cipher key to encrypt the passwords
  2. Decided to leave the password hint field in plain text

Let’s say for example, that after applying an enciphering algorithm to the password field, now our data looks like the following:

While the passwords are not able to be simply decrypted, and we cannot know the encryption key used in a simple way, by examining the data we can notice that records 2 and 7 share the same password, as well 3 and 6… This is where the password hint field comes into play.

Record 6 hint is “I’m one!” which does not give us much information, however record 3’s hint does… we can safely guess that the password is “queen”. Records 2 and 7 hints do not give a lot of information alone, but if we look at them together, how many holidays have the same name as a scary movie? Now we have access to everyone’s account that used “halloween” as a password.

To mitigate the risk of data leaks, it is better to switch to hashing techniques, however if you must use encryption techniques to store passwords, we can use tweakable encryption. The term looks fancy, but is very simple.

Let’s say we have thousands of users, and we want to encrypt all passwords. As we saw, we cannot use the same encryption key for every password since the data will be at risks (and other sophisticated attacks become possible). However, we cannot use a unique key for every user, since storing those keys will become a security risk by itself. What we have to do is to generate a single key and use a ‘tweak’ that will be unique to every user, and both the key and the tweak together will be the encryption key for each record. The simplest of tweaks available is the primary key, which by definition is unique to every record in the table (although I do not recommend to use it, this is just for demonstrating the concept):

f(key, primaryKey) = key + primaryKey

Above I’m simply concatenating both the encryption key and the primary key’s value to generate the final encryption key, however you can (and should) apply a hashing algorithm or a key derivation function to them. Also, instead of using the primary key as the tweak, you might want to generate a nonce (similar to a salt) for each record to be used as the tweak.

After applying tweakable encryption to the users table, it now looks like the following:

Of course we still have the password hint problem, but now each record has a unique value, so it is not apparent which users are using the same password.

I want to emphasize that encryption is not the best solution, and should be avoided if possible to store passwords since a lot of weaknesses can be injected… You can and should stick to proven solutions (like bcrypt) to store passwords, but keep in mind that even proven solutions have their weaknesses.

Conclusion

There is no perfect solution and the risk of someone breaking our security measures grows every day. However, cryptographic and data security studies and research continue, with the relative recent definition of sponge functions, our toolkit keeps growing everyday.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Braders

    How secure are the php hashing functions in relation to all this? Do they use password stretching or tweaks or any of the other techniques mentioned?

    • timoh6

      If you properly use the tools PHP offers, it will be OK.

      Primarily you should use password_hash() / password_verify() combo (as it makes this easier for you).

      With those functions, all you need to do by yourself is to find the suitable cost parameter (which should be so that it takes ≤ 100 ms to process a password on your server).

  • http://matisseverduyn.com/ Matisse VerDuyn

    Wow, great article! What do you think about implementing, as well, a one-time pad? It is, technically, perfect encryption.

    • Miguel Ibarra

      Although one-time pad is in fact, perfect encryption, in order to do it right, the cipher key has to be exactly the same size as the to-be-ciphered message, so you’d have to store all of the keys needed to decipher the messages back somewhere…

      • http://matisseverduyn.com/ Matisse VerDuyn

        Right. but when we’re talking about an SHA-512 hash, the output is only 128 chars… which is negligible storage wise.

        • http://www.bitfalls.com/ Bruno Skvorc

          Sound advice, cheers

  • Jamie Devine

    Nice article! I’ll be referring back to this next time I need to deal with passwords.

  • Charles Bryant

    It is a question I test potential new candidates with, I think the best answer you could give me would be to say using the php password hash function with a secure salt, and a captcha for multiple failed password attempts.

    It is a good tip to include the id field as part of the hash.

  • Taylor Ren

    Very in-depth discussion on a very serious topic.

    Nowadays, many sites supports SNS ID login. In general, we can say those big SNS sites should have stronger password protections than what we can implement in our own sites. But that still remains a challenge.

  • Sanxion

    Why should you implement your own password hash function? I’ve learned that you should never try to implement this on your own because it’s like reinventing the wheel and a semi PHP programmer just can’t implement it good enough. Just use PHPASS which have already been integrated to various CMS, such as WordPress, phpBB, Drupal.

    • Miguel Ibarra

      I totally agree on using existing, proven mechanisms instead of re-inventing your own, which is a big no-no… However I find valuable to explain the basics of how stuff works in the inside, rather to just recommend to use or implement a certain library or function. Sorry if the article did not reflect this, and appreciate the feedback :)

  • Pierre Joye

    As of 5.5.0+, you can also use hash_pdkf2 or openssl_pdkf2.

  • Tech Sec Com

    Sorry, but I think you are getting several things wrong here.

    1. Hash functions are not PRFs. Analysis of PRFs in cryptography usually involves keyed functions. Hash functions don’t have keys.

    2. Indistinguishability from random is too strong and not a requirement for hash functions. Preimage resistance and collision resistance are.

    3. Not all encryption schemes are based on PRPs.

    4. A golden rule which is taught in every crypto course and repeated often is: Don’t try to develop your own crypto. Don’t even try to implement existing algorithms yourself unless you really really know what you are doing (only a few experts know). Even if your implementation is “correct” you are likely to introduce implementation related vulnerabilities. Besides using the same key and storing the hint in plaintext, Adobe used ECB mode to encrypt the passwords, leaking information about them in the corresponding ciphertexts.

    5. Decent password hashing schemes are designed to be slow. BCRYPT uses a block cipher with the key setup part redesigned to be very expensive. This is done specifically to address attacks with increasing computing power. Moreover, it can be made even slower over time, which should address the concern of increasingly powerful attacks. On the other hand, usually, encryption schemes are designed with speed in mind.

    Reversible encryption is not a good idea for storing passwords. It adds complexity to the user login process, since now it has to handle key management, which in turn could produce more vulnerabilities. In case of an attack, the attackers can potentially also get the key, which would make the encryption useless. That is not a possibility if the passwords are only hashed/salted, assuming that a good enough scheme like BCRYPT is used.

    • http://www.bitfalls.com/ Bruno Skvorc

      Thanks for the feedback!

    • Miguel Ibarra

      I do agree on your statement, the golden rule is not try to develop your own crypto. The article was not targeted to to security gurus, explanation of Adobe’s flaws was written in a way so that anyone with basic knowledge on computers and programming could understand how information could be easily gathered from an improperly implemented security scheme.

      I do not agree and hashing functions not being part of the PRF family, since a PRF by definition is “an efficient deterministic function that maps two distinct sets. … in practice a PRF has only one input d (domain) and a hidden random seed (range) which when run multiple times with the same input, always outputs the same value. Nonetheless, given an arbitrary input the output looks random due to the random seed” Hashing functions and keyed hashing functions can have different purposes, for example a keyed hash function is often used to add an integrity signature to a given message.

      Also I do agree that hashing/salting is a better approach than ciphering, however there are external circumstances that force you as a software developer to go in a certain direction, even if you know it is not the best option and you have done everything to demonstrate better approaches… All you could do under those circumstances is to mitigate the risks.

  • timoh6

    About mentioned “1 second hashing time”, this is in general too much for interactive logins. While it offers greater protection for the passwords, it also at the same time increases the risk of DOS attack _alot_.

    General recommendation (for interactive logins) is to tune the work factor so that the password hashing takes ≤ 100 ms.

    Suitable algorithm (like bcrypt via password_hash() or crypt()) with proper work factor combined with good password policy enforcement is what makes the password hashes “properly handled”.

    After the hashing process, you could encrypt the hashes with, say, AES, but as already said, it may not be easy to tell when this extra complexity pays off. At least I’m not comfortable recommending it predominantly (and in general).

    Also, I think “tweakable encryption” is a bit misleading in this context.

    But my rants aside, it is great to see these things are being brought up for the PHP community by posts like this!

    • Miguel Ibarra

      We have to find balance between computation time spent at interactive logins. It is true that a long time can negatively impact user experience and might me attack vectors (DDOS attacks)… However a short time gives the potential attacker a greater probability to crack the password in a reasonable amount of time. There are several mechanism to avoid DDOS attacks that can be implemented along slow hashing algorithms.

      Thanks for your feedback

  • Guest

    1) No, a hash is not something for reducing an existing text to a fixed size. Hashes are not all fixed size output, and substr($foo, 10) is not a hash. This is like saying “the purpose of a car is to be a large metal box that fills a parking space.” Not only does that so completely miss the point that it worries me what the author believes, but it’s also not universally true, though commonly so.

    2) Not all hashes are in fact one way functions.

    3) The birthday problem has nothing whatsoever to do with collision attacks against hashes. At all. The birthday problem is about the likelihood of finding matches in a randomly distributed set. We do not crack hashes by finding matches in a randomly distributed set. The way collision generation works is to reduce the space that a residue might live in. Observing the statistical commonality of collisions in a perfectly even space has nothing to do with that. This is like saying “the reason it’s getting easier to hunt buffalo is because of this equation that shows you that if you fire an arrow into the wilderness, this is your chance of hitting one.” No, it isn’t, and either the author is name-dropping to invent credibility (worrisome,) or genuinely believes this (terrifying.)

    4) SHA was considered unusable in the early 1990s, and NIST said that new federal projects weren’t allowed to use it in 1993.

    5) The first two things the author says to use instead – SHA256 and SHA512 – *are* *also* *decades* *out* *of* *acceptable*. This is someone reading usenet posts from the early 1990s and repeating the advice wholesale, without understanding it. For most programming tutorials, that’s fine; that’s what Sitepoint does for a living, is to regurgitate other peoples’ content at a low quality. For crypto and security, however, which are adversarial moving targets, this is immensely dangerous and incorrect.

    6) Whirlpool was never an accepted standard. There are newer, stronger standards since. Whirlpool has not been sufficiently audited, and was rejected from the SHA2 competition for a reason. I cannot imagine any reason for this piece of advice to exist. Next recommend GOST. Oy.

    7) No, hashes are *not* called “pseudo-random” functions. No, hashes *do* *not* have any relationship to true random number generators. This is like explaining how cars are also sometimes called boats or yachts. It’s amazingly obviously wrong.

    8.) No, a hash should *not* be indistinguishable from a true random number generator. Schneier devotes 20 pages to this. A true random number generator should exhibit transitory patterns, because it’s random, and patterns show up randomly. If a hash is giving up patterns, that’s because it’s exposing what’s underneath. A hash should imitate well distributed sample from black body thermal noise with a 1/f^beta coefficient. It should have a flat frequency spectrum when run through FFT. A good hash goes to great effort to make sure that the input space maps evenly to the output space, to prevent bunching attacks like Coppersmith’s attack.

    9) The idea that databases are within reach for passwords on Google is garbage. You see that for unsalted SHA1 and unsalted MD5, but you don’t see that for legitimate keying algorithms. Why is that? Oh right, because their residues are large, so it would take exabytes or yottobytes of storage. Which is why this kind of attack only ever works if you asked the wrong person, and got an answer like “the smallest sha2 variants or whirlpool.” He also seems to have missed that his own next recommendation shows why this is nonsense. If someone has your salted hash residues, they also have your salt. They’re stored in the same place. Therefore they just make the rainbow table for your salt. Takes about 5 minutes on a modern cheap Walmart computer. The thing he’s saying salts are there to fix are what per-user salts are actually there to fix. He doesn’t seem to know what system salts are there to fix at all (they’re for immediately and permanently pulling the plug on the dataset,) and this criticism shows that he doesn’t have even a basic understanding of what he’s discussing.

    10) “In order to mitigate a brute-force attack, a salt should be as long as 64 characters” Looolololololl. The whole point of salting is to make brute force attacks impossible. Or did you think someone was going to make brute force password table reversal databases? By the time you’ve covered the first four bytes of a salt, you’re already looking at more storage than exists on planet Earth, and more CPU time than has ever been spent. This is utter tripe. Virtually any length of salt is acceptable. The length of the salt does not actually affect the work in any way. If the salt is different for each user, it doesn’t even matter if they’re sequential and stated publically. The issue is not to make them un-guessable (cargo cult security is worse than no security at all.) It’s to make the computational cost of rainbow tables physically impossible. Counting upwards from 0 is sufficient. Generally, the fake cryptographer immediately protests that then rainbow tables can just be built per-user, without noticing that under the strategy they suggested, that was already true.

    11) “Also, with a long salt, a brute-force attack is improbable.” Also, with a short salt. This is fundamentally wrong.

    12) “But, if an attacker gets access to this salt” Translation: this guy thinks there’s a situation where all the password residues would be compromised, but the salts that he’s keeping in the same database table would not be.

    13) Notice that he’s not putting up any actual defenses for when the password table is compromised, even though they’re common and well known. That’s because he doesn’t know what they are. For example, he should have mentioned honey-words. Password intrusions are detectable.

    14) “Computers are said to be deterministic machines, meaning that every single algorithm a computer is able to run, given the exact same input, will always produce the same output.” No cryptographer has ever said this. This shows a basic failure to understand side channel attacks. Exploiting this common false belief is the bread and butter of attackers.

    15) “If you need to generate random data, please use openssl_random_pseudo_bytes()” Yes, please use the thing that was just detected to be wrong a week and a half ago in a gruesome and serious way that had been reported six years earlier, and has invalidated all Linux security since 2009. Not, you know, the correct thing which is actually indicated for this – /dev/urandom .

    16) “as of PHP 5 >= 5.3.0, it even has the crypto_strong flag that will tell you if the bytes are secure enough.” Back here in reality land, what it actually does is ask the operating system if the random source (not the bytes it’s giving you, the source! it’s a critically important difference) are sufficiently secure. The reason this is important is that the three most common Linux distros always say yes to this question, no matter what.

    17) “Here is a quick code sample” Notice how his code sample actually contains the correct approach as approach #2, then uses a random number generator that is explicitly not crypto-secure as his approach #3. Seriously, that advice is “oh, you’re going to a car race? Try: a horse, a car, or eating a stick of lit dynamite.” He’s obviously cut and pasted these answers together from disparate sources, none of which he knows how to evaluate for quality. Which is exactly what you want when making crypto recommendations. Nevermind that all the actual crypto literature heavily stresses to never, ever do this. (Nevermind that he tells you not to use rand(), which goes back to /dev/random, which is the same source as /dev/urandom, which would actually be dramatically less bad on unix than mt_rand, and is equivalently bad on Windows. Because he has no idea how these things are implemented.)

    18) PBKDF2 is silly. You should not be adding stretching on top of a hash. You should be using a residue protocol with stretching built in, like scrypt or bcrypt. Hacking it in ten years after the base hash was created is dramatically inferior to creating the base hash with this in mind. PBKDF2 is a way to accomodate old hardware that cannot be updated to bring it up to modern standards, not a strategy for new design. Amusingly, this is so well known that his next point is “actually even php’s default choice is to not do this ever.” Apparently he didn’t realize that meant it was time to pull this advice out of the list as obsolete.

    19) “Recently, Adobe had a massive data leak of their users database, since they incorrectly applied encryption techniques and I’ll take them as an example of what not to do.” Amusingly, the actual mistake they made is one of your pieces of advice, sir.

    20) “Hashing and ciphering (or encrypting) are terms which are often confused. As I mentioned before, hashing is a pseudo-random function, while cyphering is a ‘pseudo-random permutation’.” Both of these are wrong. Hashing is not a pseudo-random function, and “ciphering” is what professionals call “encryption.” A cipher is an encryption algorithm. Check Schneier. Nobody has called anything “ciphering” since World War 2. It’s important to understand that if someone doesn’t even know the right words for the industry topic, they’re almost certainly self taught. You don’t want a self taught cryptographer who uses the wrong words for things and gives advice from 25 years ago.

    21) “This means the input message is sliced and changed in such a way that the output is indistinguishable from a TRNG” Still wrong.

    22) “Now, someone at Adobe decided to cipher the passwords, which is good” No, this is terrible. Passwords should never be run through a reversible encryption. This is a 101 mistake both on Adobe’s part and on the article author’s part.

    23) “two big mistakes: * Used the same cipher key to encrypt the passwords, * Decided to leave the password hint field in plain text” Notice how they actually made a ton of mistakes that are against the bloviated cut and paste text above, but the article author didn’t notice any of them (because he doesn’t actually understand any of it, and is repeating what he heard on the internet, which is how good crypto gets done.) The article author is very correct about the password hint, though.

    24) The actual mistakes, which most amateurs know, were: * encryption instead of hashing, * not table salted, * not per-user salted, * using a hilariously weak and out of date algorithm (triple des, which is stretched des,) * assuming stretching magically solves everything * providing user data to the attackers to ease targetted penetration * not invoking intrusion detection at the password level * not requiring password strengthening, which permits obscenely weak passwords

    25) “While the passwords are not able to be simply decrypted” he says, apparently unaware that that’s exactly what happened

    26) “To mitigate the risk of data leaks while using encryption techniques to store passwords, we have to use tweakable encryption.” he says, having been giving completely different and incompatible advice this entire time, apparently unaware that whether bcrypt and scrypt are tweakable have nothing to do with why they’re the right choice here. Amusingly, he goes on to discuss tweakable hashing, not tweakable encryption, apparently unaware that hashing is not a kind of encryption.

    27) “What we have to do is to generate a single key and use a ‘tweak’ that will be unique to every user, and both the key and the tweak together will be the encryption key for each record. The simplest of tweaks available is the primary key, which by definition is unique to every record in the table:” which is funny, because this is a salting strategy, and apparently he forgot that just earlier in the article he was saying they need to be 64 bytes and highly random.

    28) “Above I’m simply concatenating both the encryption key and the primary key’s value to generate the final encryption key, however you can (and should) apply a hashing algorithm or a key derivation function to them.” No, you shouldn’t.

    29) “Also, instead of using the primary key as the tweak, you might want to generate a nonce (similar to a salt) for each record to be used as the tweak.” So much self-contradictory advice, using words incorrectly :|

    30) “What might be a better solution? Perhaps using password stretching in the password field” he says, having just recommended tweakable (sic) encryption, which … is stretching. Doesn’t know what he’s recommending well enough to realize he’s repeating himself as an alternative to the last time he said it. “What might be a better solution than Foo? Well, *maybe* foo.” Yeah, or maybe the things that are actually for this, which you don’t appear to know about at all.

    So, there are 30 severe mistakes the author made, right off of the top of my head.

    • Roman

      Guest, what’s the simplest, yet secure enough, method to deal with passwords in PHP? Say, PHP 5.3+

      • http://www.bitfalls.com/ Bruno Skvorc
      • StoneCypher

        That’s like asking for the simplest way to travel from point to point. It depends on the job.

        Pre-transit stretching and hashing under scrypt, exchanging the residue with SRP, then storing at server side with a different round of stretching and hashing, with client and serverside per-user salts *and* a system-wide salt for fast cut, plus entropy-regulated honey passwords, is one decent design. To do a better job than that, you’d have to give me context.

        Or you could just google something and get IRC Maxell’s bad answer (because he’s *also* not a cryptographer.)

        For the record, I’m the guest from before, but the account this was under magically disappeared the second I told Bruno on Facebook that this article was unacceptably low quality and was going to get people hurt.

        None of the errors have been fixed since, though he claimed that he had the author go through and do a repair edit.

        I would recommend you take advice from Bruce Schneier, since SitePoint doesn’t seem to care if they’re pushing bad information in the security arena.

        • Roman

          Thanks. The solution you described seems too complex to me because I don’t even know the terms you used :) The context… so far I’ve been dealing with just websites that do NOT deal with very sensitive confidential info but need a login mechanism.

          • StoneCypher

            Respectfully, if you are responsible for other peoples’ safety, it’s probably a good idea to learn these terms. What I described is the inclusion of a handful of well defined libraries and about 30 lines of code.

            It’s worth your time, and it’s worth their safety.

        • http://timoh6.github.io/ Timo

          > Pre-transit stretching and hashing under scrypt, exchanging the residue with SRP, then storing at server side with a different round of stretching and hashing, with client and serverside per-user salts *and* a system-wide salt

          This “protocol” you brought up has quite a few downsides to be recommended in general, I think.

          When dealing with web browsers authenticating to web server, you had to use JavaScript, and thus implement scrypt in JavaScript which is of course inefficient.

          However, while this may not be a problem per se, the bigger problem with this is the need to support multiple types of clients (which is probably a very generic need), from old desktop computers to different sort of mobile devices etc. It is a bad thing when someone is logging in with their mobile phone and they are stuck waiting three minutes for the login to happen.

          The problem with SRP is that you need to have a secure connection (HTTPS) before there is a point to use it. And if you already have a secure connection, there is no need for SRP.

          Using system-wide salts could maybe save the passwords in some cases, but it is questionable whether there is a point to use them if you do not have a special “key store” or HSM etc.

          In case the password hashes leaks, you really can’t say comfortably “Hey, we lost the hashes, but no worries, they are encrypted with a super secret key which was definetely not compromised because it was kept in a secret PHP file on the server”.

          With that said, it would be a lot easier and less error-prone to use HTTPS protocol with decent password hashing algorithm and settings and enforce a password policy. If this is not enough, a separate key store intended for password hashing would be a good next step.

          As Bruce Schneier put it: “Complexity the Worst Enemy of Security”.

          • StoneCypher

            Uh.

            “This “protocol” you brought up has quite a few downsides to be recommended in general, I think.”

            All but one of your criticisms I reject out of hand. Requiring JavaScript to be available in the browser is a valid potential complaint. It is also a price I am willing to pay, but you’re right, it’s a significant consideration, and I should have raised it.

            .

            1) “As Bruce Schneier put it: “Complexity the Worst Enemy of Security”.” This is Bruce Schneier’s system, not mine, so to invoke him to describe this as too complex is a little … weird. It’s also pretty weird that you see this system as complex. Pre-transit hashing, post-storage hashing, plug pull, honeypot. This is standard issue basic stuff. Anyone worth their salt (ha) already does it this way. FIPS 140-2 required this for the bare minimum certification for all new projects almost 15 years ago.

            2) No, HTTPS does not mean that you have a secure connection, and does not obviate SRP.

            3) No, you do not need HTTPS to invoke SRP. In fact, HTTPS, in modern secure implementations, is generally built on top of TLS, which as of 1.3 uses SRP internally for its key exchange. A protocol cannot be reliant on a connection layer when the connection layer is built out of that protocol.

            4) I am willing to require Javascript for legitimate security. I accept that this is a legitimate downside, and that was smart to be pointed out.

            5) “logging in with their mobile phone and they are stuck waiting three minutes ” There’s no particular reason that scrypt in Javascript should be hard on a phone. SCrypt is scalable. You choose its workload. If the workload in your imagination is too high, choose a smaller one. Phones are relatively fast these days, iphones implement asm.js, chrome implements equivalent in-engine optimizations, and if you choose sufficiently small constants you can make the password process around a second. That stretching is still enough to be a real problem at NSA budgets. This is a hypothetical and entirely incorrect guessed problem. One second is well within the existing negotiation time for essentially every current modern cellular web login process. Logging into gmail from my phone doesn’t even begin the negotiation that quickly. That has to be done one time per session. I do not agree that the work time is a legitimate problem. There would be no being stuck waiting three minutes. You’re making that up. Next tell us how any workload that’s tenable in one second on the iphone 4 isn’t enough to thwart the NSA, except that actually it totally is, and besides, the NSA isn’t who we’re fighting.

            6) “Using system-wide salts could maybe save the passwords in some cases” You have guessed, incorrectly, at the purpose of a system-wide salt, and then criticized your own guess as specious. The actual purpose of a system-wide password salt is to have the ability to permanently, atomically, instantaneously kill all passwords simultaneously, by destroying the salt. It is not questionable whether there is a point; it’s crypto 101. Please read the Schneier book you’re feigning familiarity with.

            7) “In case the password hashes leaks, you really can’t say comfortably
            “Hey, we lost the hashes, but no worries, they are encrypted with a
            super secret key which was definetely not compromised” Yeah, that was never the point. Criticizing your own guesses in other peoples’ names is tacky. The actual point is so that when you learn the hashes leaked, you can immediately and universally destroy all of them with zero omissions in a single instantaneous atomic action.

            8) “With that said, it would be a lot easier and less error-prone to use
            HTTPS protocol with decent password hashing algorithm and settings and
            enforce a password policy.” It would be even easier and less error prone to send and store everything plaintext and use no https at all, and not even get an SSL cert. What’s your point? (Do you believe the security characteristics of a robust system should be chosen on grounds of what one finds easy?)

            9) “If this is not enough” It isn’t.

            10) “a separate key store intended for password hashing would be a good next step.” What? Seperate from what? Did you think storing the hashes on a different place on disk would make a practical difference?

          • http://timoh6.github.io/ Timo

            > 1) “As Bruce Schneier put it: “Complexity the Worst Enemy of Security”.” This is Bruce Schneier’s system, not mine, so to invoke him to describe this as too complex is a little … weird. It’s also pretty weird that you see this system as complex. Pre-transit hashing, post-storage hashing, plug pull, honeypot.

            Yes, this requires more code and thus leaves greater area for bugs. But anyway, the context here is an important factor. I doubt Schneier is recommending this to be used on web browser-web server scenario. Citation?

            > 3) No, you do not need HTTPS to invoke SRP…

            The reason you need HTTPS here is the fact that you can’t bootstrap your custom JS SRP code securely without it. It is not reliable to assume every client logging in has downloaded your SRP browser extension (or is using your custom build web browser which already has SRP code in it). So yes, it does not make much sense to try to secure the connection between web browser and web server if the login page itself is transmitted to the browser via insecure channel (you can’t assume that the adversary could only read the traffic, but _not_ modify it, do you?). That is why you need HTTPS and thus no need for SRP.

            > There’s no particular reason that scrypt in Javascript should be hard on a phone. SCrypt is scalable. You choose its workload. If the workload in your imagination is too high, choose a smaller one.

            Right, I agree that one could benefit from this. But, I disagree that this is a reasonable recommendation in general. The actual concerns with the pre-hashing approach are worse interoperability and extra complexity. As you said, you need JS or some other code to be running on the client and furthermore, how do you choose the cost settings? Are those set so low that it will not be a problem for low-end machines? How reasonable it is after that?

            > Criticizing your own guesses in other peoples’ names is tacky. The actual point is so that when you learn the hashes leaked, you can immediately and universally destroy all of them with zero omissions in a single instantaneous atomic action.

            Sorry about that, I really didn’t see you were referring about “system-wide salt” for such usage. A honest question – what is the thread model you are defending against with this? This doesn’t seem to make much sense if your data is already leaked. Wouldn’t it be easier to just reset the hashes on the database?

            > It would be even easier and less error prone to send and store everything plaintext and use no https at all, and not even get an SSL cert.

            We know this is a moot point.

            > What? Seperate from what? Did you think storing the hashes on a different place on disk would make a practical difference?

            No. Separate from you app server. Like another server or a hardware device with no access from the app server’s software to the “secret / local parameter” (or “system-wide salt” as you mentioned). If you app server does the actual hashing, your “separate device”, for example, encrypts the hashes with a key which is only known to the separate device.

          • StoneCypher

            I love how you conflate requirements of a protocol with requirements of loading code, how you believe that requirements for loading code mean that the code loaded is no longer useful, and how you don’t even realize that one of your recommendations is the same as one of the things you’re trying to shoot down (go look honeywords up.)

            What you need to deliver assets to the client has essentially nothing to do with whether there is a security gain in never transmitting whole credentials in the other direction. HTTPS is not magically secure, and having it does not mean that the contents haven’t been recorded and aren’t crackable. Furthermore, if there’s a complete failure of HTTPS, something that has happened with prior believed strong transit tunnels, what’s transmitted by SRP remains secure. You appear not to understand the actual purpose of SRP.

            As far as being asked to explain the system wide salt again, I already have more than once; if you didn’t understand it last time, you aren’t going to understand it this time. But, since you asked, “if you discover a single leaked credential, you can immediately and irrevocably destroy all active credentials atomically.” I’m not sure how to make that any simpler. “I discovered that a hash is leaked. That means none of these are trustable. Let’s hit the kill switch.” The system salt is that kill switch.

            You ask for the Schneier citation,but I’ve already given it. Just put in some more careful reading effort.

            .

            “The actual concerns with the pre-hashing approach are worse interoperability and extra complexity.”

            Yeah, be sure to phrase “it requires javascript” as many different ways as possible, to make it look like it’s more than one problem. (And honestly, if you keep beating the “it’s extra complexity” drum on a stable old library and a single function call, I mean, if you’re the kind of person who won’t make one function call to keep your data safe because complexity, then I don’t know what to tell you.)

            There’s this sort of thing that people do where they can’t admit that they’re speaking to personal expectation, so they dig in hard on specious things. Like, when someone wants to criticize PHP, and you ask them what the problem is, and the worst they can come up with is that because the string library mimics the c library’s order, it’s “inconsistent.” And you’re sitting there like “the biggest language criticism you can come up with is having to remember a half dozen signature orderings?”

            Yes, yes, complexity. Very good. Sounds important. Must be a lot of work.

            .

            “and furthermore, how do you choose the cost settings?”

            (sigh) Seriously, do you just ask questions without even trying to think of answers?

            1) Pick an amount of time. You already chose one second.

            2) Make the function call in a page.

            3) Choose a reference platform. I recommend the iPhone 4, because it’s the slowest phone in major circulation.

            3) Pick some cost settings. Try it on the phone. If over your threshhold, decrease. If under your threshhold, increase.

            Like what point were you trying to make that you couldn’t figure out how to choose a timeframe you felt acceptable, and then adjust parameters until satisfied?

            .

            “Are those set so low that it will not be a problem for low-end machines? How reasonable it is after that?”

            I actually already addressed this in the comment you didn’t read very well.

            Your skepticism based on lack of knowledge and lack of willingness to try it does not actually undermine Bruce Schneier’s advice.

            You seem to put great value in your own lack of knowledge as evidence.

            .

            “Sorry about that, I really didn’t see you were referring about “system-wide salt” for such usage.”

            That’s because it’s a completely normal standard tactic, and you don’t know standard tactics, and so I didn’t think I’d need to explain this, and you didn’t think you’d need to know what it was for before calling it useless.

            You make the same mistake after this apology in the very same post.

            You seem to put great value in your own lack of knowledge as evidence.

            .

            “A honest question – what is the thread model you are defending against with this?”

            I’ve already repeatedly explained this.

            .

            “This doesn’t seem to make much sense if your data is already leaked.”

            It /only/ /ever/ makes sense if the data is leaked. The specific purpose of this is for when the data was leaked.

            I actually already addressed this in the comment you didn’t read very well.

            You seem to put great value in your own lack of knowledge as evidence.

            .

            “Wouldn’t it be easier to just reset the hashes on the database?”

            (Facepalm)

            Just think for one second what the effect would be of changing the salt.

            THAT’S WHAT THIS DOES. EXCEPT IN A SINGLE VALUE ATOMICALLY INSTANTLY. WHICH I ALREADY TOLD YOU TWICE.

            What you just said is “wouldn’t it be easier to have SQL do over the entire user column at whatever length that takes and with the possibility of omission or rollback from query logs or backups what you could do instantaneously and permanently by changing a single number?”

            No. No, it absolutely would not. And you should stop criticizing things until after you have taken the time to understand them. Hubris is not a good look.

            I actually already addressed this in the comment you didn’t read very well.

            You seem to put great value in your own lack of knowledge as evidence.

            .

            Your quote: “it would be a lot easier and less error-prone to use HTTPS protocol with
            decent password hashing algorithm and settings and enforce a password
            policy”

            My reply: “It would be even easier and less error prone to send and store
            everything plaintext and use no https at all, and not even get an SSL
            cert.”

            Your response: “We know this is a moot point.”

            (sigh)

            If you would stop assuming whoever disagreed with you was an idiot, and take the time to understand what they were saying; etc. If you don’t get it, don’t tell someone it’s a moot point; ask them what you’re missing again.

            What I’m doing is called “reductio ad absurdum.” It’s not a moot point at all. I’m showing that the value of choosing security strategies based on their ease is low.

            It seems unfortunate that you are unwilling to visit the possibility that you’ve just missed someone else’s point before telling them what they said is moot.

            .

            “No. Separate from you app server. Like another server or a hardware
            device with no access from the app server’s software to the “secret /
            local parameter” (or “system-wide salt” as you mentioned). If you app
            server does the actual hashing, your “separate device”, for example,
            encrypts the hashes with a key which is only known to the separate
            device.”

            Oh look, you accidentally did a bad job of reinventing step 4 in the thing you called too complex!

            Because clearly adding one line of code is too complex, but making the password system from machine 1 rely on machine 2 is pretty straightforward. :D

            I think I’m about done here.

          • http://timoh6.github.io/ Timo

            About SRP, check out this answer by Thomas Pornin: http://security.stackexchange.com/questions/49689/how-do-clients-enroll-using-srp/49702#49702 and this Matasano blog post: http://www.matasano.com/articles/javascript-cryptography/ These should clear the point what I’m trying to make.

            About client-side hashing, I’m just making a point that it has drawbacks like choosing the reference platform. But yes, of course this could work, but I don’t think it is a good for a general recommendation. I’m wondering why you didn’t mention anything about password policy enforcement, which works universally on all clients.

            About the system salt as a kill switch, yes I see your point, but I’m just not convinced that it is something to recommend in general. You say it out loud, but is such an outcome really needed? When the hashes are leaked (including the “kill switch salt”), does it matter if you change the kill switch salt and atomically invalidate all the hashes, or you just reset the hashes on the database. I see it is a bigger operation to reset the hashes on the database if the user database is huge (and backup rollbacks etc.), but anyway I’m just not sure is the “atomic gain” of kill switch salt worth it in a general recommendation.

            If you meant that an adversary could log in as an another user because the database was accidentally restored from a backup (and she cracked the old password hash) doesn’t seem too high risk scenario. Maybe it is worth it. But it also has drawbacks (like merging user databases).

            > Oh look, you accidentally did a bad job of reinventing step 4 in the thing you called too complex!

            You lost me, could you elaborate?

            Besides those links I pasted at the start of this comments, I recommend you to read an article by Solar Designer about how to manage (PHP application’s) users and passwords: http://www.openwall.com/articles/PHP-Users-Passwords

            P.S. These three links I pasted, contains only material from security/crypto professionals.

          • StoneCypher

            “These should clear the point what I’m trying to make.”

            Nope. They do make it clear that you don’t understand why I disagree with you, but no, other peoples’ words that weren’t written to address what was said to you don’t actually defend you.

            .

            “but I’m just not convinced that it is something to recommend in general”

            Enjoy arguing with standard practice.

            .

            “You say it out loud, but is such an outcome really needed?”

            The US Federal Government believes so.

            .

            “anyway I’m just not sure is the “atomic gain” of kill switch salt worth it in a general recommendation.”

            That’s nice. I was answering someone else. I’m not really worried about whether you agree with me, especially after the long string of mistakes you’ve made and declined to admit.

            .

            “If you meant that an adversary could log in as an another user because the database was accidentally restored”

            Nope. Please stop attempting to speak for me.

            .

            “You lost me, could you elaborate?”

            No, I’ve already explained it several times, and you’ve missed it every time, then gotten on a post about how your opinion should override standard practice, federal requirements, and the recommendations of the person you used to pretend you were citing, but gave up on as soon as the namedrop didn’t work out.

            .

            “I recommend you to read an article by Solar Designer about how to manage (PHP application’s) users and password”

            Lol no thanks

            .

            “P.S. These three links I pasted, contains only material from security/crypto professionals.”

            Yes, the material you don’t understand which is not about what was said to you was written by professionals.

            Luckily, I’m not arguing with them in any way.

          • http://timoh6.github.io/ Timo

            > Nope. They do make it clear that you don’t understand why I disagree with you, but no, other peoples’ words that weren’t written to address what was said to you don’t actually defend you.

            According to your previous comment, you do not seem to understand the problem with web browsers and JS SRP. You wrote:

            > 3) No, you do not need HTTPS to invoke SRP. In fact, HTTPS, in modern secure implementations, is generally built on top of TLS, which as of 1.3 uses SRP internally for its key exchange. A protocol cannot be reliant on a connection layer when the connection layer is built out of that protocol.

            This is wrong, and I tried to point out why (by providing those links). Remember, we are in “web browser web server” context.

            > The US Federal Government believes so.

            The “site-wide salt” sounds like local parameterization. The usage for it you described could be one of the reasons to justify the use of local parameterization (or peppering as it is often called), but I don’t think it is a typical reason (and thus to be recommended in general). For more information, see slides at http://www.openwall.com/presentations/Passwords12-The-Future-Of-Hashing/

            About FIPS 140-2, you wrote:

            > FIPS 140-2 required this for the bare minimum certification for all new projects almost 15 years ago.

            I don’t recall FIPS making a statement about pre-hashing on web browsers. Are you sure about it? Source?

            > This is Bruce Schneier’s system

            Source (pages on books or whatever the source is)? I doubt he meant the “system” to be used as you think.

            > No, I’ve already explained it several times, and you’ve missed it every time, then gotten on a post about how your opinion should override standard practice, federal requirements, and the recommendations of the person you used to pretend you were citing, but gave up on as soon as the namedrop didn’t work out.

            This is not “my opinion”, I didn’t invent these things. This is what is a common practice in security scene. I really wonder how you see the standard practice so much different. But well, as long as you just “Lol” to material written by security expert(s)…

            > Yes, the material you don’t understand which is not about what was said to you was written by professionals. Luckily, I’m not arguing with them in any way.

            I once more emphasize that we are dealing with web browser environment. You don’t see a problem here?

          • StoneCypher

            “According to your previous comment, you do not seem to understand the problem with web browsers and JS SRP. You wrote:

            This is wrong, and I tried to point out why (by providing those links).”

            (sigh)

            Please actually read the thing that you’re calling wrong. You are confusing a requirement of the protocol with a requirement of deploying the protocol. This is equivocation. You make the claim that you shouldn’t need SRP because SRP is dependant on SSL, but that’s backwards. Then, you claim that without SSL to ship outbound, there is no value to using SRP to ship back inbound, which is conceptually faulty. Then, after it’s pointed out to you that modern SSL is actually *built* *on* SRP, you insist that because in current context it is commonly needed to use SSL to deploy SRP effectively, you imagine that that means it provides no value in the other direction afterwards.

            This is what is known in the industry as “silly.”

            After you were told that you don’t understand what’s being said to you, you simply imitated what was being said to you. After begging for more explanation and being told that your attitude was what was costing you more explanation.

            .

            “Remember, we are in “web browser web server” context.”

            No, that’s the mistake you’re making. There is no such context. The requirements to deploy code in one hypothetical situation do not undermine the value of code in a subsequent, different situation, going in the reverse direction.

            Security is not built on metaphor, and so far you have shown no actual reason to believe that SRP is a bad idea. Nobody cares if the implementation has to be shipped outbound in a tunnel. That has absolutely nothing whatsoever to what value the code can provide in the reverse direction shipping back.

            You just want to win an argument. You have no interest in understanding your mistake. You’re not even trying to understand your mistake.

            .

            “The “site-wide salt” sounds like local parameterization. … the use of local parameterization (or peppering as it is often called),”

            That’s nice.

            1) It’s not parameterization. It’s semipermanent.

            2) It’s not local.

            3) Local parameterization is not peppering.

            4) This is not peppering.

            5) You appear to be much too comfortable using words you don’t actually understand.

            .

            “but I don’t think it is a typical reason”

            That’s nice. I did not ask what you thought and I have made it repeatedly clear that I am not interested in your opinion, because I believe it to be extremely poorly informed.

            .

            “This is not “my opinion”, I didn’t invent these things.”

            Your opinion on things you didn’t invent remains an opinion. When you say things like “I don’t think,” and provide no technical justification, no evidence, and no supporting logic, that’s an opinion.

            Yes, your opinions are noted. Please stop repeating that anything you don’t understand doesn’t seem important to you.

            .

            “This is what is a common practice in security scene.”

            You have no idea what’s common practice in the security scene. You are not part of the security scene. You don’t have any training in the security scene. Stop announcing as an authority.

            .

            “I don’t recall FIPS making a statement about pre-hashing on web browsers.”

            That’s nice. I’m not interested in what you don’t remember.

            .

            “Source (pages on books or whatever the source is)?”

            Stop arguing without any form of citation then demanding sources from other people on the things you claimed. You invoked Schneier, not me.

            Nobody *cares*.

            .

            “I really wonder how you see the standard practice so much different.”

            Probably because I have training, certification, was a professional, and didn’t learn from blogs and reddit.

            .

            “But well, as long as you just “Lol” to material written by security expert(s).”

            I have not done that. What I laughed at was your inappropriate, off-topic citation which did not support your claim. This is very much like when one of those cranks that thinks fluoride in the water is killing us all cites an article that says nothing whatsoever about their position, and when nobody takes them seriously, says “omg i can’t believe you’re laughing at experts.”

            I’m not laughing at experts. I’m laughing at you.

            You are now making false claims to justify feeling ignored.

            .

            “I once more emphasize that we are dealing with web browser environment. You don’t see a problem here?”

            The problem I see here is that I have repeatedly explained why your over-generalization doesn’t make sense and you keep missing the explanation.

            And that you’re going to post again, arguing again, ignoring all your mistakes, declining to defend any of your positions, and demanding that I defend not being impressed by your no-data positions.

            That’s not how things work.

          • http://timoh6.github.io/ Timo

            Originally you wrote:

            > Pre-transit stretching and hashing under scrypt, exchanging the residue with SRP…

            I pointed out the problem with JavaScript SRP running on a web browser and backed up my point by providing a link to the Matasano article and a link to an answer by Thomas Pornin. You have provided no back up for your claims and seems you are ignoring the material I linked to (which both was written by security professionals). Is there something you disagree with the Matasano article or with the answer by Thomas Pornin?

            I asked a source to back up your claim about FIPS 140-2 requirements, you failed at it by answering:

            > That’s nice. I’m not interested in what you don’t remember.

            You originally wrote:

            > This is Bruce Schneier’s system, not mine, so to invoke him to describe this as too complex is a little … weird

            Then you wrote:

            > Stop arguing without any form of citation then demanding sources from other people on the things you claimed. You invoked Schneier, not me.

            As you see, you invoked Schneier (yes, I quoted him earlier about complexity). I thought you meant the system you recommended originally as Schneier’s. That is why I asked a back up for that. Of course if that was not what you meant, my request for back up is irrelevant.

            What did you mean by saying: “This is Bruce Schneier’s system, not mine, so to invoke him to describe this as too complex is a little … weird”? What is Bruce Schneier’s system?

            So, can you give a back up for this part of your described system: “Pre-transit stretching and hashing under scrypt, exchanging the residue with SRP”? Anyone besides you recommending it (source)?

          • StoneCypher

            “I pointed out the problem with JavaScript SRP”

            Yes, you pointed out something you thought was a problem. You have conveniently declined to address why you were told that was wrong, and kept raising it.

            It’s not clear to me why you keep pointing this out.

            .

            “and backed up my point by providing a link to the Matasano article”

            Yes, you provided an article. The article is not about what you were told. What you have backed up is that you don’t actually understand what was said to you well enough to provide an article on the correct topic.

            It’s not clear to me why you keep pointing this out.

            .

            “You have provided no back up for your claims”

            Mmm hmm.

            .

            “> Stop arguing without any form of citation then demanding sources
            from other people on the things you claimed. You invoked Schneier, not
            me.”

            As you see, you invoked Schneier (yes, I quoted him earlier about complexity).”

            When someone tells you to stop invoking a person, and your response is “see? you just invoked him,” I kind of wonder what you thought people would think.

            .

            “What did you mean”

            Please stop trying to engage with me. Every time I give you an answer, you ignore it.

            .

            “So, can you give a back up”

            I get bored of you asking the same question repeatedly, ignoring the answer, ignoring the mistakes you made, then asking again.

            If your goal is to just keep asking until someone gets bored of you and walks away, so that you can pretend to yourself that you didn’t get an answer and must have been right the entire time, then you’ve just achieved your goal.

          • http://timoh6.github.io/ Timo

            > Yes, you pointed out something you thought was a problem. You have conveniently declined to address why you were told that was wrong, and kept raising it.

            It is clear we are talking about web browser context, and you did not mention SSL/TLS in your suggestion, so yes, as pointed out, deploying a JS SRP is not a good idea. JS SRP requires more code and thus increases room for bugs and implementation errors.

            Same thing about added complexity apply when you deploy your JS over SSL/TLS (while in this scenario SRP can offer extra layer of security, but is this really something to be recommended for web browser environment in general – with the extra complexity added?)

            > Security is not built on metaphor, and so far you have shown no actual reason to believe that SRP is a bad idea. Nobody cares if the implementation has to be shipped outbound in a tunnel. That has absolutely nothing whatsoever to what value the code can provide in the reverse direction shipping back.

            You are making a mistake by thinking that hostile SRP code could provide some value “in the reverse direction shipping back”. If the JS SRP code running on a web browser is not hostile (not modified by an attacker), it is safe to assume the communication would be safe even there were no SRP at all (SRP just adds more code and room for bugs for no reason). See the Matasano article.

            > Please stop trying to engage with me

            I was just pointing out problems with a design you introduced and trying to have a conversation about it, but this conversation is not going anywhere if you dodge questions ;)

          • StoneCypher

            “You are making a mistake by thinking that hostile SRP code could provide some value “in the reverse direction shipping back.””

            Lol, clueless.

            .

            “> Please stop trying to engage with me

            I was just pointing out problems”

            Yep, homeopaths say that too.

  • Miguel Ibarra

    Thanks for the link, great resource! It was not my intention to recommend encryption above hashing, sorry if the article did not properly reflect that, that is why at the end I recommended using hashing for password field, and use encryption for the hint

  • Miguel Ibarra

    Awesome resource, just adding your post for reading it and analyze it further. My 1 sec recommendation actually comes from Enrico Zimuel’s presentation found at http://www.zimuel.it/password-insecurity-how-to-generate-and-store-passwords-in-a-secure-way/ I’ll definetely compare and contrast with your proposal.

    • http://timoh6.github.io/ Timo

      The recommendation about 1 second hashing time on Enrico’s slides is arguably wrong/misleading.

      Zend Framework 2.3 was released yesterday, and indeed they decreased the default bcrypt cost setting to 10 (Enrico did the change).

      If you look at, for example, Colin Percival’s scrypt paper, the stretching times are categorized for offline usage and interactive usage (and the interactive usage times are no higher than 100 ms).

      Thanks for the feedback!

  • frostymarvelous

    Awesome! Finally a crypto article that I can actually understand.