SecureRandom: init один раз или каждый раз, когда это необходимо? - PullRequest
20 голосов
/ 17 ноября 2008

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

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

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

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

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

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

Ответы [ 7 ]

13 голосов
/ 19 июля 2010

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

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

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

В блоге Justice League есть отличные отзывы об этом.

10 голосов
/ 17 ноября 2008

В отличие от класса java.util.Random, класс java.security.SecureRandom должен выдавать недетерминированный вывод при каждом вызове.

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

Итак, с точки зрения обычной хорошей практики кодирования, зачем создавать слишком много экземпляров, когда это происходит?

4 голосов
/ 20 августа 2009

Каждое поколение SecureRandom отбирается из некоторого энтропийного пула. В зависимости от используемой ОС, это может быть пул энтропии, поддерживаемый ОС, такой как /dev/random в Linux, или что-то, что JVM создает. В некоторых более ранних реализациях Sun JVM использовала для порождения нескольких потоков и использования их временных данных для создания начального числа.

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

Возможно, вы захотите создать оболочку для экземпляра SecureRandom, которая будет подсчитывать количество байтов, извлеченных при вызовах nextBytes или generateSeed, а после количества байтов повторно заполнить внутренний экземпляр SecureRandom с помощью системной энтропии. бассейн.

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

4 голосов
/ 17 ноября 2008

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

3 голосов
/ 17 ноября 2008

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

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

Из этого не ясно, каково реальное ожидание - RFC 1750 подробно описывает использование аппаратного обеспечения для улучшения генерации случайных чисел, но Javadocs говорят: «Следовательно, требуется, чтобы исходный материал был непредсказуемым», что может показаться противоречащим это.

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

1 голос
/ 17 ноября 2008

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

0 голосов
/ 17 ноября 2008

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

...