Я хочу использовать /dev/random
или /dev/urandom
в C. Как мне это сделать? Я не знаю, как я могу справиться с ними в C, если кто-то знает, пожалуйста, скажите мне, как это сделать. Спасибо.
Как использовать /dev/random или urandom в C?
Ответы (5)
Как правило, лучше избегать открытия файлов для получения случайных данных из-за большого количества точек отказа в процедуре.
В последних дистрибутивах Linux для получить криптозащищенные случайные числа, и он не может дать сбой, если GRND_RANDOM
не указан как флаг, а объем чтения составляет не более 256 байт.
По состоянию на октябрь 2017 года OpenBSD, Darwin и Linux (с -lbsd
) теперь имеют реализацию arc4random
, который является криптозащищенным и не может дать сбой. Это делает его очень привлекательным вариантом:
char myRandomData[50];
arc4random_buf(myRandomData, sizeof myRandomData); // done!
В противном случае вы можете использовать случайные устройства, как если бы они были файлами. Вы читаете их и получаете случайные данные. Здесь я использую open
/read
, но fopen
/fread
тоже подойдет.
int randomData = open("/dev/urandom", O_RDONLY);
if (randomData < 0)
{
// something went wrong
}
else
{
char myRandomData[50];
ssize_t result = read(randomData, myRandomData, sizeof myRandomData);
if (result < 0)
{
// something went wrong
}
}
Вы можете прочитать гораздо больше случайных байтов, прежде чем закрыть файловый дескриптор. /dev/urandom никогда не блокируется и всегда заполняет столько байтов, сколько вы запросили, если только системный вызов не прерывается сигналом. Он считается криптографически безопасным и должен быть вашим случайным устройством.
/dev/random более привередлив. На большинстве платформ он может возвращать меньше байтов, чем вы запросили, и может блокироваться, если доступно недостаточно байтов. Это делает историю обработки ошибок более сложной:
int randomData = open("/dev/random", O_RDONLY);
if (randomData < 0)
{
// something went wrong
}
else
{
char myRandomData[50];
size_t randomDataLen = 0;
while (randomDataLen < sizeof myRandomData)
{
ssize_t result = read(randomData, myRandomData + randomDataLen, (sizeof myRandomData) - randomDataLen);
if (result < 0)
{
// something went wrong
}
randomDataLen += result;
}
close(randomData);
}
/dev/urandom
. Если он был достаточно посеян один раз, он выдаст неограниченное количество псевдослучайных чисел, подходящих для использования в криптографии. Беспокоит только то, что первоначального посева может быть недостаточно. Менее случайная проблема применяется только в некоторых редких особых случаях, например, в начале процесса загрузки на встроенных устройствах или клонах виртуальных машин.
- person CodesInChaos; 27.10.2013
/dev/urandom
подходит.
- person CodesInChaos; 27.10.2013
read
, чтобы включить его. Я бы сказал, что в целом вы всегда должны проверять наличие ошибок. Кроме того, если безопасность вашего приложения критична, рекомендуется проверить, является ли файл символьным устройством.
- person zneak; 02.01.2015
randomData
, кроме его закрытия. Вы уверены, что это не должно читаться read(randomData ...
? Показывает важность именования.
- person BoppreH; 01.08.2015
/dev/random
, и /dev/urandom
сидят за одним и тем же CSPRNG. (Ваш совет выбрать /dev/urandom
вместо /dev/random
остается в силе.)
- person Sebastian; 23.03.2017
Есть другие точные ответы выше. Однако мне нужно было использовать поток FILE*
. Вот что я сделал...
int byte_count = 64;
char data[64];
FILE *fp;
fp = fopen("/dev/urandom", "r");
fread(&data, 1, byte_count, fp);
fclose(fp);
fread((char*)(&myInt),sizeof(myInt),1,fp)
- person Azeem Bande-Ali; 25.05.2013
byte_count
? Он не используется.
- person CalculatorFeline; 10.08.2017
Просто откройте файл для чтения, а затем прочитайте данные. В C++11 вы можете использовать std::random_device
, который обеспечивает межплатформенный доступ к таким устройствам.
std::random_device
не попал в стандарт 2011 года. Он присутствует в проекте N3797.
- person Keith Thompson; 02.01.2015
std::random_device
попал в С++11 в конце концов.
- person legends2k; 26.06.2015
std::random_device
находится на C ++, а не на C, и ОП спросил, как использовать /dev/random
или /dev/urandom
, а не как использовать std::random_device
, хотя это хороший выбор для использования std::random_device
и у него есть преимущества, это просто не то, о чем просил ОП
- person Nfagie Yansaneh; 08.08.2017
Zneak верен на 100%. Также очень распространено чтение буфера случайных чисел, который немного больше, чем вам нужно при запуске. Затем вы можете заполнить массив в памяти или записать их в свой собственный файл для последующего повторного использования.
Типичная реализация вышеизложенного:
typedef struct prandom {
struct prandom *prev;
int64_t number;
struct prandom *next;
} prandom_t;
Это становится более или менее похоже на ленту, которая просто продвигается вперед и может быть волшебным образом пополнена другим потоком по мере необходимости. Существует множество службы, которые предоставляют большие дампы файлов, содержащие только случайные числа, которые генерируются гораздо более сильными генераторами, такими как:
- Радиоактивный распад
- Оптическое поведение (фотоны попадают в полупрозрачное зеркало)
- Атмосферный шум (не такой сильный, как выше)
- Фермы пьяных обезьян, печатающих на клавиатуре, и двигающихся мышей (шучу)
Не используйте «предварительно упакованную» энтропию для криптографических сидов, если это не само собой разумеющееся. Эти наборы подходят для симуляций, но совсем не подходят для генерации ключей и тому подобного.
Не заботясь о качестве, если вам нужно много чисел для чего-то вроде моделирования Монте-Карло, гораздо лучше иметь их доступными таким образом, чтобы не вызвать блокировку read().
Однако помните, что случайность числа столь же детерминирована, как и сложность, связанная с его генерацией. /dev/random
и /dev/urandom
удобны, но не так надежны, как использование HRNG (или загрузка большого дампа из HRNG). Также стоит отметить, что /dev/random
пополняется с помощью энтропии, поэтому он может блокироваться довольно долго. пока в зависимости от обстоятельств.
ответ zneak охватывает это просто, однако на самом деле все сложнее. Например, вам нужно подумать, действительно ли /dev/{u}random является устройством случайных чисел. Такой сценарий может возникнуть, если ваша машина была скомпрометирована, а устройства заменены символическими ссылками на /dev/zero или разреженный файл. Если это произойдет, случайный поток теперь полностью предсказуем.
Самый простой способ (по крайней мере, в Linux и FreeBSD) — выполнить вызов ioctl на устройстве, который будет успешным, только если устройство является генератором случайных чисел:
int data;
int result = ioctl(fd, RNDGETENTCNT, &data);
// Upon success data now contains amount of entropy available in bits
Если это выполняется до первого считывания случайного устройства, то есть честная ставка на то, что у вас есть случайное устройство. Так что ответ @zneak лучше расширить:
int randomData = open("/dev/random", O_RDONLY);
int entropy;
int result = ioctl(randomData, RNDGETENTCNT, &entropy);
if (!result) {
// Error - /dev/random isn't actually a random device
return;
}
if (entropy < sizeof(int) * 8) {
// Error - there's not enough bits of entropy in the random device to fill the buffer
return;
}
int myRandomInteger;
size_t randomDataLen = 0;
while (randomDataLen < sizeof myRandomInteger)
{
ssize_t result = read(randomData, ((char*)&myRandomInteger) + randomDataLen, (sizeof myRandomInteger) - randomDataLen);
if (result < 0)
{
// error, unable to read /dev/random
}
randomDataLen += result;
}
close(randomData);
Блог Insane Coding осветил это, и другие подводные камни не так давно; Настоятельно рекомендую прочитать всю статью. Я должен отдать должное тому, откуда было взято это решение.
Отредактировано для добавления (2014-07-25)...
Кстати, прошлой ночью я прочитал это как часть усилия LibReSSL, Linux, похоже, получает GetRandom() системный вызов. На момент написания статьи неизвестно, когда он будет доступен в общем выпуске ядра. Однако это был бы предпочтительный интерфейс для получения криптографически безопасных случайных данных, поскольку он устраняет все ловушки, которые предоставляет доступ через файлы. См. также возможную реализацию LibReSSL.
getrandom()
был представлен в ядре 3.17. Так что в стоковой Ubuntu 16.04 его нет по состоянию на 17 января 2018 года. Запустите uname -a
в терминале, чтобы проверить версию вашего ядра.
- person erapert; 17.01.2018