Phá vỡ mật mã bị hỏng


12

Tôi đã thiết kế một trình tạo ngẫu nhiên đơn giản, quay vòng hai số một cách hỗn loạn bằng phương pháp nhân và mô đun. Nó hoạt động tuyệt vời cho điều đó.

Nếu tôi sử dụng nó như một trình tạo mật mã, tuy nhiên nó sẽ dễ bị tấn công bằng văn bản đã biết, do kẻ tấn công có thể đảo ngược hạt giống từ một loạt các số ngẫu nhiên theo cách tính toán hiệu quả.

Để chứng minh mật mã bị hỏng, hãy tìm một cặp giá trị hạt hợp pháp tạo 7 số 0 liên tiếp trong phạm vi [0; 255], sử dụng càng ít năng lượng, thời gian CPU, v.v. càng tốt.

Đây là trình tạo ngẫu nhiên được viết bằng 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>")
}

Tôi đã làm một công cụ để kiểm tra các cặp số ứng cử viên, nó có thể được tìm thấy ở đây .

Trong 3 ngày tiếp theo, không cho phép các spoiler , một câu trả lời chỉ chứa một bộ số và tất nhiên nó phải là một bộ khác với các bộ được đăng bởi người giải trước. Sau đó, bạn được khuyến khích đăng mã và giải thích cách tiếp cận của bạn.

Chỉnh sửa, kiểm dịch đã kết thúc:
Câu trả lời phải chứa cả một bộ số và giải thích và mã duy nhất để ghi lại phương pháp giải.

Giải pháp thanh lịch nhất chiến thắng.

Đối với hồ sơ:
Viết một chương trình có thể tìm ra giải pháp nhanh chóng là thanh lịch.
Làm cho một chương trình sử dụng các tính năng của GPU một cách hiệu quả để làm điều đó nhanh hơn là điều tuyệt vời.
Làm công việc trên một phần của "bảo tàng" là thanh lịch.
Tìm một phương pháp giải pháp khả thi có thể được sử dụng chỉ bằng bút và giấy là rất thanh lịch.
Giải thích giải pháp của bạn một cách hướng dẫn và dễ hiểu là thanh lịch.

Sử dụng nhiều máy tính hoặc rất đắt tiền là không phù hợp.


Bạn có chắc chắn một câu trả lời cho điều này?
Dogbert

Vâng, có ~ 256 người trong số họ. Và tôi cũng chắc chắn rằng có thể tìm thấy câu trả lời trong vài phút, với một PC hiện đại và lập trình đúng.
aaaaaaaaaaaa

Chỉ cần tự hỏi, tại sao GPU thanh lịch nhưng không có nhiều CPU?
JB

Bởi vì chúng khó lập trình hiệu quả hơn CPU. Bạn phải chắc chắn rằng bạn đang thực sự sử dụng GPU, không có điểm nào khiến hầu hết các shader không hoạt động vì một số hệ thống con khác đang bị nghẽn cổ chai. Và tất nhiên bạn vẫn phải thực hiện một thuật toán hiệu quả để ghi điểm lớn.
aaaaaaaaaaaa

Nếu tôi gửi mã làm việc của mình, gần như tôi đã gửi một loạt các cặp hạt giống. Trò chơi kết thúc chưa?
JB

Câu trả lời:


6

C ++, 44014022/16607120

Đó là trong C ++, sử dụng 1 GB bộ nhớ và mất khoảng 45 giây để tìm cặp đầu tiên này. Tôi sẽ cập nhật thời gian khi nó tìm thấy tất cả.

Mã dưới đây. Đầu tiên, nó tìm thấy tất cả các cặp tạo ra 4 số không, sau đó loại bỏ chúng bằng cách dùng thử đơn giản (xem checkphương thức). Nó tìm thấy các cặp tạo ra 4 số 0 bằng cách tạo hai mảng lớn, một mảng chứa 4 byte thứ tự thấp đầu tiên của trình tạo state1 và thứ hai chứa âm của 4 byte thứ tự thấp đầu tiên của trình tạo state2. Các mảng này sau đó được sắp xếp và tìm kiếm một kết quả khớp, tương ứng với trình tạo tổng thể xuất ra 4 số không để bắt đầu.

Các mảng quá lớn để lưu trữ trong bộ nhớ, do đó, nó hoạt động theo lô có kích thước vừa với bộ nhớ.

Có vẻ như quá trình chạy hoàn chỉnh sẽ mất ~ 12 giờ.

Chỉnh sửa : Cải thiện mã để chỉ mất ~ 1 giờ để có được tất cả các hạt giống có thể. Bây giờ, nó tạo các bảng thành 256 tệp khác nhau, mỗi tệp cho mỗi byte đầu ra đầu tiên. Sau đó chúng tôi có thể xử lý từng tệp một cách độc lập để chúng tôi không phải tạo lại dữ liệu.

Chỉnh sửa : Hóa ra bạn có thể tạo 256 phụ đề riêng lẻ thay vì tất cả cùng một lúc, do đó không cần đĩa. Thời gian chạy xuống ~ 15 phút với 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++;
      }
    }
  }
}

Tôi không nghĩ rằng một ổ cứng sẽ đủ nhanh để có hiệu quả cho nhiệm vụ. Hấp dẫn.
aaaaaaaaaaaa
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.