Работа ТОЛЬКО с /dev/random в Java

У меня есть HRNG, который передает /dev/random в Debian Wheezy. Это быстро, поэтому блокировка не будет проблемой. Теперь, в моем Java-коде, я хочу убедиться, что я использую энтропию в /dev/random и ТОЛЬКО этой энтропией. Я не заинтересован в использовании чего-либо из /dev/urandom.

Я хочу заставить Java SecureRandom ТОЛЬКО получить энтропию из /dev/random. Поскольку я понимаю реализацию в настоящее время, она использует /dev/urandom при вызове getBytes(), но /dev/random при вызове generateSeed(). Я понимаю, почему.

Как я понимаю, единственная причина для чтения из /dev/urandom - если вы предпочитаете скорость над безопасностью. Я хочу, чтобы была возможна высокая энтропия. /dev/urandom просто не будет делать.

Итак, как заставить SecureRandom ТОЛЬКО использовать /dev/random (поставляемый HRNG) и никогда не касаться чего-либо из нижнего PRNG (например,/dev/urandom)?

Спасибо, мил.

Ответ 1

Этот ответ предполагает, что вы знаете, что делаете. В других случаях использование /dev/random должно быть сведено к минимуму.

/dev/random действует как обычный файл, поэтому любая программа, которая может читать любой файл, может читать из /dev/random. Вероятно, вы знаете, что cat /dev/random выводит из него случайные данные, и если он делает это достаточно быстро, вы действительно можете его использовать. Итак, если все остальное не удается, вы всегда сможете напрямую прочитать этот файл...

Итак, если вы посмотрите на источник SecureRandom, вы обнаружите, что он использует SecureRandomSpi для фактической работы. Оказывается, NativePRNG.Blocking делает то, что вы хотите:

Класс NativePRNG, который использует /dev/random для семенного и случайного материала. Обратите внимание, что он не уважает свойства egd, так как мы не можем узнать, каковы эти качества. Это очень похоже на внешний класс NativePRNG, сводя к минимуму любой поломка для сериализации существующей реализации. Поскольку: 1.8

Проблема может заключаться в Since 1.8, которая оставляет вам возможность заархивировать ее на более ранних платформах, если вы еще не можете использовать Java 8. Исходный код доступен в конце концов.

Итак, теперь поставьте это в код:

Мы должны выбрать конкретную реализацию для использования. Чтобы найти точное имя, мы выводим все доступные службы со следующей строкой:

for (Provider p: Security.getProviders()) p.getServices().forEach(System.out::println);

Затем мы ищем там Native, и мы находим следующую запись:

SUN: SecureRandom.NativePRNGBlocking -> sun.security.provider.NativePRNG$Blocking

Это означает, что мы можем создать объект SecureRandom, как показано ниже, чтобы сделать то, что вы хотите:

SecureRandom sr = SecureRandom.getInstance("NativePRNGBlocking", "SUN");

Простой тест

byte[] b = new byte[10000];
sr.nextBytes(b);
System.out.println(Arrays.toString(b));

занимает много времени, мне приходилось уменьшать количество прочитанных байтов. Если он работает для вас, поздравляю, вы читаете /dev/random!

Обратите внимание, что этот класс находится в пакете sun.security.provider, который не гарантированно доступен везде. Например, он, вероятно, не будет работать на Android. Если это прекрасно, тогда это решение будет работать, иначе вы просто должны просто прочитать его как файл.

Не читайте с /dev/random на Android. Пожалуйста.