Let's say I have a character set. Let's say I'm using PHP.
$charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" . "abcdefghijklmnopqrstuvwxyz" . "0123456789" . "!@#$%^&*()_ -=";
If I build a string from a static character set, using cryptographic randomness...is the resulting password cryptographically random? I'm not 100% sure I'm even asking the right question here. Is this practical?
$pw = "";
for($i=0; $i<16; $i ){
$pw .= $charset[random_int(0, iconv_strlen($charset)-1)];
}
echo $pw;
I think the answer is no, right? I think the best practice way to do something like this is to first start off with a random character space (drawn from a source with high enough entropy) and then use a PRNG to get random indexes like I'm doing...?
Thanks.
CodePudding user response:
What you're doing looks okay. I'm not a PHP expert but there might be timing related issues here, whether that matters to your definition of security might be an issue (but I'd guess probably not).
To determine whether this is "secure" you'd have to define what you mean by secure! For example, what sorts of attacks are you trying to defend against and how much knowledge of the internal state of your computer do you think is reasonable for an attacker to have. You could assume they know the algorithm you're using and all previous outputs you generated. You can then work out the space an attacker would have to search to recover a password given some type of attack.
Assuming you trust that the RNG behind random_int
is really cryptographically secure (e.g. by making sure that your copy of PHP is actually calling urandom
, maybe via strace
) and an attacker can't observe kernel state (i.e. you have to trust your host), then we can be confident that observing previous output wouldn't help with prediction.
You can then calculate the entropy contained in your password, which for your algorithm is log(76 ** 16, 2)
~= 100 bits. This is because they'd have to guess the output of random_int(0, 75)
(i.e. 76 distinct values drawn uniformly at random) and it's reasonable to assume a CSPRNG is IID for each of your 16 draws.
Depending on what this password being used for this might well be enough. If this was used for authentication against a server that would be enough even without any standard practices of locking an account after some number of attempts (if somebody started making millions of requests per second you'd probably know about it, and even then you'd still have years of time to respond). If you expect the salted hash of this to be revealed to an attacker it would probably be okay, but I'd probably aim for >128 bits (or about a billion times harder). The reason for the larger space here is that they can perform this attack "off-line" so you wouldn't know about it and also they could scale it much more easily.
I'd recommend reading further before trusting my opinion! Maybe search around https://security.stackexchange.com/ for some good references