C语言 我正在从事一个项目,我是使用 XOR 进行加密分析的新手.如何使用密码分析来获取明文



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

int main(int argc, char** argv) {
if (argc!=3) {
  printf("command (for example) : ./enc1 file_to_encrypt key_in_hexn");
  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 %sn", 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", 5);
 enc[strlen(file)+5]='';
 int fdc=open(enc, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
 if (fdc<0) {
    printf("cannot save the encrypted file %sn", 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

如何使用该信息获取明文?我是否对标题进行了 Xored ?非常感谢

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]

但是XOR是可逆的,所以你可以通过知道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]

OP 尚未接受答案,并且似乎仍然有问题,因此这是我的答案,借鉴了 user1202136 和 OmnipotentEntity 的答案。

要确定密钥,请逐个字符对加密文件的前 8 个字符进行 XOR 操作,其中包含您期望的标头字符串,例如 %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 %llxn", 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;
}

您的程序用于加密和解密。这是因为如上所述的异或的可逆性质。将加密的文件名和生成的密钥作为参数传递。

在此测试示例中,我首先使用给定密钥使用程序加密.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

希望这有帮助。

要添加到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]

最新更新