1

这对某些人来说可能真的很容易。我不太明白如何使用密码分析和蛮力破解 XOR 加密文件。我有一个 PDF 文件,该文件使用一个程序对 8 个字节乘以 8 个字节进行异或加密。程序代码是

int main(int argc, char** argv) {

if (argc!=3) {
  printf("command (for example) : ./enc1 file_to_encrypt key_in_hex\n");
  return 1;
}

// get the key
unsigned long long key=strtoull(argv[2], NULL, 16);

// open the file
char* file=argv[1];
int fdp=open(file, O_RDONLY);
if (fdp<0) {
   printf("cannot open the file %s\n", file);
   return 1;
} 

 // open the file to save the encryption
 char enc[strlen(file)+10];
 strncpy(enc, file, strlen(file));
 strncpy(enc+strlen(file), ".enc1\0", 5);
 enc[strlen(file)+5]='\0';
 int fdc=open(enc, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);

 if (fdc<0) {
    printf("cannot save the encrypted file %s\n", enc);
    return 1;
}

  // encryption
  unsigned long long buf;
  unsigned long long k;
  int len;
  k=key;
  while ((len=read(fdp, (char*)&buf, 8))>0) {
  buf^=k;
  k*=key;
   write(fdc, (char*)&buf, len);
 }

 close(fdp);
 close(fdc);
 return 0;
}

我知道 PDF 文件的标题是

%PDF-1.0 %PDF-1.1

如何使用该信息获取明文?我对标题进行异或吗?非常感谢

4

3 回答 3

1

XOR 很容易可逆。假设 m 是您的原始文件,而 e 是它的加密版本。然后

e[0] = k[0] ^ m[0]
e[1] = k[1] ^ m[1]
e[2] = k[2] ^ m[2]
e[3] = k[3] ^ m[3]

但是异或是可逆的,所以你可以通过知道 e 和 m 的一部分来找到 k:

k[0] = e[0] ^ m[0]
k[1] = e[1] ^ m[1]
k[2] = e[2] ^ m[2]
k[3] = e[3] ^ m[3]
于 2012-04-23T17:39:04.880 回答
1

OP 没有接受答案,而且似乎仍有问题,所以这是我的答案,来自 user1202136 和 OmnipotentEntity。

要确定密钥,将加密文件的前 8 个字符与您期望的标题字符串逐个字符进行异或运算,例如 %PDF-1.4。结果是一个长度相同的字符串,您可以将其复制到一个unsigned long long键中(也占用 8 个字节。)您的程序需要一个十六进制键值,因为strtoull给定的基本参数为 16。因此使用说明%llx符来格式化结果, 否则它将是十进制并且将不起作用。

void find_key(const char *filename, const char *m)
{
    // open the encrypted file
    FILE *fp = fopen(filename, "r");
    if (!fp)
        return;

    // read encrypted header
    char e[8];
    for (int i = 0; i < 8; i++)
        e[i] = fgetc(fp);
    fclose(fp);

    // xor with known header
    char k[8];
    for (int j = 0; j < 8; j++)
        k[j] = e[j] ^ m[j];

    // copy into 8 byte value, and output in base-16
    unsigned long long newkey;
    memcpy(&newkey, &k, 8);
    printf("Testing for %s gives key %llx\n", m, newkey);
}

由于您不确定标头版本,请使用不同的选项运行几次。如果加密文件是这些 .pdf 版本之一,那么您将拥有一个用于解密它的密钥。

int main(int argc, char *argv[])
{
    if (argc != 2)
        return 1;
    find_key(argv[1], "%PDF-1.0");
    find_key(argv[1], "%PDF-1.1");
    find_key(argv[1], "%PDF-1.2");
    find_key(argv[1], "%PDF-1.3");
    find_key(argv[1], "%PDF-1.4");
    return 0;
}

您的程序用于加密和解密。这是因为上面回答的 XOR 的可逆性质。将加密的文件名和生成的密钥作为参数传递。

在这个测试示例中,我首先使用您的程序使用给定密钥加密 .pdf,然后使用上述方法再次找到该密钥,然后使用您的程序使用最佳密钥结果对其进行解密。

$ ./enc1 test.pdf 1234ABCD
$ ./find-key test.pdf.enc1 
Testing for %PDF-1.0 gives key 30000001234abcd
Testing for %PDF-1.1 gives key 20000001234abcd
Testing for %PDF-1.2 gives key 10000001234abcd
Testing for %PDF-1.3 gives key 1234abcd
Testing for %PDF-1.4 gives key 70000001234abcd
$ ./enc1 test.pdf.enc1 1234abcd

希望这可以帮助。

于 2012-04-26T18:57:40.723 回答
0

要添加到 user1202136 的答案,

如果你有两个用相同密钥编码的不同消息,你可以检索密钥的第一个n字符(以及两个消息)(n较短消息的长度在哪里)(这就是 WEP 破解的工作原理,孩子们。)(以下不是代码,而是数学。)

eA[0] = k[0] ^ mA[0]
eB[0] = k[0] ^ mB[0]
eA[0] ^ eB[0] = k[0] ^ k[0] ^ mA[0] ^ mB[0]
eA[0] ^ eB[0] = mA[0] ^ mB[0]
eA[0] ^ eB[0] ^ mA[0] = mB[0]
mB[0] ^ eB[0] = k[0]
于 2012-04-23T17:43:35.590 回答