Bagaimana cara menggunakan /dev/random atau urandom di C?

Saya ingin menggunakan /dev/random atau /dev/urandom di C. Bagaimana cara melakukannya? Saya tidak tahu bagaimana cara menanganinya di C, jika ada yang tahu tolong beri tahu saya caranya. Terima kasih.


person stojance    schedule 03.04.2010    source sumber
comment
Lihat artikel yang sangat informatif ini tentang beberapa peringatan umum dalam mengambil rute menuju keacakan (semu-) ini: insanecoding.blogspot.fi/2014/05/   -  person appas    schedule 17.06.2015


Jawaban (5)


Secara umum, sebaiknya hindari membuka file untuk mendapatkan data acak, karena banyaknya titik kegagalan yang ada dalam prosedur.

Pada distribusi Linux terbaru, panggilan sistem getrandom dapat digunakan untuk mendapatkan nomor acak yang aman untuk kripto, dan tidak akan gagal jika GRND_RANDOM tidak ditentukan sebagai tanda dan jumlah baca paling banyak 256 byte.

Mulai Oktober 2017, OpenBSD, Darwin, dan Linux (dengan -lbsd) kini semuanya memiliki implementasi arc4random yang aman terhadap kripto dan tidak dapat gagal. Itu menjadikannya pilihan yang sangat menarik:

char myRandomData[50];
arc4random_buf(myRandomData, sizeof myRandomData); // done!

Jika tidak, Anda dapat menggunakan perangkat acak seolah-olah itu adalah file. Anda membacanya dan Anda mendapatkan data acak. Saya menggunakan open/read di sini, tetapi fopen/fread juga bisa digunakan.

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

Anda dapat membaca lebih banyak byte acak sebelum menutup deskriptor file. /dev/urandom tidak pernah memblokir dan selalu mengisi byte sebanyak yang Anda minta, kecuali panggilan sistem terganggu oleh sinyal. Ini dianggap aman secara kriptografis dan harus menjadi perangkat acak Anda.

/dev/random lebih rewel. Pada sebagian besar platform, ia dapat mengembalikan byte lebih sedikit dari yang Anda minta dan dapat memblokir jika byte yang tersedia tidak mencukupi. Hal ini membuat cerita penanganan kesalahan menjadi lebih kompleks:

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);
}
person zneak    schedule 03.04.2010
comment
oke, jawaban yang bagus. Dan bagaimana jika saya ingin mengaturnya agar membaca banyak angka? Apakah saya akan melakukan while(something) { read(..) } atau haruskah saya membuka/menutupnya setiap kali loop dimulai? - person stojance; 03.04.2010
comment
Hai, bisakah Anda memberi saya beberapa tips bagaimana saya bisa terus membaca semua byte dari \dev\random. jika menghalangi, bagaimana saya bisa merasakannya. Tapi sekali lagi ketika lebih banyak byte tersedia saya akan membacanya. - person karim; 02.11.2010
comment
@karim Itu tidak memblokir di Mac OS (yang saya gunakan), dan saya tidak terlalu yakin tentang cara menangani file blok untuk keadaan ini. Anda harus mengajukan pertanyaan baru untuk itu. - person zneak; 02.11.2010
comment
@karim: Harap jangan pernah membaca semua byte dari /dev/random. Hanya saja, jangan. Program Anda mungkin bukan satu-satunya pengguna di sistem yang memerlukan byte acak. - person Zan Lynx; 26.02.2011
comment
Saya hanya membutuhkan 256 byte. lalu aku berhenti. Tapi terkadang saya tidak mendapatkan 256 byte. Saya harus menunggu 1/2 detik. - person karim; 26.02.2011
comment
Kode dalam jawaban ini salah. Anda perlu memeriksa nilai kembalian read untuk melihat berapa banyak byte yang sebenarnya dibaca, dan ulangi hingga Anda mendapatkan cukup. Apa adanya kode ini dapat membuat myRandomInteger diisi dengan memori lama daripada data acak. - person morrog; 25.10.2013
comment
@morrog, saya yakin hasil edit saya akan mengatasi masalah yang Anda ajukan. Juga jangan lupa bahwa Anda dapat mengedit jawaban siapa pun jika Anda merasa kurang memadai. - person zneak; 25.10.2013
comment
@zneak, maaf saya lupa postingan bisa diedit di sini. Terima kasih telah memberi tahu saya. Modifikasi terakhir Anda hanya menambahkan tanda centang saat dibaca, bukan loop. Saya memodifikasinya untuk menggunakan loop, sehingga kode sekarang akan diblokir dengan tepat. - person morrog; 26.10.2013
comment
@morrog Overeager pengulas menolaknya, jadi saya melakukan perubahan secara manual. Maaf, Anda tidak mendapat kredit untuk itu. - person zneak; 27.10.2013
comment
Sebenarnya sebagian besar kriptografer merekomendasikan penggunaan /dev/urandom. Jika sudah cukup diunggulkan sekali, ia akan menghasilkan nomor acak semu dalam jumlah tak terbatas yang sesuai untuk digunakan dalam kripto. Satu-satunya kekhawatiran adalah bahwa penyemaian awal mungkin tidak cukup. Masalah yang tidak terlalu acak hanya berlaku pada beberapa kasus khusus yang jarang terjadi, seperti di awal proses booting pada perangkat yang disematkan atau mengkloning mesin virtual. - person CodesInChaos; 27.10.2013
comment
@CodesInChaos, saya mengutip halaman manual Linux: Jika Anda tidak yakin apakah Anda harus menggunakan /dev/random atau /dev/urandom, maka mungkin Anda ingin menggunakan yang terakhir. Sebagai aturan umum, /dev/urandom harus digunakan untuk semua hal kecuali kunci GPG/SSL/SSH yang berumur panjang. - person zneak; 27.10.2013
comment
@zneak Penekanan pada berumur panjang karena bagi mereka tidak ada salahnya menjadi ekstra paranoid. Untuk penggunaan kripto normal /dev/urandom baik-baik saja. - person CodesInChaos; 27.10.2013
comment
Namun Anda juga perlu memastikan bahwa /dev/random (atau /dev/urandom) sebenarnya adalah perangkat nomor acak dan bukan file sparse atau symlink ke /dev/zero (yang mungkin terjadi jika mesin Anda telah diretas). Ada artikel bagus di insanecoding .blogspot.co.uk/2014/05/ yang membahas semua kendala penggunaan /dev/{u}random secara membabi buta. - person Chris J; 23.07.2014
comment
Apakah ini perlu memeriksa nilai kembalian dari panggilan open(2)? - person KyleWpppd; 02.01.2015
comment
@KyleWpppd, jawaban ini awalnya memeriksa tidak ada kondisi kesalahan sama sekali demi kesederhanaan, tetapi orang lain memutuskan bahwa itu cukup penting di sekitar read untuk memasukkannya. Menurut saya, secara umum, Anda harus selalu memeriksa kondisi kesalahan. Selain itu, jika aplikasi Anda sangat penting bagi keamanan, sebaiknya periksa apakah file tersebut adalah perangkat karakter. - person zneak; 02.01.2015
comment
Jawaban ini telah ada di sini selama 5 tahun, tetapi saya yakin kodenya salah. Anda bahkan tidak pernah menggunakan deskriptor file randomData selain menutupnya. Anda yakin seharusnya tidak terbaca read(randomData ...? Menunjukkan pentingnya penamaan. - person BoppreH; 01.08.2015
comment
@BoppreH, Anda mungkin akan senang mengetahui bahwa masalah khusus ini baru ada selama dua tahun (orang lain menyarankan perubahan yang akhirnya saya gabungkan sendiri tanpa cukup berhati-hati). Berbicara tentang menyarankan pengeditan, Anda dipersilakan untuk memperbaiki masalah lain yang Anda temukan. - person zneak; 01.08.2015
comment
Paragraf terakhir dari jawaban ini membuat asumsi yang salah, dijelaskan di sini: 2uo.de/ mitos-tentang-urandom/#struktur. Faktanya, /dev/random dan /dev/urandom duduk di belakang CSPRNG yang sama. (Saran Anda untuk memilih /dev/urandom daripada /dev/random masih berlaku.) - person Sebastian; 23.03.2017

Ada jawaban akurat lainnya di atas. Saya perlu menggunakan aliran FILE*. Inilah yang saya lakukan...

int byte_count = 64;
char data[64];
FILE *fp;
fp = fopen("/dev/urandom", "r");
fread(&data, 1, byte_count, fp);
fclose(fp);
person Dustin Kirkland    schedule 16.08.2012
comment
Sebuah int dapat dibaca secara langsung hanya dengan melemparkan pointer int ke pointer char. fread((char*)(&myInt),sizeof(myInt),1,fp) - person Azeem Bande-Ali; 25.05.2013
comment
@AzeemBande-Ali: Mengapa Anda tidak menggunakan fread((int*)(&myInt),sizeof(myInt),1,fp) saja ? Maksudku pemeran int* ? - person Larry; 30.05.2014
comment
Dalam kedua kasus tersebut cast tidak boleh digunakan dalam kode C, fread() mengambil void *, jadi lakukan saja fread(&myInt, ... ); - person nos; 03.01.2015
comment
Mengapa Anda membutuhkan byte_count? Itu tidak terpakai. - person CalculatorFeline; 10.08.2017
comment
@CalculatorFeline Byte_count di sini agak membingungkan, mungkin awalnya ingin setiap indeks memiliki panjang byte yang sama, tetapi ini tidak bisa ... - person LinconFive; 19.03.2020

Buka saja file untuk dibaca lalu baca datanya. Di C++11 Anda mungkin ingin menggunakan std::random_device yang menyediakan akses lintas platform ke perangkat tersebut.

person Tronic    schedule 03.04.2010
comment
Tampaknya std::random_device tidak masuk dalam standar 2011. Hal ini muncul dalam draf N3797. - person Keith Thompson; 02.01.2015
comment
Sepertinya std::random_device berhasil berhasil C++11 pada akhirnya. - person legends2k; 26.06.2015
comment
Masalahnya adalah std::random_device ada di C++ dan bukan di C, dan OP bertanya bagaimana cara menggunakan /dev/random atau /dev/urandom bukan bagaimana menggunakan std::random_device meskipun itu adalah pilihan yang baik untuk menggunakan std::random_device dan memiliki manfaat, hanya saja bukan itu yang diminta OP - person Nfagie Yansaneh; 08.08.2017

Zneak 100% benar. Sangat umum juga untuk membaca buffer angka acak yang sedikit lebih besar dari yang Anda perlukan saat startup. Anda kemudian dapat mengisi array di memori, atau menulisnya ke file Anda sendiri untuk digunakan kembali nanti.

Implementasi tipikal di atas:

typedef struct prandom {
     struct prandom *prev;
     int64_t number;
     struct prandom *next;
} prandom_t;

Ini menjadi lebih atau kurang seperti kaset yang hanya bergerak maju dan secara ajaib dapat diisi ulang oleh utas lain sesuai kebutuhan. Ada banyak dari layanan yang menyediakan dump file besar yang hanya berisi angka acak yang dihasilkan dengan generator yang jauh lebih kuat seperti:

  • Peluruhan radioaktif
  • Perilaku optik (foton mengenai cermin semi transparan)
  • Kebisingan atmosfer (tidak sekuat di atas)
  • Peternakan monyet mabuk yang mengetik di keyboard dan menggerakkan tikus (bercanda)

Jangan gunakan entropi 'paket' untuk benih kriptografi, jika hal tersebut tidak perlu dikatakan lagi. Kumpulan tersebut bagus untuk simulasi, tidak bagus sama sekali untuk menghasilkan kunci dan semacamnya.

Tidak peduli dengan kualitas, jika Anda memerlukan banyak angka untuk sesuatu seperti simulasi monte carlo, lebih baik menyediakannya dengan cara yang tidak menyebabkan read() diblokir.

Namun, ingat, keacakan suatu bilangan sama deterministiknya dengan kompleksitas yang ada dalam menghasilkannya. /dev/random dan /dev/urandom memang nyaman, tetapi tidak sekuat menggunakan HRNG (atau mengunduh dump besar dari HRNG). Perlu diperhatikan juga bahwa /dev/random diisi ulang melalui entropi, sehingga dapat memblokir cukup lama sementara tergantung pada keadaan.

person Tim Post♦    schedule 04.04.2010
comment
Mengunduh file besar yang berisi kumpulan angka acak adalah saran yang buruk untuk tujuan kriptografi. Ia meminta orang lain untuk menyediakan benih untuk fungsi Anda, dan layanan tersebut tampaknya mentransfer data tersebut tanpa terenkripsi melalui internet. Tolong jangan lakukan itu. - person dequis; 09.07.2014
comment
@dequis saya klarifikasi. Saya tidak melihat ada masalah dalam menggunakannya untuk menjalankan simulasi besar, agak pikir akan masuk akal untuk tidak menggunakannya untuk keygen / dll, tapi anehnya ada baiknya untuk menjelaskan secara spesifik pada intinya. Pertanyaannya bersifat agnostik, jadi tidak terpikir oleh saya untuk terlalu spesifik, tapi bagus. - person Tim Post♦; 28.07.2015

jawaban zneak mencakupnya secara sederhana, namun kenyataannya lebih rumit dari itu. Misalnya, Anda perlu mempertimbangkan apakah /dev/{u}random benar-benar merupakan perangkat nomor acak. Skenario seperti itu dapat terjadi jika mesin Anda telah disusupi dan perangkat diganti dengan symlink ke /dev/zero atau file yang jarang. Jika ini terjadi, aliran acak kini dapat diprediksi sepenuhnya.

Cara paling sederhana (setidaknya di Linux dan FreeBSD) adalah dengan melakukan panggilan ioctl pada perangkat yang hanya akan berhasil jika perangkat tersebut adalah generator acak:

int data;
int result = ioctl(fd, RNDGETENTCNT, &data); 
// Upon success data now contains amount of entropy available in bits

Jika ini dilakukan sebelum pembacaan pertama perangkat acak, maka ada kemungkinan besar Anda mendapatkan perangkat acak tersebut. Jadi jawaban @zneak sebaiknya diperluas menjadi:

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 meliput hal ini, dan kendala lainnya belum lama ini; Saya sangat menyarankan membaca keseluruhan artikel. Saya harus memberikan penghargaan kepada mereka dari mana solusi ini diambil.

Diedit untuk ditambahkan (25-07-2014)...
Secara kebetulan, saya membacanya tadi malam sebagai bagian dari Upaya LibReSSL, Linux tampaknya mendapatkan Panggilan sistem GetRandom(). Pada saat penulisan, belum ada kabar kapan akan tersedia dalam rilis umum kernel. Namun ini akan menjadi antarmuka pilihan untuk mendapatkan data acak yang aman secara kriptografis karena menghilangkan semua jebakan yang disediakan oleh akses melalui file. Lihat juga kemungkinan penerapan LibReSSL.

person Chris J    schedule 23.07.2014
comment
Seorang penyerang dengan kekuatan yang cukup untuk mengganti /dev/random atau /dev/urandom dengan sesuatu yang lain biasanya juga memiliki kekuatan yang cukup untuk memuat modul kernel untuk mengacaukan setiap upaya yang Anda lakukan dalam menentukan apakah itu perangkat acak atau bukan. - person zneak; 02.01.2015
comment
halaman manual mengatakan getrandom() diperkenalkan di kernel 3.17. Jadi stok Ubuntu 16.04 tidak memilikinya pada 17-01-2018. Jalankan uname -a di terminal untuk memeriksa versi kernel Anda. - person erapert; 17.01.2018