Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleaner key generation #27

Closed
nicktimko opened this issue Nov 20, 2015 · 6 comments
Closed

Cleaner key generation #27

nicktimko opened this issue Nov 20, 2015 · 6 comments

Comments

@nicktimko
Copy link

import random
chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
key = ''.join(random.SystemRandom().choice(chars) for _ in range(50))

The above method for secret key generation is good that it's cryptographically secure and fairly strong, but I would advocate for a different method:

import os
import base64
key = base64.b64encode(os.urandom(256 // 8))

The current method is a bit unclear as to how much entropy there is in the key (currently 50 * log2(50) = 282 bits). Drawing random bytes directly from os.urandom (the same CSPRNG that random.SystemRandom uses) then base64-encoding them provides a very clear indication of strength: whatever the argument to urandom is (in bytes, //8 for bits).

@hjwp
Copy link
Owner

hjwp commented Nov 20, 2015

Hi Nick. Wow. Neat. And Hardcore!

I like the fact that it makes the entropy really easy to see, but I worry it's a bit harder to understand for non crypto experts. Not everyone knows what base-64 encoding is, and the 256 // 8 is just baffling if you don't guess that the author is trying to make the entropy explicit...

How strongly do you feel about it? I don't want to discourage one of my very rare contributors by rejecting this outright...

How are you enjoying the book anyways?

@malemburg
Copy link

From the implementation side of things, the base64 version is faster, less obscure (have a look at how .choice() is implemented and try to find out exactly how many bytes are being read from urandom to see what I mean) and less wasteful on urandom data.

In terms of readability and educating the reader about what exactly happens, I think the original version is still better.

Note that the base64 version only reads 32 bytes from urandom, whereas the choice based one reads at least 50 bytes and then throws away the top 2 bits of each byte. The base64 one has 256 ** 32 possible keys, the original one 50 ** 50 keys - several orders of magnitude more. The base64 version would need to read 36 bytes to give the same number of possibilities - which is actually better than the choice based one, since you save >=14 urandom bytes input and the key length is only 48 bytes.

Regarding the idea of os.urandom(n) returning 8 * n bits of entropy, I don't think this is true, but then the term "entropy" has too many meanings depending on who you ask anyway ;-) See e.g. http://www.2uo.de/myths-about-urandom/ for one set of views on this.

@nicktimko
Copy link
Author

Love the book, it's helping me to break some habits (YAGNI, etc :P) as well as giving me a good walk-through of the testing functionality inside of Django (which I knew was there, but never really figured out). Speaking of Django, with a look at their SECRET_KEY generation in startproject, it's evident where you got that snippet from ;)

To calculate bits of entropy, strength, whatever...: length * log2(n_symbols). So for a 50-length string of 50 symbols, 50 * log2(50) = 282.2 bits, versus the (arbitrarily chosen, but can also be arbitrarily rechosen) 256 bits (= 32 * log2(256) ~= 43 * log2(64)). Up it to 384 perhaps, but 256 is plenty strong nowadays.

For orders, every 3.3 bits is equivalent to a power of 10 (because log2(10) = 3.32). To convert bits to combinations, just do 2**x, but talking in bits is usually more convenient and comparable to other things.

Both methods use the same PRNG source, so there is no difference in some side-channel(?) attack that exploits the weakness of the RNG.

@hjwp
Copy link
Owner

hjwp commented Nov 23, 2015

Marc-Andre (hi!), Nick, thanks very much, this has been very good for my edumecation. Am reminded of Larry Hastings' talk on PRNGs... https://duckduckgo.com/?q=larry+hastings+random+numbers&ia=videos

Hope no-one's offended if I close this and leave the code as-is?

@hjwp hjwp closed this as completed Nov 23, 2015
@nicktimko
Copy link
Author

I'm OK with it for now. I'm being kinda nit-picky, but I'd do up a PR for funsies if you'd be receptive. I'm not sure how to do so against the myriad branches...

@hjwp
Copy link
Owner

hjwp commented Nov 24, 2015

I don't really want to change the version in the book, but it's an interesting discussion -- I'll tell you what, if you want to write up a blog post about it, explaining your alternative, and writing up a bit of the discussion about pros + cons, entropy, etc, then I could link to it from the book, in a little note maybe?

Or I could just link to this PR discussion, if you're not big on blogging...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants