Tôi muốn sử dụng /dev/random
hoặc /dev/urandom
trong C. Làm thế nào tôi có thể làm điều đó? Tôi không biết làm thế nào tôi có thể xử lý chúng trong C, nếu ai đó biết xin vui lòng cho tôi biết làm thế nào. Cảm ơn bạn.
Tôi muốn sử dụng /dev/random
hoặc /dev/urandom
trong C. Làm thế nào tôi có thể làm điều đó? Tôi không biết làm thế nào tôi có thể xử lý chúng trong C, nếu ai đó biết xin vui lòng cho tôi biết làm thế nào. Cảm ơn bạn.
Câu trả lời:
Nói chung, tốt hơn hết là bạn nên tránh mở các tệp để lấy dữ liệu ngẫu nhiên, vì có bao nhiêu điểm lỗi trong quy trình.
Trên bản phân phối Linux gần đây, các getrandom
cuộc gọi hệ thống có thể được sử dụng để lấy số ngẫu nhiên crypto-an toàn, và nó không thể thất bại nếu GRND_RANDOM
là không quy định như một lá cờ và số lượng đọc tối đa là 256 byte.
Kể từ tháng 10 năm 2017, OpenBSD, Darwin và Linux (với -lbsd
) giờ đây đều có triển khai arc4random
bảo mật tiền điện tử và không thể thất bại. Điều đó làm cho nó trở thành một lựa chọn rất hấp dẫn:
char myRandomData[50];
arc4random_buf(myRandomData, sizeof myRandomData); // done!
Nếu không, bạn có thể sử dụng các thiết bị ngẫu nhiên như thể chúng là tệp. Bạn đọc từ chúng và bạn nhận được dữ liệu ngẫu nhiên. Tôi đang sử dụng open
/ read
ở đây, nhưng fopen
/ fread
sẽ hoạt động tốt.
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
}
}
Bạn có thể đọc nhiều byte ngẫu nhiên khác trước khi đóng trình mô tả tệp. / dev / urandom không bao giờ chặn và luôn điền vào nhiều byte như bạn yêu cầu, trừ khi cuộc gọi hệ thống bị gián đoạn bởi một tín hiệu. Nó được coi là an toàn bằng mật mã và phải là thiết bị ngẫu nhiên của bạn.
/ dev / random thì phức tạp hơn. Trên hầu hết các nền tảng, nó có thể trả về ít byte hơn bạn đã yêu cầu và nó có thể chặn nếu không có đủ byte. Điều này làm cho câu chuyện xử lý lỗi phức tạp hơn:
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
tiền điện tử bình thường là tốt.
Có những câu trả lời chính xác khác ở trên. Tuy nhiên, tôi cần sử dụng một FILE*
luồng. Đây là những gì tôi đã làm ...
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)
byte_count
? Nó không được sử dụng.
Chỉ cần mở tệp để đọc và sau đó đọc dữ liệu. Trong C ++ 11, bạn có thể muốn sử dụng std::random_device
cung cấp quyền truy cập đa nền tảng vào các thiết bị như vậy.
std::random_device
đã không lọt vào tiêu chuẩn năm 2011. Nó xuất hiện trong bản nháp N3797 .
std::random_device
std::random_device
trong C ++ chứ không phải trong C, và OP đã hỏi cách sử dụng /dev/random
hay /dev/urandom
không cách sử dụng std::random_device
mặc dù đó là một lựa chọn tốt để sử dụng std::random_device
và nó có lợi ích, nhưng đó không phải là những gì OP yêu cầu
Zneak đúng 100%. Việc đọc bộ đệm các số ngẫu nhiên lớn hơn một chút so với những gì bạn cần khi khởi động cũng rất phổ biến. Sau đó, bạn có thể điền một mảng trong bộ nhớ hoặc ghi chúng vào tệp của riêng bạn để sử dụng lại sau này.
Một cách triển khai điển hình ở trên:
typedef struct prandom {
struct prandom *prev;
int64_t number;
struct prandom *next;
} prandom_t;
Điều này ít nhiều trở nên giống như một cuộn băng chỉ tiến lên có thể được bổ sung một cách kỳ diệu bằng một sợi khác khi cần thiết. Có một nhiều của các dịch vụ cung cấp bãi tập tin lớn gì, nhưng ngẫu nhiên số được tạo ra với máy phát điện mạnh hơn rất nhiều như:
Không sử dụng entropy 'đóng gói sẵn' cho các hạt mã hóa , trong trường hợp điều đó không xảy ra mà không cần nói. Những bộ đó mô phỏng ổn, không ổn chút nào cho việc tạo ra các phím và những thứ tương tự.
Không quan tâm đến chất lượng, nếu bạn cần nhiều con số cho một thứ gì đó như mô phỏng monte carlo, thì tốt hơn nhiều là bạn nên cung cấp chúng theo cách không gây ra chặn read ().
Tuy nhiên, hãy nhớ rằng, tính ngẫu nhiên của một số cũng xác định như độ phức tạp liên quan đến việc tạo ra nó. /dev/random
và /dev/urandom
thuận tiện, nhưng không mạnh bằng sử dụng HRNG (hoặc tải xuống một kết xuất lớn từ HRNG). Cũng cần lưu ý rằng /dev/random
nạp qua entropy , vì vậy nó có thể bị chặn khá lâu tùy thuộc vào trường hợp.
Câu trả lời của zneak bao hàm nó một cách đơn giản, tuy nhiên thực tế phức tạp hơn thế. Ví dụ: bạn cần xem xét / dev / {u} random ngay từ đầu có thực sự là thiết bị số ngẫu nhiên hay không. Tình huống như vậy có thể xảy ra nếu máy của bạn đã bị xâm phạm và các thiết bị được thay thế bằng liên kết tượng trưng thành / dev / zero hoặc một tệp thưa thớt. Nếu điều này xảy ra, luồng ngẫu nhiên bây giờ hoàn toàn có thể dự đoán được.
Cách đơn giản nhất (ít nhất là trên Linux và FreeBSD) là thực hiện cuộc gọi ioctl trên thiết bị sẽ chỉ thành công nếu thiết bị là một trình tạo ngẫu nhiên:
int data;
int result = ioctl(fd, RNDGETENTCNT, &data);
// Upon success data now contains amount of entropy available in bits
Nếu điều này được thực hiện trước lần đọc đầu tiên của thiết bị ngẫu nhiên, thì có một cược công bằng rằng bạn đã có thiết bị ngẫu nhiên. Vì vậy, câu trả lời của @ zneak tốt hơn có thể được mở rộng thành:
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);
Blog Insane Coding đã đề cập đến vấn đề này và những cạm bẫy khác cách đây không lâu; Tôi thực sự khuyên bạn nên đọc toàn bộ bài báo. Tôi phải ghi công cho họ xem giải pháp này được đưa ra từ đâu.
Đã chỉnh sửa để thêm (2014-07-25) ... Thật
tình cờ, tối qua tôi đọc được rằng như một phần của nỗ lực LibReSSL , Linux dường như nhận được một syscall GetRandom () . Tại thời điểm viết bài, không có thông tin nào về thời điểm nó sẽ có trong bản phát hành chung cho nhân. Tuy nhiên, đây sẽ là giao diện ưa thích để lấy dữ liệu ngẫu nhiên an toàn bằng mật mã vì nó loại bỏ tất cả các cạm bẫy mà truy cập qua tệp cung cấp. Xem thêm LibReSSL có thể triển khai .
getrandom()
đã được giới thiệu trong kernel 3.17. Vì vậy, Ubuntu 16.04 cổ phiếu không có nó kể từ ngày 2018-01-17. Chạy uname -a
trong một thiết bị đầu cuối để kiểm tra phiên bản hạt nhân của bạn.