Geração de Números Aleatórios em Hardware (RDRAND/RDSEED)
Um kernel não tem teclado, mouse, ou timing de tráfego de rede algum de onde tirar aleatoriedade da forma que um sistema operacional voltado ao usuário tipicamente faz, o que torna RDRAND e RDSEED as duas instruções das quais a maior parte da geração de números aleatórios em nível de kernel em x86 no fim das contas depende. As duas leem de um circuito de entropia embutido no próprio chip da CPU, mas respondem perguntas diferentes: RDRAND retorna uma saída já passada por um gerador criptográfico, enquanto RDSEED retorna o material mais bruto do qual esse mesmo gerador seria semeado.
RDRAND: um fluxo semeado e condicionado
Seção intitulada “RDRAND: um fluxo semeado e condicionado”RDRAND não lê ruído físico bruto diretamente; ele lê a saída de um deterministic random bit generator (DRBG), um algoritmo criptográfico que é ele mesmo continuamente resemeado a partir de uma fonte de entropia física embutida no chip (ruído térmico amostrado por um circuito dedicado, nas implementações da Intel e da AMD). Esse design em dois estágios existe porque uma fonte de entropia física sozinha é comparativamente lenta e sua saída bruta pode carregar pequenos vieses estatísticos; passá-la por um DRBG produz saída numa taxa bem mais alta que também passa limpamente em testes estatísticos padrão de aleatoriedade, ao custo de essa saída ser computacionalmente derivada em vez de ruído físico em si.
retry: rdrand eax jnc retry ; CF limpa significa que o valor não estava pronto; tenta de novoRDRAND sinaliza sucesso através da carry flag em vez de um valor de retorno: CF definida significa que EAX (ou o registrador equivalente de 16/64 bits) contém um valor aleatório válido, CF limpa significa que o gerador interno não estava pronto e a instrução não produziu nada utilizável, exigindo uma nova tentativa. Isso pode falhar por mais do que um instante sob carga sustentada de muitos núcleos requisitando valores simultaneamente, motivo pelo qual código de produção tenta de novo um número limitado de vezes, comumente dez, em vez de fazer loop incondicionalmente, tratando falha repetida como um sinal para recorrer a uma fonte de entropia diferente em vez de travar indefinidamente.
RDSEED: a alternativa mais bruta e mais lenta
Seção intitulada “RDSEED: a alternativa mais bruta e mais lenta”RDSEED expõe entropia mais próxima da própria fonte física, pensada especificamente para semear um gerador aleatório separado do lado de software em vez de para consumo direto de alto volume da forma que a saída do RDRAND é. Compartilha o sinal de sucesso via carry flag e a convenção de chamada geral do RDRAND, mas puxa de um caminho consideravelmente mais limitado em taxa, já que a fonte de entropia física por trás das duas instruções só consegue produzir aleatoriedade física genuinamente nova até certa velocidade, e o RDSEED insiste nesse suprimento mais fresco e menos processado em vez da saída amplificada do DRBG.
retry: rdseed eax jnc retryUm kernel implementando seu próprio gerador aleatório criptográfico (em vez de depender da saída do RDRAND diretamente para todo consumidor) tipicamente usa RDSEED uma vez, no boot, para semear esse gerador, depois atende requisições comuns a partir do próprio gerador de software, reservando a saída mais lenta e mais limitada em taxa do RDSEED para o trabalho específico de semear em vez de para todo valor aleatório individual que o kernel algum dia precise.
Checando disponibilidade primeiro
Seção intitulada “Checando disponibilidade primeiro”Nenhuma das duas instruções é garantida presente em toda CPU x86 capaz de rodar um kernel moderno: o suporte a RDRAND é reportado pela leaf 1 do CPUID, bit 30 de ECX, e o suporte a RDSEED separadamente pela leaf 7 (subleaf 0), bit 18 de EBX, dois bits independentes já que uma CPU pode em princípio implementar um sem o outro. Executar qualquer uma das duas instruções em hardware que não a suporta levanta #UD, a mesma falha de opcode inválido que CPUID já cobre como a razão geral para checar disponibilidade de recurso antes de usar, o que é o que torna checar esses dois bits especificamente, em vez de presumir suporte universal em x86, um requisito rígido em vez de uma cautela defensiva.
int has_rdrand(void) { uint32_t eax, ebx, ecx, edx; __asm__ volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1)); return (ecx >> 30) & 1;}Notas de implementação
Seção intitulada “Notas de implementação”Nenhuma das duas instruções deveria ser confiada como única fonte de entropia de um kernel sem ao menos algum fallback: o modelo de CPU de uma máquina virtual pode não expor nenhum dos dois bits mesmo quando o hardware físico por baixo os tem, e depender exclusivamente de RDRAND/RDSEED sem caminho de entropia algum a mais significa que um kernel silenciosamente não tem aleatoriedade nenhuma no momento em que roda em algum lugar que não os oferece, exatamente o que a checagem de disponibilidade acima existe para capturar antes que essa lacuna se torne um problema de segurança em vez de um erro de build. Um kernel visando aleatoriedade genuinamente forte comumente combina entropia de hardware com outras fontes ainda disponíveis num contexto de kernel, jitter de timing entre interrupções, por exemplo, misturadas através de seu próprio gerador de software em vez de confiar em qualquer fonte única, hardware incluído, ser suficiente isoladamente.
Referências
Seção intitulada “Referências”- ^ Intel, Digital Random Number Generator (DRNG) Software Implementation Guide: a referência do fabricante para o comportamento de RDRAND/RDSEED, orientação de retry, e a relação DRBG/fonte de entropia descrita acima.
Ver também
Seção intitulada “Ver também”- CPUID: a instrução e os bits de recurso que reportam se RDRAND/RDSEED estão disponíveis.
- Mitigações de Segurança: ASLR, a mitigação cuja imprevisibilidade real depende diretamente dessa entropia ser genuína.