Подтвердить что ты не робот

SecureRandom: init один раз или каждый раз, когда это необходимо?

Наша команда использует SecureRandom для генерации списка пар ключей (SecureRandom передается в KeyPairGenerator). Мы не можем договориться о том, какой из следующих двух вариантов использовать:

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

  • Инициализировать статический экземпляр и использовать его для всех пар ключей

Какой подход вообще лучше и почему?

ДОБАВЛЕНО: Чувствуется, что второй вариант более безопасен. Но мой единственный аргумент - теоретическая атака, основанная на предположении, что псевдослучайность выводится из текущей метки времени: кто-то может видеть время создания пары ключей, угадывать временные метки в окружающем временном интервале, вычислять возможные псевдослучайные последовательности и получать ключевой материал.

ДОБАВЛЕНО: мое предположение о детерминизме, основанном на отметке времени, было неправильным. Это разница между Random и SecureRandom. Итак, похоже, что ответ: с точки зрения безопасности это не имеет большого значения.

4b9b3361

Ответ 1

В отличие от класса java.util.Random класс java.security.SecureRandom должен генерировать недетерминированный результат для каждого вызова. Это означает, что в случае java.util.Random, если вы должны воссоздать экземпляр с одним и тем же семенем каждый раз, когда вам нужно новое случайное число, вы по существу получаете одинаковый результат каждый раз. Однако SecureRandom гарантированно НЕ делает этого - поэтому создание одного экземпляра или создание нового каждый раз не влияет на случайность генерируемых случайных байтов. Итак, из простой точки зрения хорошего кодирования, зачем создавать слишком много экземпляров, когда вы это сделаете?

Ответ 2

Для SecureRandom вы хотели бы рассмотреть возможность временного повторного использования (using системной энтропии в большинстве случаев) через вызов, подобный этому:

mySecureRandom.setSeed(mySecureRandom.generateSeed(someInt));

чтобы дать потенциальному злоумышленнику что-то меньшее, чем неограниченное время, чтобы открыть ваш ключ.

Там есть отличные записи об этом обсуждении в блоге Лига правосудия.

Ответ 3

Инициализировать статический экземпляр и использовать его для всех пар ключей. Это не будет более или менее случайным.

Ответ 4

Я бы не полагался на SecureRandom, чтобы быть чем-то другим, кроме криптографически безопасного PRNG. Полная цитата, которую Gowri использует из javadocs:

Кроме того, SecureRandom должен производят недетерминированный результат и поэтому требуется, чтобы семена материал будет непредсказуемым и что вывода SecureRandom be криптографически сильные последовательности как описанный в RFC 1750: Randomness Рекомендации по безопасности.

Это менее чем понятно из этого, что такое реальное ожидание - RFC 1750 подробно описывает использование аппаратного обеспечения для увеличения генерации случайных чисел, но javadocs говорят "поэтому требуется, чтобы материал семян был непредсказуемым", что, казалось бы, противоречит это.

Самое безопасное предположение, над которым вы работаете, заключается в том, что ваша реализация SecureRandom - это просто криптографически безопасный PRNG, и поэтому ваши ключи не более безопасны, чем случайное семя, которое вы используете. Таким образом, инициализация нового SecureRandom с новым (уникальным, действительно случайным) семенем для каждого ключа будет самой безопасной ставкой.

Ответ 5

Каждое поколение SecureRandom высевается из некоторого энтропийного пула. В зависимости от используемой ОС это может быть энтропийный пул, поддерживаемый ОС, например /dev/random в Linux, или может быть чем-то, что готовит JVM. В некоторых более ранних реализациях Sun JVM используется для создания множества потоков и использования их временных данных для создания семени. Создание нового SecureRandom при каждом вызове может привести к замедлению работы приложения, поскольку создание семени может блокироваться. Лучше повторить использование статически созданного экземпляра, но обязательно переустановите его после того, как из него будет извлечено определенное количество случайных байтов. Возможно, вы захотите создать оболочку над securerandom, которая подсчитывает количество байтов, вычисленных в nextBytes или вызове generateSeed, и после нескольких байтов, повторно загружает внутренний securerandom, используя пул энтропии системы. Однако это невозможно для Java на Linux, поскольку SecureRandom вы получаете от новый SecureRandom() - это не что иное, как оболочка на /dev/random, и каждый вызов для nextBytes или generateSeed фактически истощает пул энтропий OS. В Linux и Solaris лучше использовать поставщик JCE для создания SecureRandom.

Ответ 6

Как-то должно быть достаточно. Мой опыт также заключался в том, что инициализация генераторов типа SecureRandom иногда может быть медленной (из-за того, насколько хаотично достигается), поэтому вы должны принять это во внимание.

Ответ 7

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