Hancurkan cipher yang rusak

12

Saya telah merancang generator acak sederhana yang siklus dua angka dalam cara yang kacau menggunakan metode multiply dan modulus. Ini sangat bagus untuk itu.

Namun, jika saya menggunakannya sebagai generator sandi, ia akan rentan terhadap serangan plaintext yang diketahui, mengingat bahwa seorang penyerang dapat merekayasa balik benih dari serangkaian angka acak dengan cara yang efisien secara komputasi.

Untuk membuktikan cipher broken, temukan pasangan nilai seed legal yang menghasilkan 7 nol berturut-turut dalam rentang [0; 255], menggunakan daya sesedikit mungkin, waktu CPU, dll. Sebanyak mungkin.

Berikut adalah generator acak yang ditulis dalam JavaScript:

function seed(state1,state2){
    //Constants
    var mod1=4294967087
    var mul1=65539
    var mod2=4294965887
    var mul2=65537
    function random(limit){
        //Cycle each state variable 1 step
        state1=(state1*mul1)%mod1
        state2=(state2*mul2)%mod2
        //Return a random variable
        return (state1+state2)%limit
    }
    //Return the random function
    return random
}

//Initiate the random generator using 2 integer values,
//they must be in the ranges [1;4294967086] and [1;4294965886]
random=seed(31337,42)
//Write 7 random values in the range [0;255] to screen
for(a=0;a<7;a++){
    document.write(random(256)+"<br>")
}

Saya telah membuat alat untuk menguji pasangan nomor kandidat, dapat ditemukan di sini .

Selama 3 hari berikutnya, spoiler tidak diperbolehkan , jawaban harus berisi hanya satu set angka, dan tentu saja set yang berbeda dari yang diposting oleh pemecah sebelumnya. Setelah itu Anda didorong untuk mengirim kode dan menjelaskan pendekatan Anda.

Edit, karantina selesai:
Jawaban harus berisi serangkaian angka dan penjelasan serta kode unik untuk mendokumentasikan metode penyelesaiannya.

Sebagian besar solusi elegan menang.

Sebagai catatan:
Menulis sebuah program yang dapat menemukan solusi dengan cepat itu elegan.
Membuat program yang memanfaatkan fitur-fitur GPU secara efisien untuk melakukannya lebih cepat adalah elegan.
Melakukan pekerjaan dengan sepotong "museumware" itu elegan.
Menemukan metode solusi yang layak dapat digunakan hanya dengan pena dan kertas sangat elegan.
Menjelaskan solusi Anda dengan cara yang instruktif dan mudah dimengerti adalah elegan.

Menggunakan banyak komputer atau sangat mahal tidak bagus.

aaaaaaaaaaaa
sumber
Apakah Anda yakin ada jawaban untuk ini?
Wile E. Coyote
Ya, ada ~ 256 dari mereka. Dan saya juga yakin bahwa mungkin untuk menemukan jawaban dalam beberapa menit, mengingat PC modern dan pemrograman yang tepat.
aaaaaaaaaaaa
Hanya ingin tahu, mengapa GPU elegan tetapi tidak banyak CPU?
JB
Karena mereka lebih sulit diprogram secara efisien daripada CPU. Anda harus memastikan bahwa Anda benar-benar memanfaatkan GPU, tidak ada gunanya membiarkan sebagian besar shader menyala karena beberapa subsistem lainnya mengalami hambatan. Dan tentu saja Anda masih harus menerapkan algoritma yang efisien untuk mencetak poin besar.
aaaaaaaaaaaa
Jika saya mengirimkan kode kerja saya, hampir seolah-olah saya mengirimkan banyak pasangan benih. Game sudah berakhir?
JB

Jawaban:

6

C ++, 44014022/164607120

Itu dalam C ++, menggunakan 1 GB memori, dan butuh sekitar 45 detik untuk menemukan pasangan pertama ini. Saya akan memperbarui waktu setelah menemukan semuanya.

Kode di bawah ini. Pertama menemukan semua pasangan yang menghasilkan 4 nol, lalu memotongnya dengan uji coba sederhana (lihatcheck metode). Ia menemukan pasangan yang menghasilkan 4 nol dengan menghasilkan dua array besar, satu yang berisi 4 byte orde rendah pertama dari generator state1, dan yang kedua yang berisi negatif dari 4 byte orde rendah pertama dari generator state2. Array ini kemudian disortir dan dicari kecocokannya, yang sesuai dengan keseluruhan generator yang menghasilkan 4 nol untuk memulai.

Array terlalu besar untuk disimpan dalam memori, sehingga tidak bekerja dalam ukuran batch agar sesuai dengan memori.

Sepertinya proses lengkap akan memakan waktu ~ 12 jam.

Sunting : Memperbaiki kode sehingga hanya perlu ~ 1 jam untuk mendapatkan semua kemungkinan benih. Sekarang ini menghasilkan tabel menjadi 256 file berbeda, satu untuk setiap byte pertama dari output. Kami kemudian dapat memproses setiap file secara independen sehingga kami tidak perlu membuat ulang data.

Sunting : Ternyata Anda dapat membuat 256 subtabel secara individual alih-alih sekaligus, jadi tidak diperlukan disk. Menjalankan waktu hingga ~ 15 menit menggunakan 256MB.

#include <stdio.h>
#include <stdint.h>
#include <algorithm>
using namespace std;

#define M1 65539
#define N1 4294967087
#define M2 65537
#define N2 4294965887
#define MATCHES 7

// M^-1 mod N                                                                                                                                                        
#define M1_INV 3027952124
#define M2_INV 1949206866

int npairs = 0;

void check(uint32_t seed1, uint32_t seed2) {
  uint32_t s1 = seed1;
  uint32_t s2 = seed2;
  for (int i = 0; i < MATCHES; i++) {
    s1 = (uint64_t)s1 * M1 % N1;
    s2 = (uint64_t)s2 * M2 % N2;
    if (((s1 + s2) & 0xff) != 0) return;
  }
  printf("%d %u %u\n", npairs++, seed1, seed2);
}

struct Record {
  uint32_t signature; // 2nd through 5th generated bytes                                                                                                             
  uint32_t seed;      // seed that generated them                                                                                                                    
};
// for sorting Records                                                                                                                                               
bool operator<(const Record &a, const Record &b) {
  return a.signature < b.signature;
}

int main(int argc, char *argv[]) {
  Record *table1 = (Record*)malloc((N1/256+1)*sizeof(*table1));
  Record *table2 = (Record*)malloc((N2/256+1)*sizeof(*table2));

  for (int i = 0; i < 256; i++) {  // iterate over first byte                                                                                                        
    printf("first byte %x\n", i);

    // generate signatures (bytes 2 through 5) for all states of generator 1                                                                                         
    // that generate i as the first byte.                                                                                                                            
    Record *r = table1;
    for (uint64_t k = i; k < N1; k += 256) {
      uint32_t sig = 0;
      uint32_t v = k;
      for (int j = 0; j < 4; j++) {
        v = (uint64_t)v * M1 % N1;
        sig = (sig << 8) + (v & 0xff);
      }
      r->signature = sig;
      r->seed = k;
      r++;
    }
    Record *endtable1 = r;

    // generate signatures (bytes 2 through 5) for all states of generator 2                                                                                         
    // that generate -i as the first byte.                                                                                                                           
    r = table2;
    for (uint64_t k = (-i & 0xff); k < N2; k += 256) {
      uint32_t sig = 0;
      uint32_t v = k;
      for (int j = 0; j < 4; j++) {
        v = (uint64_t)v * M2 % N2;
        sig = (sig << 8) + (-v & 0xff);
      }
      r->signature = sig;
      r->seed = k;
      r++;
    }
    Record *endtable2 = r;

    sort(table1, endtable1);
    sort(table2, endtable2);

    // iterate through looking for matches                                                                                                                           
    const Record *p1 = table1;
    const Record *p2 = table2;
    while (p1 < endtable1  && p2 < endtable2) {
      if (p1->signature < p2->signature) p1++;
      else if (p1->signature > p2->signature) p2++;
      else {
        check((uint64_t)p1->seed * M1_INV % N1, (uint64_t)p2->seed * M2_INV % N2);
        // NOTE: may skip some potential matches, if p1->signature==(p1+1)->signature or p2->signature==(p2+1)->signature                                            
        p1++;
      }
    }
  }
}
Keith Randall
sumber
Saya tidak berpikir harddisk akan cukup cepat untuk menjadi efisien untuk tugas itu. Menarik.
aaaaaaaaaaaa