Если вы хотите криптографически сильные случайные числа в Java, вы используете SecureRandom
. К сожалению, SecureRandom
может быть очень медленным. Если он используется /dev/random
в Linux, он может заблокировать ожидание достаточной энтропии для наращивания. Как избежать штрафа за производительность?
Кто-нибудь использовал Uncommon Maths как решение этой проблемы?
Кто-нибудь может подтвердить, что эта проблема производительности была решена в JDK 6?
Ответы:
Если вам нужны настоящие случайные данные, то, к сожалению, вам придется ждать их. Это включает в себя семя для
SecureRandom
PRNG. Необычные математики не могут собирать настоящие случайные данные быстрееSecureRandom
, хотя могут подключаться к Интернету и загружать начальные данные с определенного веб-сайта. Я думаю, что это вряд ли будет быстрее, чем/dev/random
там, где это доступно.Если вы хотите PRNG, сделайте что-то вроде этого:
Какие строки поддерживаются, зависит от
SecureRandom
поставщика SPI, но вы можете перечислить их, используяSecurity.getProviders()
иProvider.getService()
.Солнце любит SHA1PRNG, поэтому оно широко доступно. Это не особенно быстро, как PRNGs, но PRNGs будут просто подсчитывать цифры, а не блокировать физическое измерение энтропии.
Исключением является то, что если вы не позвоните
setSeed()
до получения данных, то PRNG будет запущен один раз при первом вызовеnext()
илиnextBytes()
. Обычно это делается с использованием довольно небольшого количества реальных случайных данных из системы. Этот вызов может блокировать, но сделает ваш источник случайных чисел намного более безопасным, чем любой вариант «хеширования текущего времени вместе с PID, добавьте 27 и надейтесь на лучшее». Если все, что вам нужно, это случайные числа для игры, или если вы хотите, чтобы поток повторялся в будущем с использованием того же начального числа для целей тестирования, небезопасное начальное число все еще полезно.источник
Вы должны быть в состоянии выбрать более быстрый, но немного менее безопасный / dev / urandom в Linux, используя:
Однако это не работает с Java 5 и более поздними версиями ( Java Bug 6202721 ). Предложенный обходной путь должен использовать:
(обратите внимание на дополнительное
/./
)источник
/dev/urandom
Sun воспринимает это как магическую строку и использует в/dev/random
любом случае, так что вам придется ее подделать. Когдаfile:
URL не являетсяfile:
URL? Всякий раз, когда Солнце решит, что это не так :-(file:/dev/urandom
установлены в-Djava.security.egd
илиsecurerandom.source
в файле java.security,/dev/random/
все равно читаются всякий разSecureRandom.getSeed()
(илиsetSeed()
вызываются). Обходной путь сfile:/dev/./urandom
результатами вообще не читает/dev/random
(подтверждено с помощью strace)/dev/urandom
не менее безопасен, чем/dev/random
при использовании современного CSPRNG: en.wikipedia.org/wiki//dev/random#FreeBSD/dev/urandom/
состоит в том, что произойдет, если вы будете использовать его для генерации секретов на новом оборудовании из коробки, которое может находиться в вполне предсказуемом состоянии./dev/urandom/
не будет блокировать энтропию, хотя это один случай, когда вы должны. Ситуация еще хуже, если секрет является постоянным, например, если первое, что ваше устройство делает при первой загрузке, это генерирует пару открытый-закрытый ключ. Вне этих страшных ситуаций, хорошо/dev/urandom
лучше, чем использовать общиеSecureRandom
алгоритмы в любом случае.В Linux реализация по умолчанию для
SecureRandom
isNativePRNG
(исходный код здесь ) имеет тенденцию быть очень медленной. В Windows по умолчаниюSHA1PRNG
, которое, как отмечали другие, вы также можете использовать в Linux, если вы укажете это явно.NativePRNG
отличается от AESCounterRNG отSHA1PRNG
Uncommons Maths тем, что он постоянно получает энтропию от операционной системы (путем чтения из/dev/urandom
). Другие PRNG не приобретают никакой дополнительной энтропии после посева.AESCounterRNG примерно в 10 раз быстрее, чем
SHA1PRNG
сам IIRC, в два-три раза быстрее, чемNativePRNG
.Если вам нужен более быстрый PRNG, который приобретает энтропию после инициализации, посмотрите, сможете ли вы найти реализацию Fortuna на Java . Базовый PRNG реализации Fortuna идентичен тому, который используется AESCounterRNG, но есть также сложная система объединения энтропии и автоматического повторного заполнения.
источник
Многие дистрибутивы Linux (в основном на основе Debian) настраивают OpenJDK для использования
/dev/random
в качестве энтропии./dev/random
по определению медленный (и может даже блокировать).Отсюда у вас есть два варианта, как разблокировать его:
Вариант 1. Улучшение энтропии.
Чтобы получить больше энтропии
/dev/random
, попробуйте демона beged . Это демон, который непрерывно собирает энтропию HAVEGE и работает также в виртуализированной среде, поскольку для него не требуется никакого специального оборудования, только сам процессор и часы.В Ubuntu / Debian:
На RHEL / CentOS:
Вариант 2. Снижение требований случайности
Если по какой-либо причине вышеприведенное решение не помогает или вас не волнует криптографически сильная случайность, вы можете переключиться на
/dev/urandom
нее, которая гарантированно не заблокирует.Чтобы сделать это глобально, отредактируйте файл
jre/lib/security/java.security
в используемой по умолчанию установке Java для использования/dev/urandom
(из-за другой ошибки его нужно указать как/dev/./urandom
).Как это:
Тогда вам никогда не придется указывать это в командной строке.
Примечание: если вы занимаетесь криптографией, вам нужна хорошая энтропия. Показательный пример - проблема PRNG для Android снизила безопасность биткойн-кошельков.
источник
/dev/random
по определению медленный (и может даже блокировать)» неверен; это полностью зависит от конфигурации системы. Более новые машины могут иметь, например, быстрый RNG в CPU, который может использоваться, и машины BSD обычно имеют одинаковую реализацию для/dev/random
и/devl/urandom
. Тем не менее, вы, вероятно, не должны полагаться на/dev/random
скорость, обязательно. На виртуальных машинах вы можете установить клиентский инструментарий на клиентскую виртуальную машину, чтобы он мог использовать ГСЧ хост-ОС.У меня была похожая проблема с вызовами
SecureRandom
блокировки примерно по 25 секунд за раз на безголовом сервере Debian. Я установилhaveged
демон, чтобы убедиться, что/dev/random
он обновлен, на серверах без головы вам нужно что-то подобное, чтобы генерировать необходимую энтропию. Мои звонкиSecureRandom
сейчас, возможно, занимают миллисекунды.источник
Если вы хотите действительно «криптографически сильную» случайность, то вам нужен сильный источник энтропии.
/dev/random
медленный, потому что он должен ждать системных событий, чтобы собрать энтропию (чтение диска, сетевые пакеты, движение мыши, нажатия клавиш и т. д.).Более быстрое решение - аппаратный генератор случайных чисел. Возможно, у вас уже есть один встроенный в материнскую плату; Изучите документацию hw_random , чтобы узнать, как выяснить, есть ли она у вас и как ее использовать. В пакет rng-tools входит демон, который будет передавать энтропию, генерируемую оборудованием
/dev/random
.Если HRNG не доступен в вашей системе, и вы готовы пожертвовать силой энтропии для повышения производительности, вы захотите получить хороший PRNG с данными из него
/dev/random
и позволить PRNG выполнять большую часть работы. Есть несколько утвержденных NIST PRNG, перечисленных в SP800-90, которые легко внедрить.источник
Используя Java 8, я обнаружил, что в Linux вызов
SecureRandom.getInstanceStrong()
даст мнеNativePRNGBlocking
алгоритм. Это часто блокировало бы в течение многих секунд, чтобы генерировать несколько байтов соли.Я переключился на явный запрос
NativePRNGNonBlocking
вместо этого, и, как и ожидалось из названия, он больше не заблокирован. Я понятия не имею, каковы последствия этого для безопасности. Предположительно, неблокирующая версия не может гарантировать количество используемой энтропии.Обновление : Хорошо, я нашел это отличное объяснение .
В двух словах, чтобы избежать блокировки, используйте
new SecureRandom()
. Это использует/dev/urandom
, который не блокирует и в основном так же безопасен, как/dev/random
. Из поста: «Единственный раз, когда вы захотите вызвать / dev / random, это когда машина загружается впервые, а энтропия еще не накопилась».SecureRandom.getInstanceStrong()
дает вам самый сильный RNG, но его можно использовать только в ситуациях, когда блокировка не будет влиять на вас.источник
getInstanceStrong()
долгосрочные ключи, такие как ключи TLS. И даже тогда я предпочел бы использоватьnew SecureRandom()
FIPS-совместимый генератор пар ключей или генератор случайных чисел. Так что да, это дает ответ, если/dev/urandom
не блокирует: в конце концов, он все равно полагается на энтропию системы; но это очень хороший совет в целом . Если/dev/urandom
блоки, возможно, вам придется исправить источник проблемы, а не ваше Java-приложение.Существует инструмент (по крайней мере, в Ubuntu), который подает искусственную случайность в вашу систему. Команда просто:
и вам может понадобиться sudo на передней панели. Если у вас нет пакета rng-tools, вам необходимо установить его. Я попробовал это, и это определенно помогло мне!
Источник: Мэтт против мира
источник
sudo rngd -r /dev/urandom
сsudo apt install rng-tools
в xenialЯ столкнулся с той же проблемой . После некоторого поиска в Google с правильными условиями поиска, я наткнулся на эту прекрасную статью о DigitalOcean .
Это потенциальное решение без ущерба для безопасности.
Я просто цитирую соответствующую часть статьи здесь.
Как установить hasged
Следуйте инструкциям в этой статье. https://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged
Я разместил это здесь
источник
Проблема, о которой вы упоминали,
/dev/random
заключается не вSecureRandom
алгоритмом, а с источником случайности, который он использует. Два ортогональны. Вы должны выяснить, какой из двух замедляет вас.На странице «Необычные математики», на которую вы ссылались, явно упоминается, что они не обращаются к источнику случайности.
Вы можете попробовать разные провайдеры JCE, такие как BouncyCastle, чтобы увидеть, если их реализация
SecureRandom
.Краткий поиск также обнаруживает патчи для Linux, которые заменяют реализацию по умолчанию на Fortuna. Я не знаю больше об этом, но вы можете расследовать.
Я должен также упомянуть, что, хотя очень плохо использовать плохо реализованный
SecureRandom
алгоритм и / или источник случайности, вы можете свернуть свой собственный JCE-провайдер с пользовательской реализациейSecureRandomSpi
. Вам нужно будет пройти через Sun процесс, чтобы подписать вашего провайдера, но на самом деле это довольно просто; им просто нужно, чтобы вы отправили им по факсу форму, подтверждающую, что вы знаете об ограничениях на экспорт криптобиблиотек в США.источник
Используйте безопасный случайный случай в качестве источника инициализации для рекуррентного алгоритма; тогда вы могли бы использовать твистер Mersenne для массовых работ вместо того, что использовался в UncommonMath, который существовал некоторое время и оказался лучше, чем другие prng
http://en.wikipedia.org/wiki/Mersenne_twister
Обязательно обновляйте время от времени безопасное случайное число, используемое для инициализации, например, вы можете создать одно безопасное случайное случайное число для каждого клиента, используя один псевдослучайный генератор mersenne twister для каждого клиента, получая достаточно высокую степень рандомизации.
источник
Random
, но не дляSecureRandom
.Согласно документации , различные алгоритмы, используемые SecureRandom, в порядке предпочтения:
Поскольку вы спрашивали о Linux, я игнорирую реализацию Windows, а также SunPKCS11, который действительно доступен только в Solaris, если вы не установили его самостоятельно - и тогда вы не будете спрашивать этого.
Согласно той же документации, эти алгоритмы
SHA1PRNG
Первоначальное в настоящее время выполняется с помощью комбинации системных атрибутов и устройства сбора энтропии java.security.
NativePRNG
nextBytes()
использует/dev/urandom
generateSeed()
использует/dev/random
NativePRNGB блокировка
nextBytes()
иgenerateSeed()
использование/dev/random
NativePRNGNonBlocking
nextBytes()
иgenerateSeed()
использование/dev/urandom
Это означает, что если вы используете
SecureRandom random = new SecureRandom()
, он идет вниз по этому списку, пока не найдет тот, который работает, который обычно будет NativePRNG. И это означает, что он берет/dev/random
начало (или использует это, если вы явно генерируете семена), а затем использует/dev/urandom
берет начало для получения следующих байтов, целых, двойных, логических значений, что у вас есть.Так как
/dev/random
это блокировка (она блокирует, пока у нее не будет достаточно энтропии в пуле энтропии), это может снизить производительность.Одним из решений этого является использование чего-то вроде hasged для генерации достаточного количества энтропии,
/dev/urandom
вместо этого используется другое решение . Хотя вы можете установить это для всего jvm, лучшим решением будет сделать это для этого конкретного случаяSecureRandom
, используяSecureRandom random = SecureRandom.getInstance("NativePRNGNonBlocking")
. Обратите внимание, что этот метод может генерировать исключение NoSuchAlgorithmException, если NativePRNGNonBlocking, поэтому будьте готовы к откату до значения по умолчанию.Также обратите внимание, что в других системах * nix
/dev/urandom
может вести себя по-разному ./dev/urandom
Достаточно ли случайно?Обычная мудрость гласит, что
/dev/random
это достаточно случайно. Однако некоторые голоса отличаются. В «Правильном способе использования SecureRandom» и «Мифах о / dev / urandom» утверждается, что/dev/urandom/
это так же хорошо.Пользователи стека информационной безопасности согласны с этим . В принципе, если вам нужно спросить,
/dev/urandom
это хорошо для вашей цели.источник
Я сам не сталкивался с этой проблемой, но при запуске программы создаю поток, который сразу же пытается создать начальное число, а затем умирает. Метод, который вы вызываете случайным образом, присоединится к этому потоку, если он жив, поэтому первый вызов блокируется только в том случае, если он происходит очень рано при выполнении программы.
источник
Мой опыт был только с медленной инициализацией PRNG, а не с генерацией случайных данных после этого. Попробуйте более активную стратегию инициализации. Поскольку создавать их дорого, относитесь к ним как к одиночке и используйте один и тот же экземпляр. Если для одного экземпляра слишком много конфликтов потоков, объедините их в пул или сделайте их локальными.
Не идите на компромисс по генерации случайных чисел. Слабость там ставит под угрозу всю вашу безопасность.
Я не вижу много генераторов на основе атомного распада COTS, но есть несколько планов для них, если вам действительно нужно много случайных данных. Один сайт, на котором всегда есть интересные вещи, включая HotBits, это Fourmilab Джона Уокера.
источник
SecureRandom
него несколько раз менялся за последние 10 лет в процессе сбора энтропии.SecureRandom
все еще является проблемой, но низкая энтропия в системе всегда будет проблемой. Использование синглтона создаст сильно связанный код, который является анти-паттерном дизайна. Поэтому его следует использовать с особой осторожностью; вам, вероятно, придется обратить все ссылки в коде, если вы решите проблему.Похоже, вы должны быть более четкими в своих требованиях к ГСЧ. Самое сильное криптографическое требование ГСЧ (насколько я понимаю) должно заключаться в том, что даже если вы знаете алгоритм, используемый для их генерации, и знаете все ранее сгенерированные случайные числа, вы не сможете получить какую-либо полезную информацию о любом из случайных чисел, сгенерированных в будущее, не тратя непрактичное количество вычислительной мощности.
Если вам не нужна эта полная гарантия случайности, вероятно, существуют соответствующие компромиссы производительности. Я склонен согласиться с ответом Дэна Дайера об AESCounterRNG от Uncommons-Maths или Fortuna (одним из его авторов является Брюс Шнайер, эксперт по криптографии). Я никогда не использовал ни один, но идеи кажутся авторитетными на первый взгляд.
Я думаю, что в что если бы вы могли генерировать начальное случайное начальное число периодически (например, один раз в день или час или что-то еще), вы могли бы использовать быстрый потоковый шифр для генерации случайных чисел из последовательных фрагментов потока (если потоковый шифр использует XOR, тогда просто передать поток нулей или получить биты XOR напрямую). ECRYPT's eStreamПроект содержит много полезной информации, включая показатели производительности. Это не будет поддерживать энтропию между моментами времени, когда вы его пополняете, поэтому, если кто-то знает одно из случайных чисел и алгоритм, который вы использовали, технически, возможно, с большой вычислительной мощностью, сломать потоковый шифр и угадать его внутреннее состояние, чтобы иметь возможность предсказывать будущие случайные числа. Но вам придется решить, достаточно ли этого риска и его последствий, чтобы оправдать затраты на поддержание энтропии.
Изменить: вот некоторые заметки о криптографии курса по ГСЧ, которые я нашел в сети, которые выглядят очень актуальными для этой темы.
источник
Если ваше оборудование поддерживает это, попробуйте использовать Java RdRand Utility, автором которой я являюсь.
Он основан на
RDRAND
инструкциях Intel и примерно в 10 раз быстрее, чемSecureRandom
проблемы с пропускной способностью при реализации больших объемов.Обратите внимание, что эта реализация работает только на тех CPU, которые предоставляют инструкцию (т.е. когда установлен
rdrand
флаг процессора). Вам нужно явно создать его экземпляр с помощьюRdRandRandom()
конструктора; никаких конкретныхProvider
не было реализовано.источник
RDRAND
это хороший источник, но это немного ненадежно. Это определенно должен быть один вклад многих в коллекционера (без обид Дэвид Джонстон).Еще нужно обратить внимание на свойство securerandom.source в файле lib / security / java.security.
Использование / dev / urandom может быть выигрыш в производительности, а не / dev / random. Помните, что если важно качество случайных чисел, не идите на компромисс, который нарушает безопасность.
источник