Por que o dd de / dev / random fornece tamanhos de arquivo diferentes?

24

Estou executando o seguinte comando em um sistema Ubuntu:

dd if=/dev/random of=rand bs=1K count=2

No entanto, toda vez que eu executo, acabo com um arquivo de tamanho diferente. Por que é isso? Como posso gerar um arquivo de um determinado tamanho preenchido com dados aleatórios?

    
por Daniel 28.02.2012 / 21:59

4 respostas

29

Você está observando uma combinação do comportamento peculiar de dd com o comportamento peculiar do /dev/random do Linux. Ambos, a propósito, raramente são a ferramenta certa para o trabalho.

O /dev/random do Linux retorna dados com moderação. Baseia-se no pressuposto de que a entropia no gerador de números pseudo-aleatórios se extingue a uma taxa muito rápida. Como a coleta de nova entropia é lenta, /dev/random geralmente desiste apenas alguns bytes de cada vez.

dd é um programa antigo e mal-humorado inicialmente destinado a operar em dispositivos de fita. Quando você diz para ler um bloco de 1kB, ele tenta ler um bloco. Se a leitura retornar menos de 1024 bytes, difícil, é tudo que você recebe. Portanto, dd if=/dev/random bs=1K count=2 faz duas chamadas read(2) . Como ele está lendo /dev/random , as duas chamadas read normalmente retornam apenas alguns bytes, em número variável, dependendo da entropia disponível. Veja também Quando o dd é adequado para copiar dados? (ou, quando são lidos () e escritos () parciais)

A menos que esteja projetando um instalador ou clonador de sistema operacional, você nunca deve usar /dev/random no Linux, sempre /dev/urandom . A página urandom man é um tanto enganadora; /dev/urandom é de fato adequado para criptografia, até mesmo para gerar chaves de longa duração. A única restrição com /dev/urandom é que ela deve ser fornecida com entropia suficiente; As distribuições Linux normalmente salvam a entropia entre as reinicializações, portanto, a única vez em que você pode não ter entropia suficiente é em uma instalação nova. A entropia não se desgasta em termos práticos. Para obter mais informações, leia É um rand de / dev / urandom secure para uma chave de login? e Feeding / dev / pool de entropia aleatória? .

A maioria dos usos de dd é melhor expressa com ferramentas como head ou tail . Se você quiser 2kB de bytes aleatórios, execute

head -c 2k </dev/urandom >rand

Com kernels mais antigos do Linux, você pode se safar com

dd if=/dev/urandom of=rand bs=1k count=2

porque /dev/urandom felizmente retornou quantos bytes foram solicitados. Mas isso não é mais verdade desde o kernel 3.16, está agora limitado a 32MB .

Em geral, quando você precisa usar dd para extrair um número fixo de bytes e sua entrada não vem de um arquivo ou dispositivo de bloco comum, você precisa ler byte por byte: dd bs=1 count=2048 .

    
por 29.02.2012 / 02:57
11

De man 4 random em uma caixa RHEL 5:

When read, the /dev/random device will only return random bytes within the estimated number of bits of noise in the entropy pool.

Eu recebo arquivos de tamanho 213 bytes nessa máquina. De volta ao homem 4 aleatório:

When read, /dev/urandom device will return as many bytes as are requested.

Eu recebo 2048 bytes de cada invocação de dd if=/dev/urandom of=rand bs=1K count=2

Concluo que a diferença se deve a quanta entropia sua máquina gera entre invocações de dd if=/dev/random ...

    
por 28.02.2012 / 22:10
5

Por que dd solta dados? ... Gilles colocou esta questão envolvente sobre dd :
Quando o dd é adequado para copiar dados? (ou, quando são lidos () e escritos () parciais)
Aqui está um trecho dessa pergunta:

* ... não é difícil colocar dd em falta; por exemplo, tente este código: **
yes | dd of=out bs=1024k count=10
e verifique o tamanho do arquivo de saída (é provável que seja bem menor que 10MB).

Além do meu comentário (no final da sua pergunta), algo assim é interessante assistir ... Ele pega seus bytes no arquivo $trnd . Eu escolhi semi-arbitrariamente bs = 8

Mova o seu rato e veja-o acelerar.
Com o meu computador ocioso (AFK e sem atividade de rede), e depois de esgotar o pool de entropia, demorou 2 horas 12 minutos para coletar apenas 1192 bytes, ponto em que eu cancelei.

Então, comigo movendo o mouse continuamente, demorou relativamente 1 minuto 15 segundos para coletar o mesmo número de bytes.

Isso mostra claramente que coletar entropia não é baseado na velocidade da CPU, mas sim em eventos aleatórios , e que meu sistema Ubuntu usa o mouse como um dos significativos fatores aleatórios.

get=2048
trnd=/tmp/$USER.rnd; >"$trnd"
while (( $(wc -c <"$trnd") < $get )) ;do
    dd if=/dev/random bs=8 count=1 2>/dev/null >>"$trnd"
    echo -n "itt: $((i+=1))  ct: "; wc -c <"$trnd"
done
truncate -s $get "$trnd"
echo -e "\nfinal count: "; wc -c <"$trnd"
    
por 28.02.2012 / 22:44
1

dd é projetado para bloqueio - geralmente é a melhor ferramenta à sua disposição para leitura de entradas de tamanho variável se você precisar disso imediatamente porque dd não fará buffer de leituras atuais em algum futuro write() (a menos que você configure explicitamente dessa forma com obs maior que ibs) , mas em vez disso write() tudo o que lê assim que read() s it (e, opcionalmente, processa-o) .

Aqui estão algumas definições importantes:

  • ibs= expr
    • Especifique o tamanho do bloco de entrada, em bytes, por expr (o padrão é 512) .
  • obs= expr
    • Especifique o tamanho do bloco de saída, em bytes, por expr (o padrão é 512) .
  • bs= expr
    • Defina os tamanhos dos blocos de entrada e saída como expr bytes, substituindo ibs= e obs= . Se nenhuma conversão diferente de sync , noerror e notrunc for especificada, cada bloco de entrada será copiado para a saída como um único bloco sem agregar blocos curtos.

Veja, quando ibs e obs são definidos juntos como bs , então ibs tem precedência - mas, caso contrário, se você for específico, obs ou cbs será.

Aqui está um exemplo em que ibs é o mais importante. Você pode fazer algo assim se quiser acompanhar o quanto o pool /dev/random será preenchido ...

dd "ibs=$size" conv=sync "count=$lmt" \ 
    if=/dev/random of="$somefile"

Contanto que o destino de if= seja legível, o sempre resultará no mesmo arquivo de saída de tamanho, porque dd irá sync hronize bloqueará a leitura em nulos . Em outras palavras, se dd read() s para um bloco de entrada de $((size=10)) $((count=5)) times e o read() arquivo retornar 2 bytes, então 8 bytes, depois 12 bytes, depois 2 bytes e, em seguida, 4 bytes , dd irá escrever para o seu outfile algo como

 2 read bytes 8NULs \
 8 read bytes 2NULs \
10 read bytes 0NULs \
 4 read bytes 6NULs \
 4 read bytes 6NULs

... porque dd , por padrão, não atrasa. Então, se você precisa acompanhar in-stream e delimitar as gravações de algum outro processo, dd é a ferramenta para você.

Se você está apenas escrevendo uma quantidade de dados em um arquivo regular, contrariamente a outras declarações feitas aqui, você também pode usar dd para isso - e com bastante facilidade - mas você precisará de mais de um e um fator de bloqueio confiável .

Por exemplo, se você fez:

{   dd ibs="$size" obs="${size}x$block_factor" |
    dd bs="${size}x$blockfactor" "count=$lmt"
}  <infile >outfile

... o primeiro dd armazenaria em buffer quantos blocos de entrada ibs="$size" fossem necessários para preencher pelo menos um bloco de saída obs="${size}x$block_factor" para cada write() para o canal entre ele e o segundo dd . Isso significa que o segundo dd pode limitar a saída de forma confiável com count="$lmt" , porque todos os write() s fabricados pela primeira vez corresponderão a seu tamanho de bloco de i / o - independentemente de quantos read() s o primeiro dd deve fazer para fazer isso.

E isso é como você pode usar dd para ler com confiança pipes ou outros tipos de arquivos especiais - com um pouco de matemática.

    
por 23.03.2015 / 23:18

Tags