I want to generate 6 random words using Wiktionary and random numbers from /dev/random. I'll get a random number with /dev/random and then use the word from that index.

I know /dev/random should be used to generate random keys, but if it's deterministic what prevents somebody from knowing the future bytes from the old ones? That would be a problem if, for example, an attacker knows one word of my random word list.

I am aware that the LNRG changed recently in 5.18. I'm using this version.

2 Answers 2


The CSPRNG used in Linux is effectively the ChaCha stream cipher. Like all cryptographically secure PRNGs, it passes the next bit test, which says that given an arbitrary amount of output from the PRNG, an attacker cannot predict the next bit with a probability substantially greater than 0.5. This test covers all possible ways of guessing: statistical analysis of the stream, intensive analysis of the algorithm, or any other means.

ChaCha uses a permutation and combines the original input, which contains the key and nonce, with the result of the permutation to prevent inverting the operation. This approach is also used by SHA-2 and BLAKE2 (although with different inputs) to great success. We presently believe that an attacker cannot distinguish the output of ChaCha20 from random, and the best known attacks are on 7 of 20 rounds. Because the ChaCha output isn't invertible and there's no way to distinguish it from random, we don't believe there's any way to guess future outputs that's better than chance. (Technically, we believe the attacker could guess by brute force, but the 2^-256 advantage is considered to be negligible here.)

In addition, recent versions of the Linux CSPRNG also use fast key erasure. That means that once random bytes are generated, additional CSPRNG output is used to change the key used, so that if the kernel's internal state is leaked, previous outputs are not compromised.

If your question is about the seeding of the CSPRNG, that's essentially done by hashing inputs with the keyed hash function BLAKE2s to produce a key for ChaCha. These inputs are things like interrupt timings, which each contain a small amount of entropy, and when 256 bits of entropy are believed to have been collected, the key is generated and ChaCha is seeded. Because BLAKE2s in this case is believed to be a pseudorandom function, this is a secure way of distilling the entropy into a suitable key for ChaCha.

If you're interested in how ChaCha works, the Wikipedia article is actually quite good. The algorithm is really quite simple and could be implemented from memory, The code is relatively easy to follow and demonstrates the main idea. Note that even though it looks very simple, substantial cryptanalysis has gone into ensuring that it's secure, and producing an algorithm that is both secure and simple isn't easy.

  • For those looking for more details, the the source code is documented in its comments.
    – A. Hersean
    Aug 3, 2022 at 7:46
  • ChaCha "is really quite simple and could be implemented from memory"... It's a beautiful algorithm, simple to understand and to implement. I recommend reading the Wikipedia entry, it's concise and informative!
    – ThoriumBR
    Aug 3, 2022 at 10:32
  • @A.Hersean There's also the wonderful LRNG document which is, by far, the most detailed and up-to-date analysis and description of the Linux random driver.
    – forest
    Aug 5, 2022 at 0:55
  • @forest I read it before. It's sadly outdated. The Linux CSPRNG is currently being rewritten (upgraded) by Jason A. Donenfeld (the author of Wireguard), one small patch at a time.
    – A. Hersean
    Aug 5, 2022 at 8:16

To understand this better, let us look at a very simple, self-made RNG algortithm. It has a counter that starts at 0 and with each call to the rng, it feeds the current counter into a SHA-256 function, then takes the last 32 bits and converts them to an integer and returns them. Finally, the counter is increased by 1. As pseudo-code, it would look like this:

counter = 0

fn getRandom()
    return SHA-256(counter++) ^ 0xFFFFFFFF;

Calling this RNG would yield the following results:


As you can see, these are rather difficult to predict. By merely looking at the output, it doesn't seem easily plausible to guess the next number. To prove my point, I will set the counter to a random 32-bit state and generate 3 more numbers.


Good luck finding the next number!

This demonstration aside, a random number generator is judged by its ability to be unpredictable to an attacker, even when they are able to observe a large amount of random data generated. In an ideal RNG, an attacker has exactly a 50% chance of guessing the next bit correctly, and when it comes to /dev/random, the attacker's chance is not much better.

In practice, how random data is used by an application is often way more relevant than the RNG being used.

  • 2
    Anecdotal evidence is not a proof or demonstration.
    – A. Hersean
    Aug 3, 2022 at 7:40
  • 2
    It's pretty trivial to find the next number: just bruteforce counter until you get the current output and you can determine all past and future outputs.
    – ThoriumBR
    Aug 3, 2022 at 10:35
  • 4
    The next number in the sequence is 750155109. As @ThoriumBR points out, this is not hard to crack. Here is the python script that I used to crack the counter value: pastebin.com/mAN3UzmF. This took less than 10 minutes to run on my ancient laptop. And, here is the script that I used to get the next value in the sequence, once the counter was cracked: pastebin.com/MbqXkRGg.
    – mti2935
    Aug 3, 2022 at 15:10
  • 2
    Notwithstanding, even if you make the counter space much larger (e.g. 256 bits, instead of just 32) to thwart a brute force attack - then this leads to another problem: how do you choose a random seed for the counter to start at? As you can see, this RNG needs another RNG to seed the counter, so it becomes and chicken-and-egg problem. What this illustrates is how deceptively difficult it is to build a true cryptographically secure pseudo random number generator (CSPRNG), as @schroeder alludes to in his comment.
    – mti2935
    Aug 3, 2022 at 15:21
  • 2
    Apart from all the other problems, your pseudocode uses ^ which is generally used for xor. You probably wanted to use &.
    – nobody
    Aug 3, 2022 at 20:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .