破解密码


12

我设计了一个简单的随机生成器,使用乘法和模数方法以混沌的方式循环两个数字。为此很好。

如果我将其用作密码生成器,则由于攻击者可以以计算有效的方式对一系列随机数进行种子反向工程,因此它容易受到已知的明文攻击。

为了证明密码破解,找到合法的种子值对,它们在[0; 255]范围内连续生成7个零,并且使用尽可能少的功率,CPU时间等。

这是用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功能的程序来更快地完成它是很优雅的。
在一块“ Museumware”上完成工作很优雅。
寻找一种可以仅使用笔和纸可行地使用的解决方法是非常优雅的。
用一种有启发性和易于理解的方式解释您的解决方案是很优雅的。

不宜使用多台或非常昂贵的计算机。


您确定对此有答案吗?
Dogbert,

是的,共有〜256个。而且我也相信,有了现代PC和正确的编程,就可以在几分钟内找到答案。
aaaaaaaaaaaaa

只是想知道,为什么GPU优雅而不是多个CPU?
JB

因为它们比CPU更难高效编程。您必须确保您实际上是在使用GPU,因为大多数其他着色器都处于瓶颈,因此没有必要让大多数着色器处于空闲状态。当然,您仍然必须实现一种有效的算法来得分。
aaaaaaaaaaaa

如果我提交工作代码,就好像我提交了大量种子对一样。游戏结束了吗?
JB

Answers:


6

C ++,44014022/164607120

它是用C ++语言编写的,使用1 GB的内存,并花了大约45秒钟找到了第一对。找到所有时间后,我将更新时间。

下面的代码。它首先查找所有产生4个零的对,然后通过简单的试验将其归零(请参见check方法)。它通过生成两个大数组来查找产生4个零的对,一个大数组包含state1生成器的前4个低阶字节,第二个数组包含state2生成器的前4个低阶字节的负数。然后对这些数组进行排序并搜索匹配项,该匹配项对应于整个生成器输出4个零开始的匹配。

数组太大而无法存储在内存中,因此它会按大小进行批量工作以适合内存。

看起来完整的运行大约需要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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.