Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will python SystemRandom / os.urandom always have enough entropy for good crypto

Tags:

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: enter image description here

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: enter image description here

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.

like image 882
Chris Avatar asked Mar 29 '11 23:03

Chris


People also ask

What does urandom do in Python?

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.

Is OS urandom predictable?

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.

Is OS urandom safe?

/dev/urandom is widely considered safe for all cryptographic purposes, except by the most paranoid people."

What is the difference between $random and urandom?

'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.


1 Answers

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 :).

like image 75
Andrew Aylett Avatar answered Sep 23 '22 14:09

Andrew Aylett