RAND_bytes не дает тот же результат из того же семени
Я пытаюсь запрограммировать пользовательский алгоритм генерации пары ключей RSA с использованием OpenSSL. Я использовал PKCS5_PBKDF2_HMAC_SHA1
функция для генерации семени PRNG, поэтому я использовал это семя в качестве входных данных RAND_seed.
К сожалению каждый раз, когда я звоню RAND_bytes
с одним и тем же начальным числом я получаю разные случайные числа, но это не ожидаемое поведение, потому что, как, скажем, ответ в разделе Как можно безопасно генерировать пару асимметричных ключей из короткой парольной фразы? генератор случайных чисел является детерминированным (тот же начальный и тот же выход).
Ниже приведен тестовый пример. Я объявил также постоянное семя, но поколение никогда не бывает детерминированным.
unsigned int seed = 0x00beef00;
unsigned int rnum[5];
RAND_seed(&seed, sizeof(seed));
RAND_bytes((unsigned char *)&rnum[0], sizeof(rnum));
Где ошибка?
2 ответа
Это не ошибка. Генератор случайных чисел в OpenSSL сам выполняет некоторые операции с использованием хороших источников случайности.
Таким образом, используя то же самое начальное значение в RAND_seed
не гарантирует одинаковую последовательность случайных чисел. Это хорошо, потому что делает их менее предсказуемыми и, следовательно, более безопасными.
Со страницы руководства для RAND_seed
:
#include <openssl/rand.h> void RAND_seed(const void *buf, int num); void RAND_add(const void *buf, int num, double entropy); int RAND_status(void); int RAND_event(UINT iMsg, WPARAM wParam, LPARAM lParam); void RAND_screen(void);
RAND_add()
смешиваетnum
байт вbuf
в состояние PRNG. Таким образом, если данные вbuf
непредсказуемы для противника, это увеличивает неопределенность в отношении состояния и делает выход PRNG менее предсказуемым. Подходящий ввод поступает от взаимодействия с пользователем (случайные нажатия клавиш, движения мыши) и определенных аппаратных событий.entropy
Аргумент - это (нижняя граница) оценка того, сколько случайности содержится в буфере, измеряется в байтах. Подробности об источниках случайности и о том, как оценить их энтропию, можно найти в литературе, например, RFC 1750.
RAND_add()
может вызываться с конфиденциальными данными, такими как введенные пользователем пароли. Начальные значения не могут быть восстановлены из вывода PRNG.OpenSSL гарантирует, что состояние PRNG уникально для каждого потока. В системах, которые предоставляют "/dev/urandom", устройство случайности используется для прозрачного заполнения PRNG. Однако во всех других системах приложение отвечает за заполнение PRNG путем вызова
RAND_add()
,RAND_egd(3)
или жеRAND_load_file(3)
,
RAND_seed()
эквивалентноRAND_add()
когдаnum == entropy
,
Так что если ваша система имеет /dev/urandom
, он будет использоваться в качестве начального семени для PRNG.
OpenSSL, int RAND_bytes(unsigned char *buf, int num);
пытается сделать вещи настолько случайными, насколько это возможно. Эта функция, по-видимому, вам не нужна, и вместо этого вы ищете повторяемую псевдослучайную последовательность
Но Openssl также имеет
int RAND_pseudo_bytes(unsigned char *buf, int num);
что, вероятно, то, что вы ищете, псевдо часть, чтобы дать вам повторяемую последовательность.
https://linux.die.net/man/3/rand_pseudo_bytes
Принудительно заставить RNG openssl возвращать повторяемую последовательность байтов
Кроме того, если вы делаете RSA, повторяемая случайная последовательность не так уж хороша, потому что вы ищете два больших простых числа. Выполнение большого числа PRNG, затем тестирование на простое число, вероятно, плохая идея. Половина из них будет делиться на 2!:)
Если я правильно помню, вам нужно выбрать хорошее начальное число, сделать его нечетным путем ИЛИ с 1, затем проверить на простое число, а если нет, увеличить на 4 и повторить попытку.
Найдя их, вы, вероятно, не захотите делать это снова, используя повторяющиеся байты PRNG, чтобы начать поиск.
И хотя я почти уверен, что это для учебного проекта, но если вам нужна пара ключей RSA от openssl, посмотрите