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.