Как бороться с медленным генератором SecureRandom?
Если вам нужны криптографически надежные случайные числа в Java, вы используете SecureRandom. К сожалению, SecureRandom может быть очень медленным. Если он использует /dev/random в Linux, он может блокировать ожидание накопления достаточной энтропии. Как избежать снижения производительности?
Кто-нибудь может подтвердить, что эта проблема с производительностью была решена в JDK 6?
Переведено автоматически
Ответ 1
Вы должны иметь возможность выбрать более быстрый, но немного менее безопасный / dev / urandom в Linux с помощью:
-Djava.security.egd=file:/dev/urandom
Однако это не работает с Java 5 и более поздними версиями (ошибка Java 6202721). Предлагаемый обходной путь заключается в использовании:
-Djava.security.egd=file:/dev/./urandom
(обратите внимание на дополнительное /./)
Ответ 2
Если вам нужны настоящие случайные данные, то, к сожалению, вам придется подождать. Сюда входит начальное значение для SecureRandom PRNG. Uncommon Maths не может собирать истинные случайные данные быстрее, чем SecureRandom, хотя он может подключаться к Интернету для загрузки исходных данных с определенного веб-сайта. Я предполагаю, что это вряд ли будет быстрее, чем /dev/random там, где это доступно.
Если вам нужен PRNG, сделайте что-то вроде этого:
SecureRandom.getInstance("SHA1PRNG");
Какие строки поддерживаются, зависит от SecureRandom поставщика SPI, но вы можете перечислить их с помощью Security.getProviders() и Provider.getService().
Sun любит SHA1PRNG, поэтому он широко доступен. Это не особенно быстро, поскольку PRNG работают, но PRNG будут просто обрабатывать числа, а не блокировать физическое измерение энтропии.
Исключение состоит в том, что если вы не вызываете setSeed() перед получением данных, то PRNG заполнит сам себя один раз при первом вызове next() или nextBytes(). Обычно это делается с использованием довольно небольшого количества истинно случайных данных из системы. Этот вызов может блокировать, но сделает ваш источник случайных чисел намного более безопасным, чем любой вариант "хэшируйте текущее время вместе с PID, добавьте 27 и надейтесь на лучшее". Однако, если все, что вам нужно, это случайные числа для игры, или если вы хотите, чтобы поток повторялся в будущем, используя то же самое начальное значение для целей тестирования, небезопасное начальное значение все еще полезно.
Ответ 3
В Linux для SecureRandomявляетсяNativePRNG реализацией по умолчанию (исходный код здесь), которая, как правило, работает очень медленно. В Windows по умолчанию используется значение SHA1PRNG, которое, как указывали другие, вы также можете использовать в Linux, если укажете это явно.
NativePRNG отличается от SHA1PRNG AESCounterRNG от Uncommons Maths тем, что он непрерывно получает энтропию от операционной системы (путем чтения из /dev/urandom). Другие PRNGS не приобретают никакой дополнительной энтропии после заполнения.
AESCounterRNG примерно в 10 раз быстрее, чем SHA1PRNG, а IIRC сам по себе в два или три раза быстрее, чем NativePRNG.
Если вам нужен более быстрый PRNG, который приобретает энтропию после инициализации, посмотрите, сможете ли вы найти Java-реализацию Fortuna. Базовый PRNG реализации Fortuna идентичен тому, который используется AESCounterRNG, но также существует сложная система объединения энтропии и автоматического повторного заполнения.
Ответ 4
Многие дистрибутивы Linux (в основном на базе Debian) настраивают OpenJDK на использование /dev/random для энтропии.
/dev/random по определению является медленным (и даже может блокировать).
Отсюда у вас есть два варианта, как его разблокировать:
Улучшить энтропию, или
Снизить требования к случайности.
Вариант 1, повышение энтропии
Чтобы увеличить энтропию /dev/random, попробуйте демон haveged. Это демон, который непрерывно собирает избыточную энтропию, а также работает в виртуальной среде, потому что для этого не требуется никакого специального оборудования, только сам процессор и часы.
В Ubuntu / Debian:
apt-get install haveged update-rc.d haveged defaults service haveged start
Если по какой-то причине приведенное выше решение не помогает или вас не волнует криптографически сильная случайность, вы можете вместо этого переключиться на /dev/urandom, который гарантированно не блокируется.
Чтобы сделать это глобально, отредактируйте файл jre/lib/security/java.security в вашей установке Java по умолчанию для использования /dev/urandom (из-за другой ошибки его необходимо указать как /dev/./urandom).
Тогда вам никогда не придется указывать это в командной строке.
Примечание: Если вы занимаетесь криптографией, вам нужна хорошая энтропия. Показательный пример - проблема с PRNG Android снизила безопасность биткоин-кошельков.