Làm thế nào để sử dụng / dev / random hoặc urandom trong C?


76

Tôi muốn sử dụng /dev/randomhoặc /dev/urandomtrong 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.


Kiểm tra bài viết rất nhiều thông tin này trên một số hãy cẩn thận phổ biến của việc tuyến đường này để (pseudo-) ngẫu nhiên: insanecoding.blogspot.fi/2014/05/...
appas

Câu trả lời:


107

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 getrandomcuộ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_RANDOMkhô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 arc4randombả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:

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/ freadsẽ hoạt động tốt.

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:


14
@karim: Vui lòng không bao giờ đọc tất cả các byte từ / dev / random. Đừng. Chương trình của bạn có lẽ không phải là người dùng duy nhất trên hệ thống cần các byte ngẫu nhiên.
Zan Lynx

1
@zneak, xin lỗi tôi quên rằng bài viết có thể được chỉnh sửa ở đây. Cảm ơn vì đã cho tôi biết. Sửa đổi cuối cùng của bạn chỉ thêm một kiểm tra khi đọc, thay vì một vòng lặp. Tôi đã sửa đổi nó để sử dụng một vòng lặp, vì vậy mã bây giờ sẽ chặn một cách thích hợp.
morrog

2
Người đánh giá @morrog Overeager đã từ chối nó, vì vậy tôi đã thực hiện các thay đổi theo cách thủ công. Xin lỗi bạn không được ghi nhận cho nó.
zneak

1
@CodesInChaos, tôi đang trích dẫn trang web Linux : "Nếu bạn không chắc mình nên sử dụng / dev / random hay / dev / urandom, thì có lẽ bạn muốn sử dụng cái sau. Theo quy tắc chung, / dev / urandom nên được sử dụng cho mọi thứ ngoại trừ các khóa GPG / SSL / SSH tồn tại lâu dài. "
zneak

2
@zneak Nhấn mạnh vào việc tồn tại lâu dài vì đối với những người đó, việc hoang tưởng thêm không có hại gì. Đối với sử dụng /dev/urandomtiền điện tử bình thường là tốt.
CodesInChaos

21

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 ...


1
Một int có thể được đọc trực tiếp bằng cách chuyển con trỏ int sang con trỏ char. fread((char*)(&myInt),sizeof(myInt),1,fp)
Azeem Bande-Ali

@ AzeemBande-Ali: Tại sao bạn không sử dụng fread ((int *) (& myInt), sizeof (myInt), 1, fp) để thay thế? Ý tôi là một cast thành int *?
Larry

4
Trong cả hai trường hợp không nên sử dụng ép kiểu trong mã C, fread () lấy giá trị void *, vì vậy chỉ cần thực hiện fread (& myInt, ...);
nos

Tại sao bạn cần byte_count? Nó không được sử dụng.
Máy

@CalculatorFeline Số lượng byte_count ở đây hơi khó hiểu, có thể ban đầu muốn mỗi chỉ mục có cùng độ dài byte, nhưng điều này không thể làm được ...
LinconFive

17

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_devicecung cấp quyền truy cập đa nền tảng vào các thiết bị như vậy.


Có vẻ như nó 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 .
Keith Thompson

2
Có vẻ như cuối cùng đã làm cho nó trở thành C ++ 11. std::random_device
Legends2k

1
Vấn đề là std::random_devicetrong C ++ chứ không phải trong C, và OP đã hỏi cách sử dụng /dev/randomhay /dev/urandomkhông cách sử dụng std::random_devicemặc dù đó là một lựa chọn tốt để sử dụng std::random_devicevà nó có lợi ích, nhưng đó không phải là những gì OP yêu cầu
Nfagie Yansaneh

8

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:

Đ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ư:

  • Phân rã phóng xạ
  • Hành vi quang học (các photon va vào một gương bán trong suốt)
  • Tiếng ồn trong khí quyển (không mạnh như ở trên)
  • Trang trại của những con khỉ say sưa gõ bàn phím và di chuyển chuột (đùa)

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/dev/urandomthuậ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.


2
Tải xuống "tập tin lớn không có gì khác ngoài số ngẫu nhiên" là lời khuyên khủng khiếp cho các mục đích mật mã. Đó là yêu cầu người khác cung cấp hạt giống cho các chức năng của bạn và những dịch vụ đó dường như chuyển dữ liệu đó không được mã hóa qua internet. Xin đừng làm vậy.
dequis

@dequis tôi đã làm rõ. Tôi thấy không có vấn đề với việc sử dụng chúng để chạy mô phỏng lớn, kinda nghĩ rằng nó sẽ là lẽ thường để không sử dụng chúng cho keygen / etc, nhưng nó có giá trị kỳ quặc là cụ thể cho các điểm. Câu hỏi là cố gắng-bất khả tri, vì vậy nó thực sự không xảy ra với tôi để quá cụ thể, nhưng là điểm tốt.
Tim Post

6

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:

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:

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 .


2
Kẻ tấn công có đủ sức mạnh để thay thế / dev / random hoặc / dev / urandom bằng thứ gì đó khác thường cũng có đủ sức mạnh để tải một mô-đun hạt nhân để làm hỏng mọi nỗ lực mà bạn thực hiện trong việc xác định xem đó có phải là thiết bị ngẫu nhiên hay không.
zneak

Các trang người đàn ông nói 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 -atrong một thiết bị đầu cuối để kiểm tra phiên bản hạt nhân của bạn.
erapert
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.