一次性密码中两个密文的XOR信息给了我什么?

时间:2013-09-30 16:30:46

标签: c cryptography cryptanalysis

因此,我们被告知不要将同一个密钥用于一次性密码,因为如果攻击者知道这两个密文,他就可以得到两个纯文本的异或。例如:

Plain Text1: 0001011
Key        : 1010110
Ciphertext : 1011101

Plain Text2: 0110011
Key        : 1010110
Ciphertext : 1100101

XOR of ciphertexts
1011101
1100101
0111000

XOR of plaintexts (which of course match)
0001011
0110011
0111000

但是这个信息对攻击者有什么好处呢?他可以用两个纯文本的XOR做什么?

3 个答案:

答案 0 :(得分:2)

我想会有很多其他的答案,但是你可以做到以下几点 - 尝试猜测一个已知的单词在给定位置的任一文本中,并且x或该单词的位置。如果该值看起来合理(统计上看起来像您感兴趣的明文),那么您就知道两个明文的一部分。

假设您有以下x文明文(或密文,对于ciphertext == plaintext xor OTP的问题中描述的情况,它是相同的):

"\x10\x00\x1f\x17E\x0c\x00H\r\x1dR\x06\x0bK\x0c\x0e\x03\x1aE\x01\rR\x1a\x1a\x06P\x04\x00RE"

现在你尝试匹配字典中的单词,并发现如果你在第1位用“正确”字符串xor,你会得到:

some ot

好的,所以你的明文最有可能:

correct.....
some ot.....

现在尝试用xor开头用“ot ...”开头的单词,并找出你得到的“其他”(以及已知的开头):

correct ho

所以你的明文是:

correct ho....
some other....

等。继续这种方式,您可以恢复两个完整的字符串。对于不是英语单词的明文,这当然会更难,但仍然可能。而且您无需在任何时候知道OTP内容。

答案 1 :(得分:2)

两个明文的xor对攻击者非常有用。举个例子,空格字符(ascii 32)在用字母字符编码时,只需改变它们的大小写。因此,如果一个明文中有很多空格,你可以通过反转大小写来读取另一个明文。

答案 2 :(得分:2)

尽量使用用作一次通过的字母(使用循环算术)。如果有人获得cyper-text

GUTV

除了4个字母以外,人们对纯文本一无所知。 有可能 BOMB或LOVE或任何其他单词。你不能区分,也不可​​能比另一个更可能。

但是如果你有两个使用相同打击垫的纯文本,那么这意味着你只需要一个解决方案,就会自动定义第二个解决方案。

使用一些试验和错误(或带有词汇的计算机),你可以在最坏的情况下将其显着减少到几个选项。

所以你从完全安全的东西(真正的一次性填充)变成容易破碎的东西。

修改

这是在python中写的小饼干 你需要文字的文件。我从http://norvig.com/big.txt

开始

此代码执行的操作需要两个单词bomblove,并使用填充/密码haha对两者进行加密。然后它找出所有可能的密码,将这些cypertexts对解密为词汇表中的单词。

import re

with open("big.txt","r") as f:
    words = set(re.findall('[a-z]+', f.read().lower())) 

def encrypt(word,password):
   add_letters = lambda x,y:chr((ord(x)+ord(y)-2*ord('a'))%26 + ord('a'))
   return "".join(add_letters(*i) for i in zip(word.lower(),password.lower()))

def decrypt(word,password):
   sub_let = lambda x,y:chr((ord(x)-ord(y)+26)%26 + ord('a'))
   return "".join(sub_let(*i) for i in zip(word.lower(),password.lower()))


def crack(a,b):
    assert(len(a) == len(b))
    w = (i for i in words if len(i) == len(a))
    for i in w:
        password = decrypt(a,i)
        b_plain= decrypt(b,password)
        if b_plain in words:
            print(i,b_plain,password)

password = "haha"
a="bomb"
b="love"

a_cyper=encrypt(a,password)
b_cyper=encrypt(b,password)

print("cyper",a_cyper,b_cyper)

crack(a_cyper,b_cyper)

输出:

('cyper', 'iotb', 'soce')
('tomb', 'dove', 'paha')
('bath', 'lack', 'hoau')
('bomb', 'love', 'haha')  <---
('vote', 'foch', 'naax')
('reid', 'berg', 'rkly')
('tank', 'dawn', 'pogr')
('felo', 'peur', 'dkin')
('hath', 'rack', 'boau')
('cork', 'moan', 'gacr')
('rath', 'back', 'roau')
('ruth', 'buck', 'ruau')
('bank', 'lawn', 'hogr')
('rake', 'bath', 'rojx')
('mike', 'with', 'wgjx')
('hero', 'rear', 'bkcn')
('comb', 'move', 'gaha')
('foch', 'polk', 'daru')
('foci', 'poll', 'dart')
('both', 'lock', 'haau')
('peri', 'zeal', 'tkct')
('maim', 'warp', 'wolp')
('limb', 'vive', 'xgha')