6

I'm trying to generate blowfish hashes and I was wondering if it's safe enough to count on mt_rand() to generate my salts for me?

function blowfish($string, $salt = NULL, $iterations = '08')
{
    if( ! $salt)
    {
        $seed = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        for ($i = 0; $i < 22; $i++)
        {
            $salt .= $seed{mt_rand(0, 63)};
        }
        $salt = '$2a$' . $iterations . '$' . $salt;
    }

    return crypt($string, $salt);
}

The character $seed above is the allowed 64-character blowfish-salt alphabet. I plan on using this to generate and compare passwords.

$password = 'my^$%#password';
$hash = blowfish($password);

if($hash = blowfish($password, $hash))
{
    print "Matches\n";
    print $hash . "\n";
}

Edit

I never realized this, but what @zerkms says is true. Salts are only to prevent reusable precomputed attacks since the salt is known at the same point that they have access to the hash. So the goal isn't a non-reversible salt - it's a random salt.

So, anything wrong with this?

function blowfish($string, $salt = NULL, $iterations = '12')
{
    return crypt($string, $salt ?: "$2a\$$iterations$" . md5(uniqid('', true)));
}

Also, as noted in the title and above code, I'm not implementing my own hashing algorithm.

Update 2

Using the mcrypt extension if loaded leads to the following, which is actually faster probably because uniqid (u)sleeps or something.

function blowfish($string, $salt = NULL, $iterations = '12')
{
    return crypt($string, $salt ?: "$2a\$$iterations$" . base64_encode(mcrypt_create_iv(22, MCRYPT_DEV_URANDOM)));
}

Update 3

base64_encode is faster than md5 - but it has invalid blowfish characters in it like +. So changed to md5 now.

function blowfish($string, $salt = NULL, $iterations = '12')
{
    return crypt($string, $salt ?: "$2a\$$iterations$" . md5(mcrypt_create_iv(22, MCRYPT_DEV_URANDOM)));
}
Xeoncross
  • 55,620
  • 80
  • 262
  • 364
  • 2
    Salt generation algorithm doesn't matter. What matters is that you have different salts for each password. ps: personally I think your current salt generation is overengineered and I would go with just `md5(uniqid('', true))` – zerkms Apr 16 '12 at 23:37
  • 1
    @pst: Any **real** issues with my advice? – zerkms Apr 16 '12 at 23:51
  • you could use `$salt = substr(str_shuffle("./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), -22);` probably quicker.. – Lawrence Cherone Apr 16 '12 at 23:55
  • 2
    ps: seems like there is another programming myth here: about overestimation of the salt generation algorithms. – zerkms Apr 16 '12 at 23:56
  • @zerkms It means you are letting them know what salts you are using (MD5 of numbers), which in theory means they could precompute attacks. I could create rainbow tables for strings salted with MD5 hashes of 1 through 100000, say. Sure, it's unlikely, but it's conceivable. Truly random is better. – Gareth Latty Apr 16 '12 at 23:58
  • 3
    @Lattyware: "It means you are letting them know what salts you are using" --- so what? Salt is not intended to be secret. "which in theory means they could precompute attacks" --- rainbow tables nowadays are nonsense, CPU is cheaper http://www.codinghorror.com/blog/2012/04/speed-hashing.html PS: `uniqid('', true)` is barely predictable and it is not just numbers – zerkms Apr 17 '12 at 00:02
  • uniqid= numbers and letters and a period 23 characters long –  Apr 17 '12 at 00:03
  • @zerkms I'm not saying that them knowing the salts is bad, I'm saying that them knowing what salts *everyone* is using is bad. If everyone used your system, the salt becomes useless, just as one salt for your entire database only requires them to recompute the rainbow table once, using the same salts in different databases mean you just compute the rainbow tables you will need. What you say about rainbow tables may be true - but if you are going to do a salt, why not do it right? – Gareth Latty Apr 17 '12 at 00:09
  • @zerkms I derped and misread your comment, I realise that's not what you meant, so disregard that all XD. Sorry. – Gareth Latty Apr 17 '12 at 00:11
  • @Lattyware: and what's wrong with my advice? I didn't advice a single salt for the whole database. I could copy-paste my words here, once again: What matters is that you have **different** salts for each password. – zerkms Apr 17 '12 at 00:12
  • @zerkms Yeah, I get that now, I thought you were suggesting using User IDs, not a random ID - so while different per-user, they would be the same across multiple databases (md5(1) through md5(number of users)). It was my mistake, your suggestion is totally valid. – Gareth Latty Apr 17 '12 at 00:14
  • @zerkms, can I get any feedback on your md5 approach vs using mcrypt? Everything look good to you? – Xeoncross Apr 17 '12 at 15:53
  • @Xeoncross: as I said in my first comment - it doesn't matter how you generate salt, just generate random ones – zerkms Apr 17 '12 at 20:24

2 Answers2

6

Use mcrypt to create a salt.

Jack
  • 5,680
  • 10
  • 49
  • 74
  • That's a good idea, I can use `MCRYPT_DEV_RANDOM` instead of manually opening a connection to `/dev/urandom` and reading from it and then converting it to base64. – Xeoncross Apr 16 '12 at 23:57
  • `MCRYPT_DEV_RANDOM` opens a connection to `/dev/random` not `/dev/urandom`. `MCRYPT_DEV_URANDOM` do open a connection to `/dev/urandom`. – aymericbeaumet Oct 21 '13 at 12:44
4

Using mt_rand for your salt, is secure enough; provided obviously that you utilize a per password different random salt.

However, with that said; nearly any self-implemented password hashing system is insecure. Few individuals are well versed enough to generate and maintain a secure password hashing system. For reference I implore you to read over a few SO threads:

Php/Password best practices

Salt generation and PHP

Do not roll your own

I suggest DO NOT ROLL YOUR OWN. Period. Please look into using the established library of PhPass of password hashing for PHP if possible. Benefits include real-world application testing, highly secure implementation, and extreme ease of use.

Community
  • 1
  • 1
PenguinCoder
  • 4,335
  • 1
  • 26
  • 37
  • +1 Security take a lot of time and skill to do right. Why not take advantage of those who have made the mistakes before you have? – Gareth Latty Apr 16 '12 at 23:47
  • 4
    "self-implemented password hashing system is insecure" --- I don't see self-implemented hashing there, do I? – zerkms Apr 16 '12 at 23:47
  • @PenguinCoder, I'm not rolling my own password hashing - I'm using the tried-and-true blowfish algorithm built into PHP. I just want to know if I can use 22x `mt_rand()` for creating the salts. – Xeoncross Apr 16 '12 at 23:52
  • 1
    @pst: do you have anything **real** against md5 + uniqid for *generating salt*? – zerkms Apr 16 '12 at 23:53
  • @pst He isn't suggesting MD5ing the password, he's suggesting MD5 hashing the user ID to generate a salt, rather than generating it randomly. – Gareth Latty Apr 16 '12 at 23:59
  • @pst, I've only read about theoretical problems and a couple collisions with sha1. I can't imagine that it's actually broken yet - just that it's better to *play it safe* and keep moving to SHA2 and SHA3 when it comes out. Actually, since they are so fast that's why I use blowfish with higher iterations anyway. – Xeoncross Apr 17 '12 at 00:00
  • @Lattyware: I didn't suggest hashing user's ID. Please read my comments once again – zerkms Apr 17 '12 at 00:02
  • @pst: salt is not intended to be secret thing. And if attacker has both salt and hash - it doesn't matter what algorithm has been used to generate it, because what only matters is the salt value – zerkms Apr 17 '12 at 00:04
  • @pst: how hashing algorithm is related to **salt generation** algorithm? As long as both salt and hash known to the attacker - it doesn't matter where the salt came from - it wouldn't protect from bruteforce – zerkms Apr 17 '12 at 00:07
  • @pst: I didn't suggest that, I could even copy-paste my advice once again: I would go with just `md5(uniqid('', true))` – zerkms Apr 17 '12 at 00:09
  • 3
    @pst: salt generation algorithm doesn't matter - the only thing that matters is that result salt is random. I'm sorry, but I'm being boring discussing such trivial things – zerkms Apr 17 '12 at 00:10
  • @zerkms My mistake, misread what you meant. I was halfway there. – Gareth Latty Apr 17 '12 at 00:12
  • Hehe, that explains everything :-) Sorry if in some comments my words were a bit rude – zerkms Apr 17 '12 at 00:13
  • 2
    @zerkms No worries, you were completely right. It's always annoying when you can't get someone to understand what you mean, and I was at fault. – Gareth Latty Apr 17 '12 at 00:15