Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Something similar to /dev/urandom with configurable seed?

Tags:

linux

I'm dd'ing from /dev/urandom in order to create files with random contents. This works well, but I would like to be able to reproduce the file contents at some later point by running the PRNG again with the same seed. Is there any seedable PRNG which exposes a character device?

I'm using recent Linux 3.X kernels.

like image 887
Jonatan Avatar asked Oct 21 '22 04:10

Jonatan


2 Answers

/dev/urandom is designed to be as unpredictable as possible. It sounds like you want a more conventional seeded pseudorandom number generator.

Here's one I just wrote in C:

#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    char *endptr;
    unsigned long int seed;

    if (argc != 2 || *argv[1] == '\0') {
        fprintf(stderr, "usage: %s seed\n", argv[0]);
        return EXIT_FAILURE;
    }
    errno = 0;
    seed = strtoul(argv[1], &endptr, 0);
    if (errno != 0 || *endptr != '\0' || seed > UINT_MAX) {
        fprintf(stderr, "%s: invalid seed\n", argv[0]);
        return EXIT_FAILURE;
    }
    srandom((unsigned int) seed);

    while (1) {
        int i;
        long int randomnum = random();
        for (i = 0; i < sizeof randomnum; i++) {
            if (putchar((randomnum >> (i * CHAR_BIT)) & UCHAR_MAX) == EOF) {
                return EXIT_SUCCESS;
            }
        }
    }
}

This is a program, not a device file, but its output is the same format as you'd get from /dev/urandom. You can pipe the output from it into dd and omit if.

If you need to come up with a truly random seed to supply to the program, you can get one in bash from /dev/urandom like this:

seed=$(od -vAn -N4 -tu4 </dev/urandom)

Replace 4 with whatever sizeof(unsigned int) is on your machine (it's probably 4).

like image 127
Taymon Avatar answered Nov 03 '22 23:11

Taymon


Python 3.9 random.randbytes + random.seed

I've learnt to stop fighting what Bash can't do and just go with the flow:

randbytes() (
  python -c 'import random;import sys;random.seed(int(sys.argv[1]));sys.stdout.buffer.write(random.randbytes(int(sys.argv[2])))' "$@"
)

Usage:

randbytes <seed> <nbytes>

e.g.:

randbytes 0 8 | hd

always outputs 8 identical pseudo-random bytes with seed 0:

00000000  cd 07 2c d8 be 6f 9f 62                           |..,..o.b|
00000008

Readable multiline version at: Generating random string of seedable data

On my Lenovo ThinkPad P51, I can dump 100 million bytes in ramfs in 0.5s. however, if I try to dump 1 billion it blows up with:

Python int too large to convert to C int

so it is something to keep in mind.

For comparison:

time sudo dd if=/dev/urandom of=ramfs/test bs=4k count=24414

took 2.5s, so it is slower, which is not surprising as it is a more random source, while the Python generator is deterministic and appears to be written in C.

Tested on Ubuntu 20.10, Linux kernel 5.8.0.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!