A leitura de / dev / random não produz nenhum dado

19

Costumo usar o comando

cat /dev/urandom | strings --bytes 1 | tr -d '\n\t ' | head --bytes 32

para gerar senhas pseudo-aleatórias. Isso não funciona com /dev/random .

Especificamente

  • cat /dev/urandom | strings --bytes 1 | tr -d '\n\t ' produz saída
  • cat /dev/random | strings --bytes 1 produz saída
  • cat /dev/random | strings --bytes 1 | tr -d '\n\t ' não produz saída

NB: Ao usar /dev/random , você pode ter que mexer o mouse ou pressionar as teclas (por exemplo, ctrl, shift, etc.) para gerar entropia.

Por que o último exemplo não funciona? O tr tem algum tipo de buffer interno grande que /dev/urandom preenche rapidamente, mas /dev/random não?

P.S. Estou usando o CentOS 6.5

cat /proc/version
Linux version 2.6.32-431.3.1.el6.x86_64 ([email protected]) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) ) #1 SMP Fri Jan 3 21:39:27 UTC 2014
    
por Aaron J Lang 12.02.2014 / 13:36

3 respostas

26

Eventualmente.

Em:

cat /dev/random | strings --bytes 1 | tr -d '\n\t '

cat nunca será compensado, mas é supérfluo de qualquer forma, pois não há nada para concatenar aqui.

< /dev/random strings --bytes 1 | tr -d '\n\t '

strings , já que sua saída não é mais um terminal armazenará em buffer sua saída por blocos (de algo como 4 ou 8kB) ao contrário de linhas quando a saída vai para um terminal. / p>

Portanto, ele só começará a gravar para stdout quando tiver acumulado 4kB de caracteres para a saída, o que em /dev/random demorará um pouco.

A saída

tr vai para um terminal (se você estiver executando isso em um prompt do shell em um terminal), então ele armazenará em buffer sua linha de saída. Como você está removendo o \n , ele nunca terá uma linha completa para gravar, então, em vez disso, ele gravará assim que um bloco inteiro for acumulado (como quando a saída não vai para um terminal). / p>

Portanto, tr provavelmente não escreverá nada até que strings tenha lido o suficiente de /dev/random para escrever 8kB (2 blocos possivelmente muito mais) de dados (já que o primeiro bloco provavelmente conterá alguma nova linha ou caracteres de tabulação ou espaço).

Neste sistema que estou experimentando, posso obter uma média de 3 bytes por segundo de /dev/random (em oposição a 12MiB em /dev/urandom ), portanto, no melhor cenário possível (os primeiros 4096 bytes de /dev/random são todos imprimíveis), estamos falando 22 minutos antes de o tr iniciar a saída de qualquer coisa. Mas é mais provável que sejam horas (em um teste rápido, posso ver strings escrevendo um bloco a cada 1 ou 2 blocos lidos, e os blocos de saída contêm cerca de 30% dos caracteres de nova linha, então eu esperaria precisa ler pelo menos 3 blocos antes que tr tenha 4096 caracteres para a saída).

Para evitar isso, você pode fazer:

< /dev/random stdbuf -o0 strings --bytes 1 | stdbuf -o0 tr -d '\n\t '

stdbuf é um comando GNU (também encontrado em alguns BSDs) que altera o buffer stdio de comandos através de um truque LD_PRELOAD.

Observe que, em vez de strings , você pode usar tr -cd '[:graph:]' , que também excluirá tabulação, nova linha e espaço.

Você pode querer corrigir a localidade para C para evitar possíveis surpresas futuras com caracteres UTF-8.

    
por 12.02.2014 / 14:05
4

A geração de números aleatórios para muitas aplicações de segurança requer entropia suficiente - a entropia mede quão imprevisível é a aleatoriedade. Um processador determinístico não pode gerar entropia, portanto a entropia deve vir de fora - seja de um componente de hardware com comportamento não determinístico, seja de outros fatores que são difíceis de reproduzir, como o tempo de ação do usuário entra). Uma vez que a entropia suficiente esteja disponível, a criptografia pode ser usada para gerar um fluxo praticamente ilimitado de números aleatórios.

O Linux funciona acumulando entropia em um conjunto e, em seguida, usando criptografia para produzir números aleatórios aceitáveis, tanto em /dev/random como em /dev/urandom . A diferença é que /dev/random aplica um cálculo de entropia extremamente conservador que reduz a estimativa da entropia no conjunto para cada byte gerado, enquanto /dev/urandom não se preocupa com a quantidade de entropia no conjunto.

Se a estimativa de entropia no conjunto for muito baixa, /dev/random bloqueará até que mais entropia possa ser acumulada. Isso pode prejudicar gravemente a taxa na qual /dev/random pode produzir saída. É isso que você está observando aqui. Não tem nada a ver com tr ; mas strings lê a saída com o buffer, então ele precisa ler um buffer completo (alguns KB) de /dev/random apenas para produzir pelo menos um byte de entrada.

/dev/urandom é perfeitamente aceitável para gerar uma chave criptográfica , porque a entropia de fato não diminui de maneira perceptível. (Se você mantiver sua máquina rodando por mais tempo do que o universo já existia, você não pode negligenciar essas considerações, mas caso contrário, você é bom.) Há apenas um caso em que /dev/urandom não é bom, que é em um recém-instalado sistema que ainda não teve tempo de gerar entropia ou um sistema recém-inicializado que inicializa a partir de mídia somente leitura.

Eliminar strings da sua cadeia de inicialização provavelmente acelerará seu processo. Abaixo de tr filtrará os caracteres não imprimíveis:

</dev/random LC_ALL=C tr -dc '!-~'

Mas você pode usar /dev/urandom here , contanto que você tome cuidado para não gerar senhas em um sistema que não tenha tido tempo suficiente para acumular entropia suficiente. Você pode verificar o nível do pool de entropia do Linux em /proc/sys/kernel/random/entropy_avail (se você usar /dev/random , a figura neste arquivo será conservadora, possivelmente muito).

    
por 13.02.2014 / 00:41
1

Você deve usar /dev/urandom para obter números aleatórios de alta qualidade (pseudo) e /dev/random apenas quando precisar de números aleatórios que sejam realmente imprevisíveis. Um invasor abaixo dos recursos da NSA terá um tempo muito muito para quebrar /dev/urandom (e não se esqueça da criptografia da mangueira de borracha ). O kernel preenche um buffer com bytes "realmente aleatórios", é isso que o /dev/random fornece. Infelizmente, a taxa em que são gerados é baixa, por isso, ler muito a partir de /dev/random irá parar de esperar pela aleatoriedade.

Você pode usar o random.org ou seu gerador de senha , ou um dos muitos, muitos geradores de senha aleatórios que estão flutuando, dê uma olhada, por exemplo, esta página para um poucas dicas de linha de comando (não que eu recomende todas elas, mas elas devem lhe dar idéias), ou você poderia usar algo como mkpasswd(1) (aqui no Fedora 19 parte de expect-5.45-8.fc19.x86_64 ).

    
por 13.02.2014 / 00:23

Tags