Pergunta

Se você quiser um criptograficamente forte de números aleatórios em Java, você usa SecureRandom. Infelizmente, SecureRandom pode ser muito lento. Se ele usa /dev/random no Linux, ele pode bloquear de espera para entropia suficiente para construir. Como evitar a penalidade de desempenho?

Alguém já usou Uncommon Maths como uma solução para este problema?

Alguém pode confirmar que esse problema de desempenho foi resolvido no JDK 6?

Foi útil?

Solução

Se você quiser verdadeiros dados aleatórios, então, infelizmente, você tem que esperar por isso. Isto inclui a semente para um PRNG SecureRandom. Incomum Matemática não pode recolher os verdadeiros dados aleatórios mais rápido do que SecureRandom, embora possa se conectar à internet para download de dados de sementes a partir de um determinado site. Meu palpite é que isso é pouco provável que seja mais rápido do que /dev/random onde que está disponível.

Se você quiser um PRNG, fazer algo como isto:

SecureRandom.getInstance("SHA1PRNG");

O que cordas são suportados depende do provedor SecureRandom SPI, mas você pode enumerá-los usando Security.getProviders() e Provider.getService().

Sun gosta de SHA1PRNG, por isso é amplamente disponível. Não é especialmente rápido quanto PRNGs ir, mas PRNGs será apenas mastigando números, não de bloqueio para medição física de entropia.

A exceção é que, se você não chamar setSeed() antes de obter dados, então o PRNG vai semear em si uma vez que a primeira vez que você chamar next() ou nextBytes(). Em geral, ele vai fazer isso usando uma quantidade relativamente pequena de verdadeiros dados aleatórios do sistema. Esta chamada pode bloquear, mas vai fazer a sua fonte de números aleatórios muito mais seguras do que qualquer variante de "haxixe a hora actual juntamente com o PID, adicione 27, e esperar o melhor". Se tudo que você precisa é de números aleatórios para um jogo, embora, ou se você deseja que o fluxo de ser repetível no futuro usando a mesma semente para fins de teste, uma semente de insegurança ainda é útil.

Outras dicas

Você deve ser capaz de selecionar o mais rápido-mas-ligeiramente-menos seguro / dev / urandom no Linux usando:

-Djava.security.egd=file:/dev/urandom

No entanto, isso não funciona com Java 5 e posterior ( Java Bug 6202721 ). A solução alternativa sugerida é a utilização:

-Djava.security.egd=file:/dev/./urandom

(note a /./ adicional)

No Linux, a implementação padrão para SecureRandom é NativePRNG (código-fonte aqui ), que tende a ser muito lento. No Windows, o padrão é SHA1PRNG, que, como outros apontaram que você também pode usar no Linux, se você especificá-lo explicitamente.

difere NativePRNG de SHA1PRNG e Uncommons Matemática AESCounterRNG em que recebe continuamente entropia do sistema operacional (através da leitura de /dev/urandom). Os outros PRNGs não adquirir qualquer entropia adicional após a semeadura.

AESCounterRNG é cerca de 10x mais rápido do que SHA1PRNG, que IIRC é em si duas ou três vezes mais rápido do que NativePRNG.

Se precisar PRNG um mais rápido que adquire entropia após a inicialização, veja se você pode encontrar uma implementação Java de Fortuna . O PRNG núcleo de uma implementação Fortuna é idêntico ao usado por AESCounterRNG, mas há também um sofisticado sistema de pooling entropia e reseeding automática.

Muitas distribuições Linux (a maioria baseada em Debian) configure OpenJDK para uso /dev/random para a entropia.

/dev/random é, por definição lenta (e pode até mesmo bloquear).

A partir daqui você tem duas opções sobre como desbloqueá-lo:

  1. Melhorar a entropia, ou
  2. Reduzir os requisitos de aleatoriedade.

Opção 1, Melhorar a entropia

Para obter mais entropia em /dev/random, tente o haveged daemon. É um daemon que recolhe continuamente HAVEGE entropia, e trabalha também em um ambiente virtualizado, pois não requer nenhum hardware especial, apenas a própria CPU e um relógio.

No Ubuntu / Debian:

apt-get install haveged
update-rc.d haveged defaults
service haveged start

No RHEL / CentOS:

yum install haveged
systemctl enable haveged
systemctl start haveged

Opção 2. Reduzir os requisitos de aleatoriedade

Se por algum motivo a solução acima não ajuda ou você não se preocupam com criptograficamente forte aleatoriedade, você pode alternar para /dev/urandom vez, o que é garantido que não bloco.

Para fazê-lo globalmente, editar o jre/lib/security/java.security arquivo na sua instalação padrão do Java para uso /dev/urandom (devido a uma outra bug ele precisa ser especificado como /dev/./urandom).

Como esta:

#securerandom.source=file:/dev/random
securerandom.source=file:/dev/./urandom

Em seguida, você nunca vai ter que especificá-lo na linha de comando.


Nota: Se você fizer criptografia, você necessidade boa entropia. Caso em questão - android PRNG questão reduzidas, a garantia de Bitcoin carteiras <. / p>

Eu tive um problema semelhante com chamadas para SecureRandom bloqueando por cerca de 25 segundos de cada vez em um servidor Debian sem cabeça. Eu instalei o daemon haveged para garantir /dev/random é mantido tampo, em servidores sem cabeça você precisa de algo como este para gerar a entropia necessário. As minhas chamadas para SecureRandom agora talvez tomar milissegundos.

Se você quiser aleatoriedade verdadeiramente "criptograficamente forte", então você precisa de uma fonte de entropia forte. /dev/random é lento porque tem que esperar para eventos do sistema para reunir entropia (leituras de disco, pacotes de rede, o movimento do mouse, teclas pressionadas, etc.).

A solução mais rápida é um hardware gerador de números aleatórios. Você já pode ter um built-in para sua placa-mãe; consulte a hw_random documentação para obter instruções sobre como descobrir se você tem isso, e como usá-lo. O pacote rng-ferramentas inclui um daemon que irá alimentar hardware gerado entropia em /dev/random.

Se um HRNG não está disponível em seu sistema, e você está disposto a sacrificar a força entropia para o desempenho, você vai querer semear um bom PRNG com dados de /dev/random, e deixar que o PRNG fazer o grosso do trabalho. Existem vários PRNG está listada na SP800-90 , que são fáceis de implementar.

Eu enfrentei mesmo . Depois de algumas pesquisas no Google com os termos de pesquisa certos, me deparei com este artigo agradável em DigitalOcean .

haveged é uma solução potencial, sem comprometer a segurança.

Eu estou apenas citando a parte relevante do artigo aqui.

Com base no princípio da HAVEGE, e, anteriormente, com base na sua associada biblioteca, haveged permite aleatoriedade geração com base nas variações tempo de execução de código em um processador. Uma vez que é quase impossível para um pedaço de código para tomar ao mesmo tempo exato para executar, mesmo no mesmo ambiente no mesmo hardware, o tempo de execução de uma única ou vários programas deve ser adequado para semear uma fonte aleatória. o sementes de implementação haveged fonte aleatória do seu sistema (normalmente / Dev / random), utilizando diferenças de contador carimbo de tempo do processador (TSC), após a execução de um ciclo repetidamente

Como instalar haveged

Siga as etapas neste artigo. https: // www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged

Eu postei aqui

Use o seguro aleatória como fonte de inicialização para um algoritmo recorrente; você poderia usar, em seguida, um Mersenne twister para o trabalho em massa, em vez de um em UncommonMath, que tem sido em torno de um tempo e provado melhor do que outro PRNG

http://en.wikipedia.org/wiki/Mersenne_twister

Certifique-se de atualizar agora e, em seguida, o aleatório seguro utilizado para a inicialização, por exemplo, você poderia ter um seguro aleatório gerado por cliente, usando um Mersenne twister pseudo gerador aleatório por cliente, obtendo um grau suficientemente elevado de randomização

Usando Java 8, descobri que no Linux chamando SecureRandom.getInstanceStrong() me daria o algoritmo NativePRNGBlocking. Isso muitas vezes bloquear por muitos segundos para gerar alguns bytes de sal.

Mudei para pedir explicitamente NativePRNGNonBlocking vez, e como esperado a partir do nome, ele não é mais bloqueado. Eu não tenho idéia do que as implicações desta segurança são. Presumivelmente, a versão não-bloqueio não pode garantir a quantidade de entropia que está sendo usado.

Atualizar : Ok, eu encontrei este excelente explicação .

Em poucas palavras, para evitar o bloqueio, o uso new SecureRandom(). Este /dev/urandom usos, que não bloqueia e é basicamente tão seguro quanto /dev/random. A partir do post: "A única vez que você quiser chamá-/ dev / random é quando a máquina é a primeira inicialização, e entropia ainda não acumulou"

SecureRandom.getInstanceStrong() dá-lhe a RNG mais forte absoluta, mas é apenas seguro para uso em situações onde um grupo de bloqueio não afetará você.

O problema que você referenciada sobre /dev/random não é com o algoritmo SecureRandom, mas com a fonte de aleatoriedade que ele usa. Os dois são ortogonais. Você deve descobrir qual dos dois está retardando para baixo.

Uncommon Maths página que você ligado menciona explicitamente que não estão a abordar a fonte de aleatoriedade.

Você pode experimentar diferentes provedores JCE, como BouncyCastle, para ver se a sua implementação de SecureRandom é mais rápido.

Uma breve procurar também revela manchas Linux que substituem o padrão implementação com Fortuna. Eu não sei muito mais sobre isso, mas você é bem-vindo para investigar.

Gostaria também de mencionar que, enquanto é muito perigoso usar um algoritmo SecureRandom mal implementados e / ou fonte de aleatoriedade, você pode lançar seu próprio provedor JCE com uma implementação personalizada do SecureRandomSpi. Você terá que passar por um processo com a Sun para obter o seu provedor de assinado, mas na verdade é bastante simples; eles só precisam que você fax-lhes um formulário declarando que você está ciente das restrições de exportação dos EUA em bibliotecas de criptografia.

Eu não bater contra este problema sozinho, mas eu gerar um segmento no início do programa que imediatamente tenta gerar uma semente, então morre. O método que você chama para randoms irá juntar-se a esse segmento se ele está vivo assim que a primeira chamada apenas blocos se ocorre muito cedo na execução do programa.

Minha experiência tem sido apenas com a inicialização lenta do PRNG, não com geração de dados aleatórios depois disso. Tente uma estratégia de inicialização mais ansioso. Uma vez que eles são caros para criar, tratá-lo como um singleton e reutilizar a mesma instância. Se há muita contenção thread para uma instância, piscina-los ou torná-los thread-local.

Não comprometa a geração de números aleatórios. A fraqueza não compromete toda a sua segurança.

Eu não ver um monte de COTS geradores atômica baseada-decadência, mas existem vários planos lá fora para eles, se você realmente precisa de um monte de dados aleatórios. Um site que sempre tem coisas interessantes para olhar, incluindo HotBits, é Fourmilab de John Walker.

Parece que você deveria ser mais clara sobre suas necessidades RNG. A exigência RNG criptográfico mais forte (como eu o entendo) seria que, mesmo se você sabe o algoritmo usado para gerá-los, e você sabe todos os números aleatórios gerados anteriormente, você não poderia obter qualquer informação útil sobre qualquer um dos números aleatórios gerados no futuro, sem gastar uma quantidade inviável de poder de computação.

Se você não precisa dessa garantia cheia de aleatoriedade, em seguida, provavelmente há compensações de desempenho adequados. Eu tenderia a concordar com a resposta do Dan Dyer sobre AESCounterRNG de Uncommons-Matemática, ou Fortuna (um dos autores é Bruce Schneier, um especialista em criptografia). Eu nunca usei quer, mas as ideias aparecem respeitável à primeira vista.

eu pensar que se você pudesse gerar uma semente aleatória inicial periodicamente (por exemplo, uma vez por dia ou hora ou qualquer outro), você poderia usar uma cifra de fluxo rápido para gerar números aleatórios de pedaços sucessivos do Stream (se a cifra de fluxo utiliza XOR em seguida, basta passar em um fluxo de valores nulos ou pegar os bits XOR diretamente). eStream projeto de ECRYPT tem muita informação boa incluindo benchmarks de desempenho. Isso não manteria entropia entre os pontos no tempo que você reabastecê-lo, então se alguém conhecia um dos números aleatórios e o algoritmo que você usou, tecnicamente seria possível, com um monte de poder de computação, para quebrar a cifra de fluxo e acho que seu estado interno para ser capaz de prever futuros números aleatórios. Mas você tem que decidir se esse risco e suas consequências são suficientes para justificar o custo de manutenção entropia.

Edit: aqui estão algumas notas do curso de criptografia sobre RNG eu encontrei na 'net que olhar muito relevante para este tema.

Se os seus suportes de hardware que tente usando Java RdRand Utility da qual eu sou o autor .

A sua base em instrução RDRAND da Intel e é cerca de 10 vezes mais rápido do que SecureRandom e sem problemas de largura de banda para a implementação de grande volume.


Note que esta implementação só funciona nesses da CPU que fornecem a instrução (ou seja, quando a bandeira processador rdrand é definido). Você precisa instanciar explicitamente através do construtor RdRandRandom(); não Provider específica foi implementada.

Outra coisa a olhar é o securerandom.source propriedade em arquivo lib / security / java.security

Pode haver um benefício de desempenho para usar / dev / urandom em vez de / dev / random. Lembre-se que se a qualidade dos números aleatórios é importante, não fazer um compromisso que quebras de segurança.

Você pode tentar projeto Apache Commons matemática, que tem algumas implementações de algoritmos bem saber:

https://commons.apache.org/proper/commons- math / userguide / random.html

No entanto, ter cuidado com o desempenho. O construtor padrão de RandomDataGenerator cria uma instância dedicada do Well19937c, que é uma operação muito cara.

De acordo com a documentação, esta classe não thread-safe, mas se você pode garantir que apenas um thread irá aceder a esta classe, você pode inicializar somente uma instância por Thread.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top