2013-10-09 12 views
6

Stavo per usare/dev/uscita casuale come un seme per la generazione di chiavi per openssl, poi ho scritto questo piccolo programma solo per controllare quello che stavo per fare:/dev/random tornando sempre la stessa sequenza

#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; 
} 

ho eseguito il programma di alcuni una o due volte e tutto sembrava funzionare bene, ma poi ho eseguito quattro volte di nuovo in breve sequenza, e questo è l'output:

[[email protected] ~]$ ./random 
0ee08c942ddf901af1278ba8f335b5df8db7cf18e5de2a67ac200f320a7a20e84866f533667a7e66a4572b3bf83d458e6f71f325783f2e3f921868328051f8f296800352cabeaf00000000000000000001000000000000005d08400000000000c080300e00000000000000000000000010084000000000000006400000000000 
[[email protected] ~]$ ./random 
1f69a0b931c16f796bbb1345b3f58f17f74e3df600000000bb03400000000000ffffffff00000000880e648aff7f0000a88103b4d67f000000305cb4d67f000030415fb4d67f0000000000000000000001000000000000005d08400000000000c080300e00000000000000000000000010084000000000000006400000000000 
[[email protected] ~]$ ./random 
4e8a1715238644a840eb66d9ff7f00002e4e3df600000000bb03400000000000ffffffff00000000a8ec66d9ff7f0000a871a37ad97f00000020fc7ad97f00003031ff7ad97f0000000000000000000001000000000000005d08400000000000c080300e00000000000000000000000010084000000000000006400000000000 
[[email protected] ~]$ ./random 
598c57563e8951e6f0173f0cff7f00002e4e3df600000000bb03400000000000ffffffff0000000058193f0cff7f0000a8e1cbda257f0000009024db257f000030a127db257f0000000000000000000001000000000000005d08400000000000c080300e00000000000000000000000010084000000000000006400000000000 

Theese mi sembrano tutto tranne che Stringhe casuali da 128 byte, poiché sono per lo più le stesse. Quindi, escludendo la possibilità che l'NSA abbia manomesso il generatore di numeri casuali del kernel Linux, ho potuto solo supporre che questo abbia qualcosa a che fare con l'entropia disponibile nella mia macchina, che si esaurisce quando chiedo troppi byte in sequenza. Le mie domande sono: 1) Questa ipotesi è corretta? 2) Supponendo che 1) sia corretto, come faccio a sapere se c'è abbastanza entropia per generare una sequenza di byte casuali reali?

+4

Usa '/ dev/urandom'. La casualità reale è scarsa e non dovrebbe essere sprecata in questo modo. –

+0

@KerrekSB Definire "sprecato". Se leggo da/dev/urandom', anche il conteggio entropico viene diminuito. La differenza è che 'urandom' non si ferma se il conteggio ha raggiunto 0. – glglgl

+1

@glglgl: la differenza è che' urandom' usa la casualità vera per seminare la pseudo-casualità. È vero che ottieni una casualità migliore se ne è disponibile più, ma la pseudo-casualità è almeno altrettanto buona di quella che può essere data alla casualità disponibile. –

risposta

13

Dalla pagina man di lettura:

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.

Linea di fondo: controllare il valore restituito da read e vedere quanti byte effettivamente letto - non ci può essere stato abbastanza entropia per generare il numero di byte richiesti

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

prova:

$ ./a.out 
read() returned 16 bytes: c3d5f6a8ee11ddc16f00a0dea4ef237a 
$ ./a.out 
read() returned 8 bytes: 24e23c57852a36bb 
$ ./a.out 
read() returned 16 bytes: 4ead04d1eedb54ee99ab1b25a41e735b 
$ 
+1

Ovviamente ... Sono stato scacciato dal fatto che l'OP non ha assistito apertamente * bloccando * la chiamata. Immagino che una piccola quantità di casualità naturale si sia verificata tra una chiamata e l'altra. Buona chiamata e sicuramente +1. –

2

Come altre persone hanno suggerito, è necessario controllare il valore di ritorno per il numero di byte letti.

Se/dev/random non ha sufficienti byte disponibili, ne verrà restituito un numero inferiore.

Tuttavia, si utilizza ancora la lunghezza previsto nelle seguenti chiamate:

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

Quindi, si sta convertendo e la stampa della memoria Non inizializzato. Non mi sorprende che le chiamate successive mostrino quindi lo stesso valore - dal momento che se quella memoria non è stata scritta tra le chiamate, il valore non cambierà.

EDIT: Meglio sarebbe:

int nBytes=read(fd,buf,LEN); 
uc2hex(str,buf,nBytes); 
printf("%s\n",str); 
Problemi correlati