I have a password generator:
import random, string
def gen_pass():
foo = random.SystemRandom()
length = 64
chars = string.letters + string.digits
return ''.join(foo.choice(chars) for _ in xrange(length))
According to the docs, SystemRandom uses os.urandom which uses /dev/urandom to throw out random cryto bits. In Linux you can get random bits from /dev/urandom or /dev/random, they both use whatever entropy the kernel can get its hands on. The amount of entropy available can be checked with tail /proc/sys/kernel/random/entropy_avail, this will return a number like: 129. The higher the number more entropy is available. The difference between /dev/urandom and /dev/random is that /dev/random will only spit out bits if entropy_avail is high enough (like at least 60) and /dev/urandom will always spit out bits. The docs say that /dev/urandom is good for crypto and you only have to use /dev/random for ssl certs and the like.
My question is will gen_pass be good for making strong crypto grade passwords always? If I call this function as quickly as possible will I stop getting strong cryto bits at some point because the entropy pool is depleted?
The question could also be why does /dev/urandom always produce strong cryto bits and not care about the entropy_avail?
It is possible that /dev/urandom is designed so that its bandwidth is capped by the number of cycles you can guess will be correlated with an amount of entropy, but this is speculation and I can't find an answer.
Also this is my first stackoverflow question so please critique me. I am concerned that I gave to much background when someone who knows the answer probably knows the background.
Thanks
update
I wrote some code to look at the entropy pool while the /dev/urandom
was being read from:
import subprocess
import time
from pygooglechart import Chart
from pygooglechart import SimpleLineChart
from pygooglechart import Axis
def check_entropy():
arg = ['cat', '/proc/sys/kernel/random/entropy_avail']
ps = subprocess.Popen(arg,stdout=subprocess.PIPE)
return int(ps.communicate()[0])
def run(number_of_tests,resolution,entropy = []):
i = 0
while i < number_of_tests:
time.sleep(resolution)
entropy += [check_entropy()]
i += 1
graph(entropy,int(number_of_tests*resolution))
def graph(entropy,rng):
max_y = 200
chart = SimpleLineChart(600, 375, y_range=[0, max_y])
chart.add_data(entropy)
chart.set_colours(['0000FF'])
left_axis = range(0, max_y + 1, 32)
left_axis[0] = 'entropy'
chart.set_axis_labels(Axis.LEFT, left_axis)
chart.set_axis_labels(Axis.BOTTOM,['time in second']+get_x_axis(rng))
chart.download('line-stripes.png')
def get_x_axis(rng):
global modnum
if len(filter(lambda x:x%modnum == 0,range(rng + 1)[1:])) > 10:
modnum += 1
return get_x_axis(rng)
return filter(lambda x:x%modnum == 0,range(rng + 1)[1:])
modnum = 1
run(500,.1)
If run this and also run:
while 1 > 0:
gen_pass()
Then I pretty reliablly get a graph that looks like this:
Making the graph while running cat /dev/urandom
looks smiler and cat /dev/random
drops off to nothing and stays low very quickly (this also only reads out like a byte every 3 seconds or so)
update
If I run the same test but with six instances of gen_pass(), I get this:
So it looks like something is making it be the case that I have enough entropy. I should measure the password generation rate and make sure that it is actually being capped, because if it is not then something fishy may be going on.
update
I found this email chain
This says that urandom will stop pulling entropy once the pool only has 128 bits in it. This is very consistent with the above results and means that in those tests I am producing junk passwords often.
My assumption before was that if the entropy_avail was high enough (say above 64 bits) then /dev/urnadom
output was good. This is not the case it seems that /dev/urandom
was designed to leave extra entropy for /dev/random
in case it needs it.
Now I need to find out how many true random bits a SystemRandom call needs.
urandom() method is used to generate a string of size random bytes suitable for cryptographic use or we can say this method generates a string containing random characters. Return Value: This method returns a string which represents random bytes suitable for cryptographic use.
In #26839 os. urandom() was made non-blocking and non-exception-raising on Linux. As a result os. urandom() is no longer a CSPRNG under some conditions as it can and will return predictable random values without any sort of warning or error flag.
/dev/urandom is widely considered safe for all cryptographic purposes, except by the most paranoid people."
'Urandom' is used where there is constant need of random numbers and its randomness is not much important while 'random' is used where there is a security concern and its randomness should be reliable as it blocks outputting random numbers if entropy is not up to the mark.
There's a subtle difference between the output of /dev/random
and /dev/urandom
. As has been pointed out, /dev/urandom
doesn't block. That's because it gets its output from a pseudo-random number generator, seeded from the 'real' random numbers in /dev/random
.
The output of /dev/urandom
will almost always be sufficiently random -- it's a high-quality PRNG with a random seed. If you really need a better source of random data, you could consider getting a system with a hardware random number generator -- my netbook has a VIA C7 in it, which can generate quite a lot of properly random data (I get a consistent 99.9kb/s out of /dev/random, 545kb/s out of /dev/urandom).
As an aside, if you're generating passwords then you might want to look at pwgen
-- it makes nice pronounceable passwords for you :).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With