Давайте поиграем в компьютерный покер, только вы, я и сервер, которому мы оба доверяем. Сервер использует генератор псевдослучайных чисел, который инициализируется 32-битным начальным числом прямо перед началом игры. Таким образом, существует около четырех миллиардов возможных колод.
У меня в руке пять карт - очевидно, мы не играем в Техасский Холдем. Предположим, карты раздаются одному мне, одному вам, одному мне, одному вам и так далее. Итак, у меня в колоде первая, третья, пятая, седьмая и девятая карты.
Ранее я запускал генератор псевдослучайных чисел четыре миллиарда раз, по одному разу с каждым начальным числом, и записывал первую карту, сгенерированную для каждого, в базу данных. Предположим, моя первая карта - Пиковая дама. Это показывает только одну карту в каждой из 52 возможных колод, поэтому мы сократили количество возможных колод с четырех миллиардов до примерно 80 миллионов или около того.
Предположим, моя вторая карта - это три сердца. Теперь я использую свой RNG еще 80 миллионов раз, используя 80 миллионов семян, которые в качестве первого числа дают пиковую даму. Это займет у меня пару секунд. Я записываю все колоды, которые производят три червы, в качестве третьей карты - второй карты в моей руке. Это опять-таки только около 2% колод, так что теперь мы сократили до 2 миллионов колод.
Предположим, третья карта в моей руке - это 7 треф. У меня есть база данных с 2 миллионами семян, которые раздают мои две карты; Я использую свой RNG еще 2 миллиона раз, чтобы найти 2% из тех колод, которые производят 7 треф в качестве третьей карты, и у нас осталось всего 40 тысяч колод.
Вы видите, как это происходит. Я запускаю свой RNG 40000 раз, чтобы найти все семена, которые дают мою четвертую карту, и это приводит нас к 800 колодам, а затем пробую еще 800 раз, чтобы получить ~ 20 семян, которые дают мою пятую карту, и теперь я просто сгенерируйте эти двадцать колод карт, и я знаю, что у вас есть одна из двадцати возможных рук. Более того, я очень хорошо представляю, что буду рисовать дальше.
Теперь вы понимаете, почему важна истинная случайность? Как вы описываете это, вы думаете, что распределение важно, но распределение не делает процесс случайным. Непредсказуемость - это то, что делает процесс случайным.
ОБНОВИТЬ
Исходя из (теперь удаленных из-за их неконструктивного характера) комментариев, по крайней мере 0,3% людей, которые читали это, смущены моей точкой зрения. Когда люди выступают против точек я не сделал, или хуже, утверждают , для точек , которые я сделал сделать на том , что я не делал их, то я знаю , что мне нужно более четко и тщательно объяснить.
Похоже, что в распространении слов возникает определенная путаница, поэтому я хочу аккуратно назвать употребления.
Вопросы под рукой:
- Чем отличаются псевдослучайные числа и действительно случайные числа?
- Почему разница важна?
- Различия имеют какое-то отношение к распределению выхода PRNG?
Давайте начнем с рассмотрения идеального способа создания случайной колоды карт для игры в покер. Затем мы увидим, как другие методы для генерации колод отличаются, и если это возможно, чтобы воспользоваться этим различием.
Давайте начнем с предположения, что у нас есть волшебная коробка с надписью TRNG
. В качестве входных данных мы даем ему целое число n, большее или равное единице, а в качестве выходных данных оно дает нам действительно случайное число от одного до n включительно. Вывод этого поля совершенно непредсказуем (если ему дано число, отличное от одного), и любое число от одного до n столь же вероятно, как и другое; то есть сказать , что распределение является равномерным . (Существуют и другие более сложные статистические проверки случайности, которые мы могли бы выполнить; я игнорирую этот момент, поскольку он не соответствует моему аргументу. Предполагается, что TRNG является совершенно статистически случайным по предположению.)
Начнем с колоды карт без перетасовки. Мы просим поле для числа от одного до 52 - то есть TRNG(52)
. Какое бы число оно не вернуло, мы отсчитываем столько карт из нашей отсортированной колоды и удаляем эту карту. Он становится первой картой в перетасованной колоде. Затем мы просим TRNG(51)
и делаем то же самое, чтобы выбрать вторую карту, и так далее.
Еще один способ взглянуть на это: есть 52! = 52 x 51 x 50 ... x 2 x 1 возможных колод, что примерно равно 2 226 . Мы выбрали один из них поистине наугад.
Теперь мы сдаем карты. Когда я смотрю на свои карты, я понятия не имею, какие у вас карты. (Помимо очевидного факта, что у вас нет ни одной из моих карт.) Это могут быть любые карты с равной вероятностью.
Итак, позвольте мне убедиться, что я объясню это ясно. У нас есть равномерное распределение каждого отдельного выхода TRNG(n)
; каждый выбирает число от 1 до n с вероятностью 1 / n. Кроме того, результатом этого процесса является то, что мы выбрали один из 52! возможные палубы с вероятностью 1/52 !, поэтому распределением по множеству возможных колод являются также равномерной.
Хорошо.
Теперь давайте предположим, что у нас есть менее волшебный ящик с надписью PRNG
. Прежде чем вы сможете использовать его, он должен быть заполнен 32-разрядным беззнаковым номером.
В сторону: почему 32 ? Разве он не может быть заполнен 64- или 256- или 10000-битным числом? Конечно. Но (1) на практике большинство готовых PRNG засевается 32-битным числом, и (2) если у вас есть 10000 бит случайности для создания начального числа, тогда почему вы вообще используете PRNG? У вас уже есть источник 10000 бит случайности!
В любом случае, вернемся к тому, как работает PRNG: после того, как он посеян, вы можете использовать его так же, как и вы TRNG
. То есть вы передаете ему число n, и оно возвращает число от 1 до n включительно. Более того, распределение этого выхода более или менее равномерно . То есть, когда мы запрашиваем PRNG
число от 1 до 6, мы получаем 1, 2, 3, 4, 5 или 6 каждый примерно одну шестую часть времени, независимо от того, каким было семя.
Я хочу подчеркнуть этот момент несколько раз, потому что он, похоже, сбивает с толку некоторых комментаторов. Распределение PRNG является равномерным, по крайней мере, двумя способами. Сначала предположим, что мы выбрали какое-то конкретное семя. Мы ожидаем, что последовательность PRNG(6), PRNG(6), PRNG(6)...
в миллион раз даст равномерное распределение чисел от 1 до 6. И во-вторых, если мы выберем миллион разных семян и вызовем PRNG(6)
один раз для каждого семени, мы снова ожидаем равномерное распределение чисел от 1 до 6. Единообразие PRNG в любой из этих операций не имеет отношения к описываемой мной атаке .
Этот процесс называется псевдослучайным, поскольку поведение блока на самом деле полностью детерминировано; он выбирает один из 2 32 возможных вариантов поведения на основе начального числа. То есть, как только он будет посеян, он PRNG(6), PRNG(6), PRNG(6), ...
создает последовательность чисел с равномерным распределением, но эта последовательность полностью определяется начальным числом . Для данной последовательности вызовов, скажем, PRNG (52), PRNG (51) ... и т. Д., Существует только 2 32 возможных последовательности. Семя по сути выбирает, какое мы получим.
Для создания колоды сервер теперь генерирует начальное число. (Как? Мы вернемся к этому вопросу.) Затем они звонят PRNG(52)
, PRNG(51)
и так далее , чтобы создать палубу, подобную раньше.
Эта система подвержена атаке, которую я описал. Чтобы атаковать сервер, мы сначала заблаговременно собираем нашу собственную копию коробки с 0, запрашиваем PRNG(52)
и записываем ее. Затем мы перезапускаем с 1, просим PRNG(52)
и записываем это, вплоть до 2 32 -1.
Теперь покерный сервер, который использует PRNG для генерации колод, должен каким-то образом генерировать начальное число. Неважно, как они это делают. Они могли бы позвонить, TRNG(2^32)
чтобы получить действительно случайное семя. Или они могли бы взять текущее время как семя, которое вряд ли случайно; Я знаю, сколько сейчас времени, столько же, сколько и тебе. Суть моей атаки в том, что это не имеет значения, потому что у меня есть база данных . Когда я вижу свою первую карту, я могу уничтожить 98% возможных семян. Когда я вижу свою вторую карту, я могу убрать на 98% больше и так далее, пока в конечном итоге не смогу добраться до горстки возможных семян и с высокой вероятностью узнать, что у вас в руке.
Теперь, опять же, я хочу подчеркнуть, что предположение здесь состоит в том, что если бы мы звонили PRNG(6)
миллион раз, мы получали бы каждое число примерно в одну шестую времени . Это распределение (более или менее) равномерное , и если однородность этого распределения - все, что вас волнует , это нормально. Суть вопроса заключалась в том, есть ли что-то еще, о PRNG(6)
чем мы заботимся? и ответ да . Мы также заботимся о непредсказуемости .
Другой способ взглянуть на проблему состоит в том, что, хотя распределение миллиона вызовов PRNG(6)
может быть нормальным, поскольку PRNG выбирает только из 32 возможных вариантов поведения, он не может генерировать все возможные колоды. Он может генерировать только 2 32 из 2 226 возможных колод; крошечная фракция. Так что распределение по множеству всех колод очень плохое. Но опять же, фундаментальная атака здесь основана на нашей способности успешно предсказывать прошлое и будущее поведение на PRNG
основе небольшой выборки его результатов.
Позвольте мне сказать это в третий или четыре раза, чтобы убедиться, что это входит. Здесь есть три распределения. Во-первых, распределение процесса, который производит случайное 32-разрядное начальное число. Это может быть совершенно случайным, непредсказуемым и равномерным, и атака все равно будет работать . Во-вторых, раздача миллиона звонков PRNG(6)
. Это может быть совершенно равномерным, и атака все равно будет работать. В-третьих, распределение колод, выбранных псевдослучайным процессом, который я описал. Это распределение крайне плохое; только небольшая часть возможных колод IRL может быть выбрана. Атака зависит от предсказуемости поведения PRNG, основанного на частичном знании его выхода .
ASIDE: эта атака требует, чтобы злоумышленник знал или мог угадать, какой именно алгоритм используется PRNG. Реалистично это или нет, остается открытым вопросом. Однако при разработке системы безопасности вы должны спроектировать ее защищенной от атак, даже если злоумышленник знает все алгоритмы в программе . Другими словами, часть системы безопасности, которая должна оставаться секретной, чтобы система была защищенной, называется «ключом». Если ваша система в своей безопасности зависит от алгоритмов, которые вы используете в качестве секрета, тогда ваш ключ содержит эти алгоритмы . Это чрезвычайно слабая позиция, чтобы быть в!
Двигаемся дальше.
Теперь давайте предположим, что у нас есть третья волшебная коробка с надписью CPRNG
. Это криптостойкая версия PRNG
. Требуется 256-разрядное начальное число, а не 32-разрядное начальное число. Он разделяет со PRNG
свойством, которое семя выбирает из одного из 2 256 возможных вариантов поведения. И, как и на других наших машинах, он обладает свойством, состоящим в том, что большое количество вызовов CPRNG(n)
приводит к равномерному распределению результатов между 1 и n: каждый происходит 1 / n времени. Можем ли мы провести нашу атаку против этого?
Наша первоначальная атака требует, чтобы мы сохранили 2 32 отображения из семян в PRNG(52)
. Но 2 256 - намного большее число; Совершенно невозможно выполнить CPRNG(52)
это много раз и сохранить результаты.
Но предположим, что есть какой-то другой способ извлечь ценность CPRNG(52)
из этого факта о семени? До сих пор мы были довольно глупы, просто перебирая все возможные комбинации. Можем ли мы заглянуть внутрь волшебной коробки, выяснить, как она работает, и вывести факты о семени на основе результатов?
Нет. Детали слишком сложны для объяснения, но CPRNG продуманно спроектированы так, что невозможно вывести какой-либо полезный факт о семени из первого вывода CPRNG(52)
или из любого подмножества вывода, независимо от его размера .
Хорошо, теперь давайте предположим, что сервер использует CPRNG
для создания колод. Это нуждается в 256-битном семени. Как он выбирает это семя? Если он выбирает какое-либо значение, которое злоумышленник может предсказать, то внезапно атака снова становится жизнеспособной . Если мы сможем определить, что из 2 256 возможных семян, только четыре миллиарда из них будут выбраны сервером, то мы вернемся к делу . Мы можем провести эту атаку снова, обращая внимание только на небольшое количество семян, которые могут быть сгенерированы.
Поэтому сервер должен выполнить работу, чтобы обеспечить равномерное распределение 256-битного числа, то есть каждое возможное начальное число выбирается с вероятностью 1/2 256 . По сути, сервер должен вызывать, TRNG(2^256)-1
чтобы создать начальное число для CPRNG
.
Что если я смогу взломать сервер и заглянуть в него, чтобы увидеть, какое семя было выбрано? В этом случае злоумышленник знает полное прошлое и будущее CPRNG . Автор сервера должен остерегаться этой атаки! (Конечно, если я смогу успешно провести эту атаку, то, вероятно, я также могу просто перевести деньги на свой банковский счет напрямую, так что, возможно, это не так уж и интересно. действительно случайное 256-битное число чертовски сложно угадать.)
Возвращаясь к моему более раннему вопросу о глубокой защите: 256-битное начальное число является ключом к этой системе безопасности. Идея CPRNG состоит в том, что система защищена, пока ключ защищен ; даже если известны все другие факты об алгоритме, пока вы можете держать ключ в секрете, карты противника непредсказуемы.
Итак, зерно должно быть как секретным, так и равномерно распределенным, потому что, если это не так, мы можем провести атаку. Предполагается, что распределение выходов CPRNG(n)
является равномерным. Как насчет распределения по множеству всех возможных колод?
Вы можете сказать: есть 2 256 возможных последовательностей, выведенных CPRNG, но есть только 2 226 возможных колод. Поэтому существует больше возможных последовательностей, чем колод, так что мы в порядке; каждая возможная колода IRL теперь (с высокой вероятностью) возможна в этой системе. И это хороший аргумент, кроме ...
2 226 - это всего лишь приближение 52 !. Разделите это. 2 256/52 ! не может быть целым числом, потому что, с одной стороны, 52! делится на 3, но нет степени двойки! Поскольку теперь это не целое число, у нас есть ситуация, когда все колоды возможны , но некоторые колоды более вероятны, чем другие .
Если это не ясно, рассмотрите ситуацию с меньшими числами. Предположим, у нас есть три карты, A, B и C. Предположим, мы используем PRNG с 8-битным начальным числом, поэтому существует 256 возможных начальных чисел. Есть 256 возможных выходов в PRNG(3)
зависимости от начального числа; невозможно, чтобы одна треть из них была A, треть из них - B, а треть - C, потому что 256 не делится поровну на 3. Должен быть небольшой уклон к одному из них.
Аналогично, 52 не делится поровну на 2 256 , поэтому должен быть некоторый уклон в сторону некоторых карт в качестве первой выбранной карты и уклон в сторону от других.
В нашей оригинальной системе с 32-битным начальным числом было огромное смещение, и подавляющее большинство возможных колод никогда не создавалось. В этой системе могут быть изготовлены все колоды, но распределение колод все еще некорректно . Некоторые колоды чуть более вероятны, чем другие.
Теперь вопрос: у нас есть атака, основанная на этом недостатке? и ответ на практике, вероятно, нет . CPRNG разработаны так, что если начальное число действительно случайное, то в вычислительном отношении невозможно определить разницу между CPRNG
и TRNG
.
Хорошо, давайте подведем итоги.
Чем отличаются псевдослучайные числа и действительно случайные числа?
Они отличаются уровнем предсказуемости, которую они демонстрируют.
- Поистине случайные числа непредсказуемы.
- Все псевдослучайные числа предсказуемы, если начальное число может быть определено или угадано.
Почему разница важна?
Потому что есть приложения, в которых безопасность системы зависит от непредсказуемости .
- Если для выбора каждой карты используется TRNG, то система недоступна.
- Если для выбора каждой карты используется CPRNG, то система безопасна, если начальное число непредсказуемо и неизвестно.
- Если используется обычный PRNG с небольшим начальным пространством, то система не защищена независимо от того, является ли начальное число непредсказуемым или неизвестным; достаточно малое начальное пространство подвержено атакам грубой силы, которые я описал.
Различие имеет какое-то отношение к распределению выхода PRNG?
Равномерность распределения или их из- за отсутствия отдельных вызовов к RNG(n)
не относится к атакам , которые я описал.
Как мы уже видели, и a, PRNG
и CPRNG
дают плохие распределения вероятности выбора какой-либо отдельной колоды из всех возможных колод. PRNG
Значительно хуже, но у обоих есть проблемы.
Еще один вопрос:
Если TRNG намного лучше, чем CPRNG, что, в свою очередь, намного лучше, чем PRNG, почему кто-то использует CPRNG или PRNG?
Две причины.
Первый: расход. TRNG стоит дорого . Генерировать действительно случайные числа сложно. CPRNG дают хорошие результаты для произвольно большого количества вызовов с одним вызовом TRNG для начального числа. Недостатком является то, что вы должны держать это семя в секрете .
Второе: иногда нам нужна предсказуемость, и все, что нас волнует, это хорошее распределение. Если вы генерируете «случайные» данные в качестве входных данных программы для набора тестов, и это показывает ошибку, было бы хорошо, если запуск набора тестов снова приведет к ошибке!
Я надеюсь, что теперь это намного яснее.
Наконец, если вам понравилось это, то вы могли бы получить дальнейшее чтение на тему случайности и перестановок: