Самая быстрая реализация генератора истинных случайных чисел в C # - PullRequest
11 голосов
/ 21 марта 2009

Я читал о Random.Next () , что для «криптографически безопасного случайного числа, подходящего для создания случайного пароля» MSDN предлагает RNGCryptoServiceProvider Class

Какая скорость пенальности? Есть какой-нибудь самый быстрый способ получить истинные случайные числа?

EDIT: С Random.Next () я получаю новое случайное число. И с ...

byte[] randomNumber = new byte[1];
RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider();
Gen.GetBytes(randomNumber);
int rand = Convert.ToInt32(randomNumber[0]);

Я получаю «криптографически безопасное случайное число» Я хочу знать, является ли приведенный выше код быстрым по сравнению с "Random.Next ()" и если есть какой-то быстрый способ получить те же результаты, хорошо?

Ответы [ 8 ]

45 голосов
/ 21 марта 2009

Самый простой способ ответить на ваш вопрос - перевернуть вопрос с ног на голову.

Предположим , что реализация CryptoServiceProvider обладает всеми преимуществами. Он такой же быстрый и использует столько же памяти, сколько и Random.Next.

Тогда почему существуют обе реализации ? Почему у нас даже есть Random.Next в рамках?

Посмотрите, что мы знаем о каждой реализации. Один генерирует криптографически безопасное случайное число, другой не дает обещаний.

Что проще? Генерация случайных чисел, достаточно случайных для использования в криптографии, или генерация чисел, которые просто «выглядят» случайными, но не гарантируют что-либо еще? Если бы не было затрат, связанных с генерацией криптографически безопасных случайных чисел, то каждый генератор случайных чисел сделал бы это.

Обычно можно предположить, что стандартные функции библиотеки предназначены для того, чтобы делать то, что написано на коробке, и делать это хорошо. Random.Next предназначен для того, чтобы максимально эффективно получить следующее случайное число в последовательности псевдослучайных чисел .

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

Ваш вопрос, похоже, предполагает повреждение мозга со стороны разработчиков каркаса - что они каким-то образом разработали ненужную медленную функцию для генерации криптографически безопасных случайных чисел, даже если был более быстрый способ.

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

26 голосов
/ 21 марта 2009

Эмпирическое правило, когда речь заходит о безопасности и криптографии:

Никогда напишите свое.

Используйте стандартный способ и избегайте опасных оптимизаций.

Изменить для решения обновленного вопроса:

Используйте Random.Next, когда вам нужны статистически случайные числа, не используемые в секретном коде, и RNGCryptoServiceProvider в секретном коде. Это не так быстро, как Random.Next, но имеет приемлемую производительность. Вы должны сравнить, чтобы увидеть реальную разницу. Обычно не имеет смысла жертвовать безопасностью ради производительности.

19 голосов
/ 21 марта 2009

«Криптографически безопасное случайное число», генерируемое вашим примером кода, будет когда-либо только между 0 и 255 включительно!

Если вы хотите вернуть все возможные значения Int32, вам следует использовать 4 случайных байта. Ваш код должен выглядеть примерно так:

RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] rndBytes = new byte[4];
rng.GetBytes(rndBytes);
int rand = BitConverter.ToInt32(rndBytes, 0);

Быстрый тест на моей (старой) машине показывает, что Random.Next примерно в 200 раз быстрее, чем RNGCryptoServiceProvider.

7 голосов
/ 21 марта 2009

В первую очередь вам следует изучить основные различия между RNG , PRNG и CSPRNG .

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

5 голосов
/ 21 марта 2009

Единственный известный способ получить истинно случайные числа в аппаратном обеспечении - это медленный; если вы попытаетесь ускорить его, ваши волосы станут белыми, выпадут в пучки, и NRC отправит роботов для очистки вашей серверной комнаты.

Я нахожусь с Мехрдадом в этом: не пытайтесь свернуть свое собственное.

2 голосов
/ 29 декабря 2009

Еще один момент, который не был затронут:

PRNG будет давать предсказуемые результаты при одинаковом начальном начальном значении. CSPRNG не будет - у него нет начального значения. Это делает PRNG (в некоторой степени) пригодными для использования в алгоритмах шифрования. Два компьютера, имеющие одинаковые векторы инициализации (используемые в качестве начальных значений для одного или нескольких PRNG), могут эффективно обмениваться данными друг с другом в частном порядке, используя результат XORed байтов в виде простого текста и выходные данные использованных отобранных PNG.

Я не утверждаю, что такая реализация обязательно была бы криптографически безопасной; только то, что такая реализация потребует предсказуемости PRNG, который CSPRNG не предлагает.

2 голосов
/ 21 марта 2009

AFAIK настоящий генератор случайных чисел никогда не будет реализован в C #. Что можно сделать только с помощью аппаратного обеспечения?

2 голосов
/ 21 марта 2009

Побочным вопросом, но интересным, является использование вами «истинного» в этом вопросе. Истинные случайные числа не существуют в аппаратном или программном обеспечении. Они существуют в «реальной жизни», как радиоактивный распад или шум на линии, но не могут быть созданы программой. Поэтому, пожалуйста, обратите внимание на то, что jalf использует «псевдо», и проверьте ссылки jcinacio на википедию.

...