2
$\begingroup$

In our Python codebase, some random bytes were generated that we wanted to be cryptographically secure. Previously, the code was:

capability = "".join(secrets.choice(string.digits) for i in range(33))

I've changed it to:

capability = secrets.token_bytes(16)

By my estimation, the first version chose 33 times between 10 digits and so had 33*log2(10)=110bits of entropy, while the second has 128bits of entropy. Is this calculation correct?

$\endgroup$
4
  • 4
    $\begingroup$ "How less secure were those random bytes"; it also depends on what you did with those bytes. For example, if you used them as an AES-128 key, well, that means that you most likely used only the first 16 bytes of the first example, which is significantly worse than "110 bits security" $\endgroup$
    – poncho
    Commented Apr 29, 2022 at 14:24
  • 1
    $\begingroup$ I agree with Poncho. I don't see anything wrong with your calculations, but it then depends on how the digits are used (and considering the method for generating them, that may be any good or bad way). Once thing is also that if this is considered a number that you might end up with a few leading zeros, which may be removed before the value is used. It again depends on the code thereafter if that has a significant impact or not. $\endgroup$
    – Maarten Bodewes
    Commented Apr 29, 2022 at 14:43
  • 2
    $\begingroup$ Beware of the Duck-typing used in Python. Having a String consisting of digits or bytes is rather different. I don't like using strings for binary values; if I'd design an API I would just accept bytes or bytearray for Python 3 $\endgroup$
    – Maarten Bodewes
    Commented Apr 29, 2022 at 14:47
  • $\begingroup$ We use the whole thing to make an unguessable URL (wiith base64). $\endgroup$ Commented May 3, 2022 at 15:54

1 Answer 1

3
$\begingroup$

Your math are correct, theoretically. Indeed, using printable digits to store randomness is a trade-off between storage and readability. However, since you are talking about cryptographic security, I want to mention something.

When considering randomness there are two things you should keep in mind : unpredictability and uniformity.

  • Not your case but, if you are using python built-ins like random, you have uniformity but not unpredictability, because it uses a PRNG. So, speaking cryptographic wise according to Kerchoff's laws, you get 0 entropy.
  • If you are using secrets. It uses (in Linux for exmaple) /dev/urandom which is generally considered cryptographically secure *, except in some cases (e.g. while booting) you get an estimated amount of entropy (you can't actually measure it) that you hope it is a little bit less than your theoretical one.

* There is/was an ongoing debate on whether to use /dev/urandom or /dev/random. You can read more here and you can also check SAI Peregrinus' comment bellow.

$\endgroup$
2
  • $\begingroup$ Err, what do you mean "using printable digits to store randomness is a trade-off between storage and readability"? Are you concerned with storage capacity? $\endgroup$
    – Paul Uszak
    Commented May 3, 2022 at 5:31
  • 1
    $\begingroup$ That "ongoing debate" hasn't been a debate for some time now. Current Linux kernels have no difference in behavior between /dev/random and /dev/urandom. They block at boot until the pool is seeded, then don't block afterwards. $\endgroup$ Commented May 5, 2022 at 1:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.