Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

/dev/random returning always the same sequence

Tags:

c

linux

random

I was going to use /dev/random output as a seed for key generation for openssl, then I wrote this small program just to check what I was going to do:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#define LEN 128

void uc2hex(char* hex, unsigned char* uc, unsigned short uc_len)
{
    FILE* bp=fmemopen(hex,2*uc_len+1,"w");
    unsigned short i;
    for(i=0;i<uc_len;i++)
    {
        fprintf(bp,"%02x",uc[i]);
        //printf("%02x\n",uc[i]);
        //fprintf(bp,"%d-",i);
    }
    fprintf(bp,"%c",'\0');
    fclose(bp);
}

int main()
{
    unsigned char buf[LEN];
    char str[2*LEN+1];
    int fd=open("/dev/random",O_RDONLY);
    read(fd,buf,LEN);
    uc2hex(str,buf,LEN);
    printf("%s\n",str);
    close(fd);
    return 0;
}

I ran the program some one or two times and everything seemed to work fine, but then I ran it four times again in short sequence and this is the output:

[walter@eM350 ~]$ ./random 
0ee08c942ddf901af1278ba8f335b5df8db7cf18e5de2a67ac200f320a7a20e84866f533667a7e66a4572b3bf83d458e6f71f325783f2e3f921868328051f8f296800352cabeaf00000000000000000001000000000000005d08400000000000c080300e00000000000000000000000010084000000000000006400000000000
[walter@eM350 ~]$ ./random 
1f69a0b931c16f796bbb1345b3f58f17f74e3df600000000bb03400000000000ffffffff00000000880e648aff7f0000a88103b4d67f000000305cb4d67f000030415fb4d67f0000000000000000000001000000000000005d08400000000000c080300e00000000000000000000000010084000000000000006400000000000
[walter@eM350 ~]$ ./random 
4e8a1715238644a840eb66d9ff7f00002e4e3df600000000bb03400000000000ffffffff00000000a8ec66d9ff7f0000a871a37ad97f00000020fc7ad97f00003031ff7ad97f0000000000000000000001000000000000005d08400000000000c080300e00000000000000000000000010084000000000000006400000000000
[walter@eM350 ~]$ ./random 
598c57563e8951e6f0173f0cff7f00002e4e3df600000000bb03400000000000ffffffff0000000058193f0cff7f0000a8e1cbda257f0000009024db257f000030a127db257f0000000000000000000001000000000000005d08400000000000c080300e00000000000000000000000010084000000000000006400000000000

Theese seem to me everything but 128-bytes random strings, since they are mostly the same. Then, excluding the possibility that the NSA tampered with the linux kernel random-number-generator, I could only guess that this has something to do with the available entropy in my machine, which gets exhausted when I ask too many bytes in sequence. My questions are: 1) Is this guess correct? 2) Assuming 1) is correct, how do I know whether there is enough entropy to generate real random bytes sequence?

like image 435
woggioni Avatar asked Oct 09 '13 08:10

woggioni


2 Answers

As other people have suggested, you need to check the return value for the number of bytes read.

If /dev/random did not have sufficent bytes available, it will have returned fewer.

However, you still use the expected length in your following calls:

uc2hex(str,buf,LEN);
printf("%s\n",str);

So, you are converting and printing uninitialised memory. I am not surprised that subsequent calls then show the same value - since if that memory hasn't been written to between calls, the value wont change.

EDIT: Better would be:

int nBytes=read(fd,buf,LEN);
uc2hex(str,buf,nBytes);
printf("%s\n",str);
like image 25
mjs Avatar answered Oct 07 '22 05:10

mjs


From the man page for read:

Upon successful completion, read(), readv(), and pread() return the number of bytes actually read and placed in the buffer. The system guarantees to read the number of bytes requested if the descriptor references a normal file that has that many bytes left before the end-of-file, but in no other case.

Bottom line: check the return value from read and see how many bytes you actually read - there may not have been enough entropy to generate the number of bytes you requested.

int len = read(fd, buf, LEN);
printf("read() returned %d bytes: ", len);
if (len > 0)
{
    uc2hex(str, buf, len);
    printf("%s\n", str);
}

Test:

$ ./a.out 
read() returned 16 bytes: c3d5f6a8ee11ddc16f00a0dea4ef237a
$ ./a.out
read() returned 8 bytes: 24e23c57852a36bb
$ ./a.out 
read() returned 16 bytes: 4ead04d1eedb54ee99ab1b25a41e735b
$
like image 133
Paul R Avatar answered Oct 07 '22 05:10

Paul R