깨진 암호를 깰


12

곱하기 및 계수 방법을 사용하여 혼란스러운 방식으로 두 숫자를 순환시키는 간단한 임의 생성기를 설계했습니다. 그것은 잘 작동합니다.

내가 암호 생성기로 사용한다면 공격자가 계산적으로 효율적인 방식으로 일련의 난수에서 시드를 리버스 엔지니어링 할 수 있다는 점을 감안하면 알려진 일반 텍스트 공격에 취약합니다.

암호가 손상되었음을 증명하려면 가능한 적은 전력, CPU 시간 등을 사용하여 [0; 255] 범위의 행에서 7 개의 0을 생성하는 올바른 시드 값 쌍을 찾으십시오.

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

후보 번호 쌍을 테스트하기위한 도구를 만들었으며 여기 에서 찾을 수 있습니다 .

다음 3 일 동안 스포일러는 허용되지 않으며 답변에는 일련의 숫자 만 포함되어야하며 물론 이전 솔버가 게시 한 것과 다른 세트 여야합니다. 그런 다음 코드를 게시하고 접근 방식을 설명하는 것이 좋습니다.

편집, 격리가 끝났습니다.
답변에는 고유 한 숫자 세트와 설명 및 코드가 모두 포함되어 해결 방법을 문서화해야합니다.

가장 우아한 솔루션이 승리합니다.

레코드 :
솔루션을 빠르게 찾을 수있는 프로그램 작성은 우아합니다.
GPU의 기능을 효율적으로 활용하여 더욱 빠르게 수행하는 프로그램을 만드는 것은 우아합니다.
"박물관"에서 작업을하는 것은 우아합니다.
펜과 종이만으로도 활용 가능한 솔루션 방법을 찾는 것은 매우 우아합니다.
유익하고 이해하기 쉬운 방식으로 솔루션을 설명하는 것은 우아합니다.

여러 대 또는 매우 비싼 컴퓨터를 사용하는 것은 중요하지 않습니다.


이에 대한 답변이 확실합니까?
Dogbert

예, ~ 256 개가 있습니다. 또한 최신 PC와 올바른 프로그래밍을 고려하면 몇 분 안에 답을 찾을 수 있다고 확신합니다.
aaaaaaaaaaaa

GPU가 우아하지만 여러 CPU가 아닌 이유는 무엇입니까?
JB

CPU보다 효율적으로 프로그래밍하기가 어렵 기 때문입니다. 다른 하위 시스템에 병목 현상이 발생하여 대부분의 셰이더를 유휴 상태로 두지 않아도 GPU를 실제로 사용하고 있는지 확인해야합니다. 물론 큰 점수를 얻기 위해 효율적인 알고리즘을 구현해야합니다.
aaaaaaaaaaaa

작업 코드를 제출하면 마치 많은 시드 쌍을 제출 한 것과 거의 같습니다. 게임 끝?
JB

답변:


6

C ++, 44014022/164607120

C ++로되어 있으며 1GB의 메모리를 사용하며이 첫 번째 쌍을 찾는 데 약 45 초가 걸렸습니다. 모든 것을 찾으면 시간을 업데이트하겠습니다.

아래 코드 먼저 4 개의 0을 생성하는 모든 쌍을 찾은 다음 간단한 시행으로 이들을 제거합니다 ( check방법 참조 ). 상태 1 생성기의 첫 번째 4 하위 바이트를 포함하고 두 번째는 state2 생성기의 첫 4 하위 바이트의 음수를 포함하는 두 개의 큰 배열을 생성하여 4 개의 0을 생성하는 쌍을 찾습니다. 그런 다음이 어레이를 정렬하고 일치하는 항목을 검색합니다. 이는 전체 제너레이터 출력을 시작하여 4 개의 0을 출력하는 것에 해당합니다.

배열은 메모리에 저장하기에 너무 커서 메모리에 맞도록 배치 된 크기로 작업을 수행합니다.

전체 실행에는 ~ 12 시간이 걸리는 것 같습니다.

편집 : 가능한 모든 시드를 얻는 데 ~ 1 시간 만 걸리도록 코드가 개선되었습니다. 이제 출력의 첫 바이트 당 하나씩 256 개의 서로 다른 파일로 테이블을 생성합니다. 그런 다음 각 파일을 독립적으로 처리 할 수 ​​있으므로 데이터를 다시 생성 할 필요가 없습니다.

편집 : 256 개의 서브 테이블을 한꺼번에 생성하지 않고 개별적으로 생성 할 수 있으므로 디스크가 필요하지 않습니다. 256MB를 사용하여 ~ 15 분까지 실행 시간.

#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++;
      }
    }
  }
}

하드 디스크가 작업에 효율적일 정도로 빠를 것이라고 생각하지 않았습니다. 흥미 롭군
aaaaaaaaaaaa
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.