Как использовать /dev/random или urandom в C?
Я хочу использовать /dev/random
или /dev/urandom
в C. Как я могу это сделать? Я не знаю, как я могу справиться с ними в C, если кто-то знает, пожалуйста, скажите мне, как. Спасибо.
5 ответов:
в общем, лучше избегать открытия файлов для получения случайных данных, из-за того, сколько точек отказа есть в процедуре.
в последних дистрибутивах Linux,
getrandom
системный вызов может быть использован для получения криптозащищенных случайных чисел, и он не может потерпеть неудачу если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); }
есть и другие точные ответы выше. Мне нужно было использовать
FILE*
хотя поток,. Вот что я сделал...int byte_count = 64; char data[64]; FILE *fp; fp = fopen("/dev/urandom", "r"); fread(&data, 1, byte_count, fp); fclose(fp);
просто откройте файл для чтения, а затем считайте данные. В C++11, вы можете использовать
std::random_device
, которая обеспечивает кросс-платформенный доступ к таким устройствам.
Zneak 100% правильно. Его также очень часто читать буфер случайных чисел, который немного больше, чем то, что вам нужно при запуске. Затем вы можете заполнить массив в памяти или записать их в свой собственный файл для последующего повторного использования.
типичная реализация выше:
typedef struct prandom { struct prandom *prev; int64_t number; struct prandom *next; } prandom_t;
это становится более или менее похожим на ленту, которая просто продвигается, которая может быть волшебным образом пополнена другой нитью по мере необходимости. Есть и много of услуги которые обеспечивают большие дампы файлов только случайных чисел, которые генерируются с гораздо более сильными генераторами, такими как:
- радиоактивного распада
- оптическое поведение (фотоны, попадающие в полупрозрачное зеркало)
- атмосферный шум (не такой сильный, как выше)
- фермы пьяных обезьян, печатающих на клавиатурах и движущихся мышей (шутка)
не используйте "предварительно упакованные" энтропия для криптографических семян, в случае, если это не само собой разумеется. Эти наборы отлично подходят для моделирования,совсем не нормально для генерации ключей и тому подобное.
не заботясь о качестве, Если вам нужно много чисел для чего-то вроде моделирования Монте-Карло, гораздо лучше иметь их в наличии таким образом, чтобы не вызывать блокировку 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);
Безумный блог кодирования на эту тему, и другие подводные камни не так давно, я настоятельно рекомендую прочитать всю статью. Я должен отдать должное их, где это решение было вытащили оттуда.
изменить добавить (2014-07-25)...
Кстати, я читал вчера вечером, что в рамках LibReSSL усилий, Linux, кажется, получает GetRandom() syscall. Как и на момент написания, нет ни слова о том, когда он будет доступен в общем выпуске ядра. Однако это был бы предпочтительный интерфейс для получения криптографически безопасных случайных данных, поскольку он удаляет все ловушки, которые предоставляет доступ через файлы. Видеть также LibReSSL возможной реализации.