-12

If you start with a list of hundreds or perhaps thousands of separate items, and you want Python to choose one (at a time) at random (for creating a ciphertext), how "random" will it really be? It's highly important that there be no repeats of the same item (integers, strings) whatsoever, because of the crypt0graphic nature of the app. But is there some way to confidently perform random selection from dictionaries?

Thanks for the suggestions of such, but this question is not a duplicate of the two possibilities listed. For one thing, the range of items up for selection needs to be entirely dynamic, yet for brevity's sake, I've limited the description of the mechanics of the app, which is intended for educational/entertainment purposes and not for saving the world ;-)

mjmill
  • 1
  • 2
  • If you do `random.shuffle(container)[:n]` where `n` is the number of results you want, that could work. Just doing choice repeatedly could potentially lead to repeats – Patrick Haugh Jan 03 '17 at 14:59
  • 2
    Possible duplicate of [Pick N items at random from sequence of unknown length](http://stackoverflow.com/q/9690009/953482). Short answer: Shuffle once, then pop N times. – Kevin Jan 03 '17 at 15:00
  • 1
    Possible duplicate of [Generating random integers in a specific range](http://stackoverflow.com/questions/363681/generating-random-integers-in-a-specific-range) – Jonathan Newton Jan 03 '17 at 16:07
  • If you're intending it for educational purposes, that's even more critical than production quality. Teaching people to do the wrong thing is much worse than doing the wrong thing yourself. – Filip Haglund Jan 04 '17 at 13:50

4 Answers4

5

From random module docs:

Warning: The pseudo-random generators of this module should not be used for security purposes. Use os.urandom() or SystemRandom if you require a cryptographically secure pseudo-random number generator.

Yevhen Kuzmovych
  • 10,940
  • 7
  • 28
  • 48
4

If you're using Python 3.6 you can use:

from secrets import choice

choice(your_options)

According to the module documentation:

The secrets module is used for generating cryptographically strong random numbers suitable for managing data such as passwords, account authentication, security tokens, and related secrets.

MSeifert
  • 145,886
  • 38
  • 333
  • 352
  • That will give you one random item from `your_options`, not multiple items with no repeats. Of course, avoiding repeats _may_ be a bad idea, it depends exactly on what the OP is doing. In some crypto apllications you do _not_ want repeats, eg in the shuffle-like process used in [format-preserving encryption](https://en.wikipedia.org/wiki/Format-preserving_encryption) – PM 2Ring Jan 03 '17 at 15:54
  • 1
    @PM2Ring Good point, it's unfortunate that `secrets` doesn't have a `sample` function then. But it could be implemented by using some sort of unique_everseen ([1](https://docs.python.org/3/library/itertools.html#itertools-recipes) [2](http://iteration-utilities.readthedocs.io/en/latest/api/cfuncs.html#iteration_utilities.unique_everseen)) functionality within a `while` loop. – MSeifert Jan 03 '17 at 16:02
3

First off, what you're talking about is how random a human perceives a generator to be; not how random something is. There's a good post on how Spotify shuffles music to seem more random to humans, while actually reducing entropy. (or at least how they used to do it).

Not ever using the same number/string twice in the same message is a worse security flaw than the one used to crack the Enigma during WW2.

Second, by "how random", you probably mean "how much entropy".

Third, the random module in Python is not cryptographically secure, as others have pointed out. Don't use it for cryptography-related code. There's os.urandom(), SystemRandom or secrets, but you should probably not use any of them, because:

Fourth, and most important, you should never roll your own crypto unless you have a degree in cryptography. Check what the state of the art is, and use that instead. Crypto SE knows their stuff, and so does Security SE.

Community
  • 1
  • 1
Filip Haglund
  • 13,919
  • 13
  • 64
  • 113
  • I think your 3rd point needs a little clarification. It's certainly not safe to use the default Mersenne Twister (or the old Wichmann-Hill generator which was used in early Python but has been removed in Python 3) for crypto, but you can safely use `random` functions for crypto if you specify the `SystemRandom` generator. But of course your 4th point trumps that. :) – PM 2Ring Jan 03 '17 at 15:26
  • @PM2Ring good point. I have some feeling that libraries/modules providing random functionality that are not secure by default might not consider security all the way through, like not using constant-time comparisons. A library/module/package/... that only supports cryptographically secure random is (hopefully) secure all the way through. For example, Go has `crypto/rand` and `rand` as two separate packages, and Python has `secrets` and `random` now. – Filip Haglund Jan 03 '17 at 15:33
  • Good point! The functions in `random` are certainly **not** designed to resist timing attacks, but that _might_ not be an issue for the OP's application. – PM 2Ring Jan 03 '17 at 15:37
1

One of the big additions in the recently released Python 3.6 is the addition of a secrets module for generating cryptographically strong random numbers.

Patrick Haugh
  • 59,226
  • 13
  • 88
  • 96