0

I am updating my helper functions library. I am wondering whether it is too much of salt in the password encryption?

Is there any difference between:

mb_substr(sha1($str . AY_HASH), 5, 10) . mb_substr(sha1(AY_HASH . sha1($str . AY_HASH)), 5, 10) . mb_substr(md5($str . AY_HASH), 5, 10)

and simply:

sha1(AY_HASH . sha1($str . AY_HASH))

AY_HASH being the salt. Which should I prefer and if neither is good, what is the best alternative?

Gajus
  • 69,002
  • 70
  • 275
  • 438
  • You are aware of this magic tool called [blowfish crypt](http://php.net/manual/en/function.crypt.php) which, in addition to being [adaptive](http://www.postgresql.org/docs/9.0/static/pgcrypto.html), uses a different salt for each password, right? – Denis de Bernardy Jun 29 '11 at 10:44

1 Answers1

4

A salt should be generated for each password, not a secret string used on every password. Re-using a salt means that the attacker will only need to create one rainbow table for every password instead of one per password.

I invite you to read a previous answer I wrote on secure hashing. The rules are simple:

  • Do NOT use a single salt for all passwords. Use a randomly generated salt per password.
  • Do NOT rehash an unmodified hash (collision issue, see my previous answer, you need infinite input for hashing).
  • Do NOT attempt to create your own hashing algorithm or mix-matching algorithms into a complex operation.
  • If stuck with broken/unsecure/fast hash primitives, use key strengthening. This increases the time required for the attacker to compute a rainbow table. Example:

function strong_hash($input, $salt = null, $algo = 'sha512', $rounds = 20000) {
  if($salt === null) {
    $salt = crypto_random_bytes(16);
  } else {
    $salt = pack('H*', substr($salt, 0, 32));
  }

  $hash = hash($algo, $salt . $input);

  for($i = 0; $i < $rounds; $i++) {
    // $input is appended to $hash in order to create
    // infinite input.
    $hash = hash($algo, $hash . $input);
  }

  // Return salt and hash. To verify, simply
  // passed stored hash as second parameter.
  return bin2hex($salt) . $hash;
}

function crypto_random_bytes($count) {
  static $randomState = null;

  $bytes = '';

  if(function_exists('openssl_random_pseudo_bytes') &&
      (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // OpenSSL slow on Win
    $bytes = openssl_random_pseudo_bytes($count);
  }

  if($bytes === '' && is_readable('/dev/urandom') &&
     ($hRand = @fopen('/dev/urandom', 'rb')) !== FALSE) {
    $bytes = fread($hRand, $count);
    fclose($hRand);
  }

  if(strlen($bytes) < $count) {
    $bytes = '';

    if($randomState === null) {
      $randomState = microtime();
      if(function_exists('getmypid')) {
        $randomState .= getmypid();
      }
    }

    for($i = 0; $i < $count; $i += 16) {
      $randomState = md5(microtime() . $randomState);

      if (PHP_VERSION >= '5') {
        $bytes .= md5($randomState, true);
      } else {
        $bytes .= pack('H*', md5($randomState));
      }
    }

    $bytes = substr($bytes, 0, $count);
  }

  return $bytes;
}

If anything however, you should use bcrypt, which is future-adaptable. Again, I invite you to my previous answer for a more detailed example.

Community
  • 1
  • 1
Andrew Moore
  • 93,497
  • 30
  • 163
  • 175
  • What exactly is the driver for using a random salt ? In order to check password correctness you have to save it in relation. The oone and only attack vector against hashes is that someone has access to the database ... where he can read the related salt as well ... ! So maybe im something missing but as far as i know the only advantage of salting is that someone may not compare the database dump against a rainbow table. Pls enlighten me. – fyr Jun 29 '11 at 10:50
  • 1
    @fyr: A salt requires the attacker to generate a rainbow table tailored to that specific salt. While generating a rainbow table is costly, if you reuse the same salt for each password, the attacker only has to generate one table to crack all your passwords. However, if you generate a random salt per password, the attacker needs to generate a rainbow table for each and every password he wants to crack (instead of cracking all your passwords with one table only). Key strengthening increases the time required for the attacker to generate a rainbow table. – Andrew Moore Jun 29 '11 at 10:52
  • 1
    @fyr, if each user gets their own salt, then an attacker cannot compute a table with the one fixed salt for the entire site. It'll be twice as hard to brute-force crack a password for two users if each user has their own salt. Ten thousand times harder if you have ten thousand different salts. It's so cheap to randomly generate salts, there's no reason not to. – sarnold Jun 29 '11 at 10:54
  • Thats correct, the attacker gains access to the salt. But now he needs to compute a rainbow table for each salt, and if you use a unique salt then he has to do it for each user. –  Jun 29 '11 at 10:55
  • @andrew Actually thats not true. Because the amount of rainbowtables someone has to calculate is limited by the amount of possible values a salt can take. So the amount of rainbow tables someone needs to generate is equal in both worst cases. But you lower security while relating the hash to a specific user which he receives via his database access anyways despite the person who has saved his salt in a different region of his os .. where someone needs to escalate root privileges to gain the salt. – fyr Jun 29 '11 at 10:59
  • 1
    @fyr: You are the one who is wrong. If you use a single salt, your salt is also subject to a rainbow table attack. The attacker simply has to register. Then, knowing his own password and retrieving the hashed version, he can generate a table to find the proper salt. – Andrew Moore Jun 29 '11 at 11:00
  • @fyr: A salt **IS** a cryptographic nonce. You are never supposed to reuse it nor is it considered a secret. [Here's a paper from 1978 describing this practice](http://wolfram.schneider.org/bsd/7thEdManVol2/password/password.pdf). Reusing your salt reduces the effectiveness of using a salt. It won't stop the attacker and it won't slow him down as much as a random salt. Also, a random salt has a benefit of preventing the attacker from identifying two users with the same password. – Andrew Moore Jun 29 '11 at 11:09
  • @Andrew Moore, those are very helpful comments. Thank you for explaining the concept of salt for me. – Gajus Jun 29 '11 at 13:21
  • Just to confirm: `bcrypt == CRYPT_BLOWFISH`? (http://ca.php.net/manual/en/function.crypt.php) – Gajus Jun 29 '11 at 14:16
  • @Guy: Yes, bcrypt is supported when `CRYPT_BLOWFISH == 1` – Andrew Moore Jun 29 '11 at 14:26
  • @Andrew Moore, does this look like a good way to generate bcrypt with salt hash? https://gist.github.com/4e2bf3b00b06ab625b7f Is there anything you'd recommend to improve? – Gajus Jun 29 '11 at 15:07
  • @Guy: You shouldn't allow for manual salts at all and you are wasting entropy with your salt (as well as it being predictable). Please see my [bcrypt class](http://stackoverflow.com/questions/6340105/how-can-we-create-a-fairly-secure-password-hash-in-php/6340197#6340197) if you are going to be using bcrypt. – Andrew Moore Jun 29 '11 at 20:27