Mari kita bermain poker komputer, hanya Anda, saya dan server yang kami berdua percayai. Server menggunakan generator nomor pseudo-acak yang diinisialisasi dengan seed 32-bit tepat sebelum kita bermain. Jadi ada sekitar empat miliar kemungkinan deck.
Saya mendapatkan lima kartu di tangan saya - tampaknya kita tidak memainkan Texas Hold 'Em. Misalkan kartu dibagikan satu kepada saya, satu untuk Anda, satu untuk saya, satu untuk Anda, dan seterusnya. Jadi saya punya kartu pertama, ketiga, kelima, ketujuh dan kesembilan di geladak.
Sebelumnya saya menjalankan generator nomor pseudo-acak empat miliar kali, sekali dengan masing-masing seed, dan menuliskan kartu pertama yang dihasilkan untuk masing-masing ke dalam database. Misalkan kartu pertama saya adalah ratu sekop. Itu hanya menunjukkan satu sebagai kartu pertama dalam satu dari setiap 52 deck yang mungkin, jadi kami telah mengurangi deck yang mungkin dari empat miliar menjadi sekitar 80 juta atau lebih.
Misalkan kartu kedua saya adalah tiga hati. Sekarang saya menjalankan RNG saya 80 juta kali lebih banyak menggunakan 80 juta biji yang menghasilkan ratu sekop sebagai angka pertama. Saya perlu beberapa detik. Saya menuliskan semua deck yang menghasilkan tiga hati sebagai kartu ketiga - kartu kedua di tangan saya. Itu lagi hanya sekitar 2% dari deck, jadi sekarang kita turun ke 2 juta deck.
Misalkan kartu ketiga di tangan saya adalah 7 klub. Saya memiliki database 2 juta benih yang membagi dua kartu saya; Saya menjalankan RNG saya 2 juta kali lagi untuk menemukan 2% dari deck yang menghasilkan 7 klub sebagai kartu ketiga, dan kita hanya memiliki 40 ribu deck.
Anda lihat bagaimana ini berjalan. Saya menjalankan RNG 40000 saya lebih banyak kali untuk menemukan semua benih yang menghasilkan kartu keempat saya, dan itu membuat kita turun menjadi 800 deck, dan kemudian menjalankannya 800 kali lebih banyak untuk mendapatkan ~ 20 biji yang menghasilkan kartu kelima saya, dan sekarang saya hanya menghasilkan dua puluh tumpukan kartu dan saya tahu bahwa Anda memiliki salah satu dari dua puluh kartu yang mungkin. Selain itu, saya memiliki ide yang sangat bagus tentang apa yang akan saya gambar selanjutnya.
Sekarang apakah Anda melihat mengapa keacakan sejati itu penting? Cara Anda menggambarkannya, Anda berpikir bahwa distribusi itu penting, tetapi distribusi bukanlah yang membuat proses acak. Ketidakpastian adalah apa yang membuat proses acak.
MEMPERBARUI
Berdasarkan komentar (sekarang dihapus karena sifatnya yang tidak konstruktif), setidaknya 0,3% orang yang pernah membaca ini bingung dengan poin saya. Ketika orang-orang membantah poin saya belum dibuat, atau lebih buruk, berpendapat untuk poin yang saya tidak membuat asumsi bahwa saya tidak membuat mereka, maka saya tahu bahwa saya perlu menjelaskan lebih jelas dan hati-hati.
Tampaknya ada kebingungan khusus di sekitar distribusi kata jadi saya ingin memanggil penggunaan dengan hati-hati.
Pertanyaan yang dihadapi adalah:
- Bagaimana perbedaan angka pseudorandom dan benar-benar acak?
- Mengapa perbedaan itu penting?
- Apakah perbedaannya ada kaitannya dengan distribusi output PRNG?
Mari kita mulai dengan mempertimbangkan cara sempurna untuk menghasilkan setumpuk kartu acak untuk bermain poker. Kemudian kita akan melihat bagaimana teknik lain untuk menghasilkan deck berbeda, dan jika memungkinkan untuk mengambil keuntungan dari perbedaan itu.
Mari kita mulai dengan mengandaikan bahwa kita memiliki label kotak ajaib TRNG
. Sebagai inputnya kita memberikan bilangan bulat n lebih besar atau sama dengan satu, dan sebagai outputnya memberi kita angka acak antara satu dan n, inklusif. Output dari kotak sepenuhnya tidak dapat diprediksi (bila diberi nomor selain satu) dan angka apa pun antara satu dan n sama besar kemungkinannya dengan yang lain; yang mengatakan bahwa distribusi adalah seragam . (Ada pemeriksaan statistik tingkat lanjut yang lebih lanjut yang bisa kita lakukan; Saya mengabaikan hal ini karena tidak sesuai dengan argumen saya. TRNG secara statistik acak secara acak dengan asumsi.)
Kami mulai dengan setumpuk kartu yang tidak diacak. Kami meminta boks untuk nomor antara satu dan 52 - yaitu TRNG(52)
,. Berapapun jumlah yang diberikannya, kami menghitung banyak kartu dari dek yang kami sortir dan mengeluarkan kartu itu. Ini menjadi kartu pertama di geladak yang dikocok. Kemudian kami meminta TRNG(51)
dan melakukan hal yang sama untuk memilih kartu kedua, dan seterusnya.
Cara lain untuk melihatnya adalah: ada 52! = 52 x 51 x 50 ... x 2 x 1 kemungkinan deck, yang kira-kira 2 226 . Kami telah memilih salah satu dari mereka secara acak.
Sekarang kami memberikan kartu. Ketika saya melihat kartu saya, saya tidak tahu kartu apa yang Anda miliki. (Selain dari fakta yang jelas bahwa Anda tidak memiliki kartu yang saya miliki.) Mereka dapat berupa kartu apa saja, dengan probabilitas yang sama.
Jadi izinkan saya memastikan bahwa saya menjelaskan ini dengan jelas. Kami memiliki distribusi seragam untuk setiap output individu TRNG(n)
; masing-masing mengambil angka antara 1 dan n dengan probabilitas 1 / n. Juga, hasil dari proses ini adalah bahwa kami telah memilih satu dari 52! mungkin deck dengan probabilitas 1/52 !, sehingga distribusi atas set mungkin deck adalah juga seragam.
Baiklah.
Sekarang anggap saja kita memiliki kotak ajaib yang lebih sedikit, berlabel PRNG
. Sebelum Anda dapat menggunakannya, nomor tersebut harus diunggulkan dengan nomor 32-bit yang tidak ditandatangani.
ASIDE: Kenapa 32 ? Tidak bisakah itu diunggulkan dengan nomor 64- atau 256- atau 10000-bit? Tentu. Tetapi (1) dalam prakteknya sebagian besar PRNG yang ada di pasaran diunggulkan dengan angka 32-bit, dan (2) jika Anda memiliki 10.000 bit keacakan untuk membuat benih maka mengapa Anda menggunakan PRNG sama sekali? Anda sudah memiliki sumber 10.000 bit keacakan!
Bagaimanapun, kembali ke cara kerja PRNG: setelah diunggulkan, Anda dapat menggunakannya dengan cara yang sama seperti yang Anda gunakan TRNG
. Artinya, Anda memberikan angka, n, dan memberi Anda kembali angka antara 1 dan n, inklusif. Selain itu, distribusi output itu kurang lebih seragam . Artinya, ketika kita meminta PRNG
angka antara 1 dan 6, kita mendapatkan 1, 2, 3, 4, 5 atau 6 masing-masing kira-kira seperenam dari waktu, tidak peduli apa benihnya.
Saya ingin menekankan hal ini beberapa kali karena sepertinya itu yang membingungkan komentator tertentu. Distribusi PRNG seragam dalam setidaknya dua cara. Pertama, misalkan kita memilih benih tertentu. Kami berharap bahwa urutan PRNG(6), PRNG(6), PRNG(6)...
satu juta kali akan menghasilkan distribusi angka yang seragam antara 1 dan 6. Dan kedua, jika kami memilih satu juta benih yang berbeda dan memanggil PRNG(6)
satu kali untuk setiap benih, sekali lagi kami akan mengharapkan distribusi angka yang seragam dari 1 hingga 6. 6. Keseragaman PRNG di kedua operasi ini tidak relevan dengan serangan yang saya gambarkan .
Proses ini dikatakan pseudo-acak karena perilaku kotak sebenarnya sepenuhnya deterministik; ia memilih dari salah satu dari 32 perilaku yang mungkin berdasarkan pada benih. Yaitu, setelah diunggulkan, PRNG(6), PRNG(6), PRNG(6), ...
menghasilkan urutan angka dengan distribusi seragam, tetapi urutan itu sepenuhnya ditentukan oleh benih. Untuk urutan panggilan tertentu, katakanlah, PRNG (52), PRNG (51) ... dan seterusnya, hanya ada 2 32 kemungkinan urutan. Benih pada dasarnya memilih yang mana yang kita dapatkan.
Untuk menghasilkan sebuah dek, server sekarang menghasilkan sebuah seed. (Bagaimana? Kami akan kembali ke titik itu.) Kemudian mereka memanggil PRNG(52)
, PRNG(51)
dan seterusnya untuk menghasilkan dek, mirip dengan sebelumnya.
Sistem ini rentan terhadap serangan yang saya jelaskan. Untuk menyerang server yang pertama, sebelumnya, perbanyak salinan kotak kami sendiri dengan 0 dan minta PRNG(52)
dan tuliskan. Kemudian kita menabur ulang dengan 1, meminta PRNG(52)
, dan menuliskannya, hingga 2 32 -1.
Sekarang, server poker yang menggunakan PRNG untuk menghasilkan deck harus menghasilkan seed. Tidak masalah bagaimana mereka melakukannya. Mereka bisa menelepon TRNG(2^32)
untuk mendapatkan benih yang benar-benar acak. Atau mereka dapat mengambil waktu saat ini sebagai benih, yang hampir tidak acak sama sekali; Saya tahu jam berapa sekarang sebanyak yang Anda lakukan. Maksud serangan saya adalah bahwa itu tidak masalah, karena saya memiliki basis data saya . Ketika saya melihat kartu pertama saya, saya bisa menghilangkan 98% dari kemungkinan benih. Ketika saya melihat kartu kedua saya, saya bisa menghilangkan 98% lebih banyak, dan seterusnya, sampai akhirnya saya bisa turun ke beberapa kemungkinan benih, dan tahu dengan kemungkinan besar apa yang ada di tangan Anda.
Sekarang, sekali lagi, saya ingin menekankan bahwa asumsi di sini adalah bahwa jika kita memanggil PRNG(6)
satu juta kali kita akan mendapatkan masing-masing nomor kira-kira seperenam dari waktu . Distribusi itu (kurang lebih) seragam , dan jika keseragaman distribusi itu yang Anda pedulikan , tidak apa-apa. Inti pertanyaannya adalah adakah hal-hal lain yang menjadi PRNG(6)
perhatian kita? dan jawabannya adalah ya . Kami peduli tentang ketidakpastian juga.
Cara lain untuk melihat masalahnya adalah bahwa meskipun distribusi satu juta panggilan PRNG(6)
mungkin baik-baik saja, karena PRNG memilih dari hanya 2 32 perilaku yang mungkin, ia tidak dapat menghasilkan setiap dek yang mungkin. Itu hanya dapat menghasilkan 2 32 dari 2 226 deck yang mungkin; sebagian kecil. Jadi distribusi set himpunan semua sangat buruk. Tetapi sekali lagi, serangan mendasar di sini didasarkan pada kemampuan kita untuk berhasil memprediksi perilaku masa lalu dan masa depan dari PRNG
sampel kecil dari hasilnya.
Izinkan saya mengatakan ini ketiga atau empat kali untuk memastikan ini masuk. Ada tiga distribusi di sini. Pertama, distribusi proses yang menghasilkan benih 32-bit acak. Itu bisa sangat acak, tidak dapat diprediksi dan seragam dan serangan akan tetap bekerja . Kedua, distribusi satu juta panggilan ke PRNG(6)
. Itu bisa sangat seragam dan serangannya masih akan berhasil. Ketiga, distribusi deck dipilih oleh proses pseudo-acak yang telah saya jelaskan. Distribusi itu sangat buruk; hanya sebagian kecil dari IRL deck yang mungkin dapat dipilih. Serangan tergantung pada prediktabilitas perilaku PRNG berdasarkan pengetahuan sebagian dari hasilnya .
ASIDE: Serangan ini mengharuskan penyerang tahu atau bisa menebak apa algoritma yang tepat yang digunakan oleh PRNG. Apakah itu realistis atau tidak adalah pertanyaan terbuka. Namun, ketika merancang sistem keamanan Anda harus merancang itu agar aman terhadap serangan bahkan jika penyerang tahu semua algoritma dalam program . Dengan kata lain: bagian dari sistem keamanan yang harus tetap rahasia agar sistem menjadi aman disebut "kunci". Jika sistem Anda bergantung pada keamanannya pada algoritme yang Anda gunakan sebagai rahasia, maka kunci Anda berisi algoritme tersebut . Itu adalah posisi yang sangat lemah!
Bergerak.
Sekarang anggaplah kita memiliki label kotak ajaib ketiga CPRNG
. Ini adalah versi crypto-strength dari PRNG
. Dibutuhkan benih 256-bit alih-alih benih 32-bit. Ini berbagi dengan PRNG
properti yang benih pilih dari salah satu dari 256 perilaku yang mungkin. Dan seperti mesin kami yang lain, ia memiliki properti yang menghasilkan sejumlah besar panggilan untuk CPRNG(n)
menghasilkan distribusi hasil yang seragam antara 1 dan n: masing-masing terjadi 1 / n waktu itu. Bisakah kita menjalankan serangan kita melawannya?
Serangan awal kami mengharuskan kami menyimpan 2 32 pemetaan dari benih hingga PRNG(52)
. Tetapi 2 256 adalah angka yang jauh lebih besar; itu benar-benar tidak mungkin untuk menjalankan CPRNG(52)
itu berkali-kali dan menyimpan hasilnya.
Tapi bagaimana kalau ada cara lain untuk mengambil nilai CPRNG(52)
dan dari itu menyimpulkan fakta tentang benih? Kami sudah cukup bodoh sejauh ini, hanya dengan kasar memaksa semua kombinasi yang mungkin. Bisakah kita melihat ke dalam kotak ajaib, mencari tahu cara kerjanya, dan menyimpulkan fakta tentang benih berdasarkan output?
Tidak Rincian terlalu rumit untuk menjelaskan, tapi CPRNGs cerdik dirancang sehingga tidak layak untuk menyimpulkan setiap fakta yang berguna tentang benih dari output pertama CPRNG(52)
atau dari setiap bagian dari output, tidak peduli seberapa besar .
OK, jadi sekarang misalkan server menggunakan CPRNG
untuk menghasilkan deck. Perlu benih 256-bit. Bagaimana cara memilih benih itu? Jika ia memilih nilai apa pun yang dapat diprediksi oleh penyerang maka tiba-tiba serangan itu menjadi layak lagi . Jika kita dapat menentukan bahwa dari 2 256 kemungkinan benih, hanya empat miliar di antaranya yang kemungkinan akan dipilih oleh server, maka kita kembali berbisnis . Kami dapat memasang serangan ini lagi, hanya memperhatikan sejumlah kecil benih yang mungkin dapat dihasilkan.
Karena itu server harus bekerja untuk memastikan bahwa jumlah 256-bit terdistribusi secara merata - yaitu, setiap seed yang mungkin dipilih dengan probabilitas 1/2 256 . Pada dasarnya server harus memanggil TRNG(2^256)-1
untuk menghasilkan benih untuk CPRNG
.
Bagaimana jika saya bisa meretas server dan mengintip ke dalamnya untuk melihat seed apa yang dipilih? Dalam hal ini, penyerang mengetahui masa lalu dan masa depan CPRNG yang lengkap . Penulis server harus berjaga-jaga terhadap serangan ini! (Tentu saja jika saya dapat berhasil me-mount serangan ini maka saya mungkin bisa juga hanya mentransfer uang ke rekening bank saya secara langsung, jadi mungkin itu tidak menarik. Intinya adalah: benih harus menjadi rahasia yang sulit ditebak, dan angka 256-bit yang benar-benar acak sangat sulit ditebak.)
Kembali ke poin saya sebelumnya tentang pertahanan-dalam: benih 256-bit adalah kunci untuk sistem keamanan ini. Gagasan CPRNG adalah bahwa sistem aman selama kuncinya aman ; bahkan jika setiap fakta lain tentang algoritma diketahui, selama Anda dapat menyimpan kunci rahasia, kartu lawan tidak dapat diprediksi.
OK, jadi benih harus rahasia dan didistribusikan secara seragam karena jika tidak, kita dapat melakukan serangan. Kami memiliki asumsi bahwa distribusi output CPRNG(n)
seragam. Bagaimana dengan distribusi set semua deck yang mungkin?
Anda mungkin mengatakan: ada 2 256 kemungkinan urutan keluaran oleh CPRNG, tetapi hanya ada 2 226 deck yang mungkin. Oleh karena itu ada lebih banyak urutan yang mungkin daripada deck, jadi kami baik-baik saja; setiap kemungkinan-IRL deck sekarang (dengan probabilitas tinggi) mungkin dalam sistem ini. Dan itu argumen yang bagus kecuali ...
2 226 hanya merupakan perkiraan 52 !. Bagilah. 2 256/52 ! tidak mungkin menjadi bilangan bulat karena untuk satu hal, 52! habis dibagi 3 tetapi tidak ada kekuatan dua! Karena ini bukan bilangan bulat sekarang kita memiliki situasi di mana semua deck dimungkinkan , tetapi beberapa deck lebih mungkin daripada yang lain .
Jika itu tidak jelas, pertimbangkan situasi dengan jumlah yang lebih kecil. Misalkan kita memiliki tiga kartu, A, B dan C. Misalkan kita menggunakan PRNG dengan seed 8-bit, jadi ada 256 kemungkinan seed. Ada 256 kemungkinan hasil PRNG(3)
tergantung pada benih; tidak ada cara untuk memiliki sepertiga dari mereka menjadi A, sepertiga dari mereka menjadi B dan sepertiga dari mereka menjadi C karena 256 tidak dapat habis dibagi oleh 3. Harus ada bias kecil terhadap salah satu dari mereka.
Demikian pula, 52 tidak dibagi secara merata menjadi 2 256 , jadi harus ada beberapa bias terhadap beberapa kartu sebagai kartu pertama yang dipilih dan bias dari yang lain.
Dalam sistem asli kami dengan benih 32-bit ada bias besar dan sebagian besar kemungkinan deck tidak pernah diproduksi. Dalam sistem ini semua geladak dapat diproduksi, tetapi distribusi geladak masih cacat . Beberapa deck sangat sedikit lebih mungkin daripada yang lain.
Sekarang pertanyaannya adalah: apakah kita memiliki serangan berdasarkan kelemahan ini? dan jawabannya ada dalam praktik, mungkin tidak . CPRNG dirancang sedemikian rupa sehingga jika benih benar-benar acak maka secara komputasi tidak layak untuk membedakan antara CPRNG
dan TRNG
.
OK, jadi mari kita simpulkan.
Bagaimana perbedaan angka pseudorandom dan benar-benar acak?
Mereka berbeda dalam tingkat prediktabilitas yang mereka tunjukkan.
- Angka yang benar-benar acak tidak dapat diprediksi.
- Semua angka pseudo-acak dapat diprediksi jika benih dapat ditentukan atau ditebak.
Mengapa perbedaan itu penting?
Karena ada aplikasi di mana keamanan sistem bergantung pada ketidakpastian .
- Jika TRNG digunakan untuk memilih masing-masing kartu maka sistem tidak tersedia.
- Jika CPRNG digunakan untuk memilih masing-masing kartu maka sistem aman jika benih keduanya tidak dapat diprediksi dan tidak diketahui.
- Jika PRNG biasa dengan ruang benih kecil digunakan maka sistem tidak aman terlepas dari apakah benih tidak dapat diprediksi atau tidak diketahui; ruang biji yang cukup kecil rentan terhadap serangan brute-force seperti yang saya jelaskan.
Apakah perbedaannya ada kaitannya dengan distribusi output PRNG?
Keseragaman distribusi atau ketiadaan untuk panggilan individu untuk RNG(n)
tidak relevan dengan serangan yang telah saya jelaskan.
Seperti yang telah kita lihat, baik PRNG
dan CPRNG
menghasilkan distribusi yang buruk dari kemungkinan memilih setiap dek dari semua deck yang mungkin. Ini PRNG
jauh lebih buruk, tetapi keduanya memiliki masalah.
Satu pertanyaan lagi:
Jika TRNG jauh lebih baik daripada CPRNG, yang pada gilirannya jauh lebih baik daripada PRNG, mengapa ada yang menggunakan CPRNG atau PRNG?
Dua alasan.
Pertama: biaya. TRNG mahal . Menghasilkan angka acak benar-benar sulit. CPRNG memberikan hasil yang baik untuk banyak panggilan secara sewenang-wenang dengan hanya satu panggilan ke TRNG untuk seed. Sisi negatifnya tentu saja Anda harus merahasiakan benih itu .
Kedua: kadang-kadang kita menginginkan prediktabilitas dan yang kita pedulikan adalah distribusi yang baik. Jika Anda menghasilkan data "acak" sebagai input program untuk test suite, dan itu menunjukkan bug, maka alangkah baiknya menjalankan test suite lagi menghasilkan bug lagi!
Saya harap itu sekarang jauh lebih jelas.
Akhirnya, jika Anda menikmati ini maka Anda mungkin menikmati beberapa bacaan lebih lanjut tentang subjek keacakan dan permutasi: