Вопрос

Если вам нужно криптографически надежное случайное число в Java, вы используете SecureRandom.К сожалению, SecureRandom может быть очень медленным.Если он использует /dev/random в Linux это может блокировать ожидание накопления достаточной энтропии.Как вам избежать снижения производительности?

Кто-нибудь пользовался Необычная Математика как решить эту проблему?

Кто-нибудь может подтвердить, что эта проблема с производительностью была решена в JDK 6?

Это было полезно?

Решение

Если вам нужны истинные случайные данные, то, к сожалению, вам придется их дождаться.Это включает в себя исходные данные для SecureRandom PRNG.Необычные математики не могут собрать истинные случайные данные быстрее, чем SecureRandom, хотя он может подключаться к Интернету для загрузки исходных данных с определенного веб-сайта.Я предполагаю, что это вряд ли будет быстрее, чем /dev/random там, где это доступно.

Если вам нужен PRNG, сделайте что-то вроде этого:

SecureRandom.getInstance("SHA1PRNG");

Какие строки поддерживаются, зависит от SecureRandom Поставщик SPI, но вы можете перечислить их с помощью Security.getProviders() и Provider.getService().

Sun любит SHA1PRNG, поэтому он широко доступен.Это не особенно быстро, поскольку PRNG работают, но PRNG будут просто обрабатывать числа, а не блокировать физическое измерение энтропии.

Исключением является то, что если вы не позвоните setSeed() прежде чем получать данные, PRNG заполнит сам себя один раз при первом вызове next() или nextBytes().Обычно он делает это, используя довольно небольшой объем истинно случайных данных из системы.Этот вызов может блокировать, но сделает ваш источник случайных чисел намного более безопасным, чем любой вариант "хэшировать текущее время вместе с PID, добавить 27 и надеяться на лучшее".Однако, если все, что вам нужно, это случайные числа для игры, или если вы хотите, чтобы поток повторялся в будущем, используя одно и то же начальное значение для целей тестирования, небезопасное начальное значение все еще полезно.

Другие советы

Вы должны иметь возможность выбрать более быстрый, но немного менее безопасный / dev / urandom в Linux, используя:

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

Однако это не работает с Java 5 и более поздними версиями (Ошибка Java 6202721).Предлагаемый обходной путь заключается в использовании:

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

(обратите внимание на дополнительные /./)

В Linux реализация по умолчанию для SecureRandom является NativePRNG (исходный код здесь), который, как правило, происходит очень медленно.В Windows по умолчанию используется SHA1PRNG, который, как указывали другие, вы также можете использовать в Linux, если укажете это явно.

NativePRNG отличается от SHA1PRNG и Необычная Математика' Столкновение в том смысле, что он непрерывно получает энтропию от операционной системы (путем считывания из /dev/urandom).Другие PRNG не приобретают никакой дополнительной энтропии после заполнения.

AESCounterRNG примерно в 10 раз быстрее, чем SHA1PRNG, который IIRC сам по себе в два или три раза быстрее , чем NativePRNG.

Если вам нужен более быстрый PRNG, который приобретает энтропию после инициализации, посмотрите, сможете ли вы найти Java-реализацию Фортуна.Базовый PRNG реализации Fortuna идентичен тому, который используется AESCounterRNG, но существует также сложная система объединения энтропии и автоматического повторного заполнения.

Многие дистрибутивы Linux (в основном на базе Debian) настраивают OpenJDK для использования /dev/random для получения энтропии.

/dev/random является по определению медленным (и даже может блокировать).

Отсюда у вас есть два варианта, как его разблокировать:

  1. Улучшить энтропию, или
  2. Уменьшите требования к случайности.

Вариант 1, Повышение энтропии

Чтобы получить больше энтропии в /dev/random, попробуйте победили демон.Это демон, который постоянно собирает избыточную энтропию и работает также в виртуализированной среде, потому что для этого не требуется никакого специального оборудования, только сам процессор и часы.

В Ubuntu/Debian:

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

На RHEL/CentOS:

yum install haveged
systemctl enable haveged
systemctl start haveged

Вариант 2.Снизить требования к случайности

Если по какой-то причине приведенное выше решение не помогает или вас не волнует криптографически сильная случайность, вы можете переключиться на /dev/urandom вместо этого, который гарантированно не блокируется.

Чтобы сделать это глобально, отредактируйте файл jre/lib/security/java.security в вашей установке Java по умолчанию для использования /dev/urandom (из-за другого ошибка это должно быть указано как /dev/./urandom).

Вот так:

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

Тогда вам никогда не придется указывать это в командной строке.


Примечание:Если вы занимаетесь криптографией, вы потребность хорошая энтропия.Показательный пример - проблема с Android PRNG снижена безопасность биткоин-кошельков.

У меня была аналогичная проблема со звонками в SecureRandom блокировка примерно на 25 секунд за раз на безголовом сервере Debian.Я установил haveged демон для обеспечения /dev/random постоянно пополняется, на безголовых серверах вам нужно что-то вроде этого, чтобы генерировать требуемую энтропию.Мои призывы к SecureRandom теперь, возможно, потребуются миллисекунды.

Если вы хотите действительно "криптографически сильную" случайность, то вам нужен сильный источник энтропии. /dev/random работает медленно, потому что ему приходится ждать, пока системные события соберут энтропию (чтение с диска, сетевые пакеты, движение мыши, нажатия клавиш и т.д.).

Более быстрым решением является аппаратный генератор случайных чисел.Возможно, у вас уже есть один встроенный в вашу материнскую плату;посмотрите на документация hw_random для получения инструкций о том, как выяснить, есть ли он у вас и как им пользоваться.Пакет rng-tools включает в себя демон, который будет передавать аппаратно генерируемую энтропию в /dev/random.

Если HRNG недоступен в вашей системе, и вы готовы пожертвовать силой энтропии ради производительности, вам захочется создать хороший PRNG с данными из /dev/random, и пусть PRNG выполнит основную часть работы.Существует несколько PRNG, одобренных NIST, перечисленных в SP800-90 которые просты в реализации.

Существует инструмент (по крайней мере, в Ubuntu), который будет внедрять искусственную случайность в вашу систему.Команда - это просто:

rngd -r /dev/urandom

и вам может понадобиться sudo на передней панели.Если у вас нет пакета rng-tools, вам нужно будет его установить.Я попробовал это, и это определенно помогло мне!

Источник: мэтт против мира

Я столкнулся с тем же самым проблема.Немного погуглив с нужными поисковыми запросами, я наткнулся на эту замечательную статью о Цифровой океан.

haveged - это потенциальное решение без ущерба для безопасности.

Я просто цитирую соответствующую часть из приведенной здесь статьи.

Основанный на принципе HAVEGE и ранее основанный на связанной с ним библиотеке, haveged позволяет генерировать случайность на основе изменений во времени выполнения кода на процессоре.Поскольку практически невозможно, чтобы для выполнения одного фрагмента кода требовалось одинаковое точное время, даже в одной и той же среде на одном и том же оборудовании, время выполнения одного или несколько программ должны подходить для заполнения случайного источника. Реализация haveged заполняет случайный источник вашей системы (обычно / dev / random), используя различия в счетчике временных меток вашего процессора (TSC) после повторного выполнения цикла

Как установить haveged

Следуйте инструкциям, описанным в этой статье. https://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged

Я опубликовал это здесь

Используйте secure random в качестве источника инициализации для рекуррентного алгоритма;тогда вы могли бы использовать Mersenne twister для объемной работы вместо того, что есть в UNCOMMON MATH, который существует уже некоторое время и зарекомендовал себя лучше, чем другие prng

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

Обязательно время от времени обновляйте secure random, используемый для инициализации, например, вы могли бы сгенерировать один secure random для каждого клиента, используя один псевдослучайный генератор mersenne twister для каждого клиента, получая достаточно высокую степень рандомизации

Используя Java 8, я обнаружил, что в Linux вызывается SecureRandom.getInstanceStrong() дал бы мне возможность NativePRNGBlocking алгоритм.Это часто приводило к блокировке на много секунд для генерации нескольких байт соли.

Я перешел к явному запросу NativePRNGNonBlocking вместо этого, как и следовало ожидать из названия, он больше не блокировался.Я понятия не имею, каковы последствия этого для безопасности.Предположительно, неблокирующая версия не может гарантировать количество используемой энтропии.

Обновить:Хорошо, я нашел это прекрасное объяснение.

В двух словах, чтобы избежать блокировки, используйте new SecureRandom().Это использует /dev/urandom, который не блокируется и в принципе так же безопасен, как /dev/random.Из сообщения:"Единственный раз, когда вы хотели бы вызвать /dev/random, - это когда машина загружается в первый раз, а энтропия еще не накопилась".

SecureRandom.getInstanceStrong() дает вам абсолютно мощный ГСЧ, но его безопасно использовать только в ситуациях, когда куча блокировок на вас не повлияет.

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

На странице Uncommon Maths, на которую вы ссылаетесь, явно упоминается, что они не обращаются к источнику случайности.

Вы можете попробовать различные поставщики JCE, такие как BouncyCastle, чтобы узнать, является ли их реализация SecureRandom это быстрее.

Краткий Поиск также показаны исправления для Linux, которые заменяют реализацию по умолчанию на Fortuna.Я не знаю об этом больше ничего, но вы всегда можете провести расследование.

Я должен также упомянуть, что, хотя использовать плохо реализованный SecureRandom алгоритма и / или источника случайности, вы можете создать свой собственный поставщик JCE с пользовательской реализацией SecureRandomSpi.Вам нужно будет пройти процедуру с Sun, чтобы подписать контракт с вашим провайдером, но на самом деле это довольно просто;им просто нужно, чтобы вы отправили им по факсу форму, в которой указано, что вы осведомлены об ограничениях на экспорт криптографических библиотек в США.

Я сам не сталкивался с этой проблемой, но я бы создал поток при запуске программы, который немедленно пытается сгенерировать начальное значение, а затем умирает.Метод, который вы вызываете для randoms, присоединится к этому потоку, если он активен, поэтому первый вызов блокируется только в том случае, если он происходит на очень ранней стадии выполнения программы.

Мой опыт был связан только с медленной инициализацией PRNG, а не с генерацией случайных данных после этого.Попробуйте более энергичную стратегию инициализации.Поскольку их создание обходится дорого, относитесь к ним как к одноэлементным и повторно используйте один и тот же экземпляр.Если для одного экземпляра слишком много конфликтов потоков, объедините их в пул или сделайте локальными для потоков.

Не идите на компромисс с генерацией случайных чисел.Слабое место там ставит под угрозу всю вашу безопасность.

Я не вижу большого количества генераторов на основе атомного распада COTS, но есть несколько планов для них, если вам действительно нужно много случайных данных.Одним из сайтов, на котором всегда есть что посмотреть, включая горячие точки, является Фурмилаборатория Джона Уокера.

Похоже, вам следует более четко представлять свои требования к ГСЧ.Самым строгим криптографическим требованием к RNG (насколько я понимаю) было бы то, что даже если вы знаете алгоритм, используемый для их генерации, и вы знаете все ранее сгенерированные случайные числа, вы не смогли бы получить никакой полезной информации ни о каких случайных числах, сгенерированных в будущем, не затрачивая непрактичного количества вычислительной мощности.

Если вам не нужна эта полная гарантия случайности, то, вероятно, существуют соответствующие компромиссы в производительности.Я был бы склонен согласиться с Ответ Дэна Дайера об ошибке от Uncommons-Maths, или Fortuna (одним из ее авторов является Брюс Шнайер, эксперт в области криптографии).Я никогда не использовал ни то, ни другое, но на первый взгляд идеи кажутся заслуживающими доверия.

Я бы так и сделал подумай что, если бы вы могли периодически генерировать начальное случайное начальное значение (напримеродин раз в день, час или что-то еще), вы могли бы использовать быстрый потоковый шифр для генерации случайных чисел из последовательных фрагментов потока (если потоковый шифр использует XOR, то просто передайте поток нулей или возьмите биты XOR напрямую).ECRYPT's Эстрим проект содержит много полезной информации, включая контрольные показатели производительности.Это не позволило бы поддерживать энтропию между моментами времени, когда вы ее пополняете, поэтому, если бы кто-то знал одно из случайных чисел и алгоритм, который вы использовали, технически было бы возможно, при большой вычислительной мощности, взломать потоковый шифр и угадать его внутреннее состояние, чтобы иметь возможность предсказывать будущие случайные числа.Но вам придется решить, достаточны ли этот риск и его последствия, чтобы оправдать затраты на поддержание энтропии.

Редактировать:вот некоторые из них конспекты курса криптографии по ГСЧ Я нашел в сети то, что выглядит очень уместным для этой темы.

Если ваше оборудование поддерживает это, попробуйте использование утилиты Java RdRand автором которого я являюсь.

Он основан на данных Intel RDRAND инструкция и примерно в 10 раз быстрее, чем SecureRandom и никаких проблем с пропускной способностью при реализации большого объема.


Обратите внимание, что эта реализация работает только на тех процессорах, которые предоставляют инструкцию (т. Е.когда rdrand установлен флаг процессора).Вам нужно явно создать его экземпляр с помощью RdRandRandom() конструктор;никаких конкретных Provider было реализовано.

Что-то еще, на что стоит обратить внимание, - это свойство securerandom.source в файле lib /security /java.security

Использование /dev/urandom вместо /dev/random может повысить производительность.Помните, что если качество случайных чисел важно, не идите на компромисс, который нарушает безопасность.

Вы можете попробовать Apache commons Math project, в котором есть несколько реализаций хорошо известных алгоритмов:

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

Однако будьте осторожны с производительностью.Конструктор по умолчанию для RandomDataGenerator создает выделенный экземпляр Well19937c, это очень дорогостоящая операция.

Согласно документации, этот класс это не так потокобезопасный, но если вы можете гарантировать, что только один поток получит доступ к этому классу, вы можете инициализировать только один экземпляр для каждого потока.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top