注意:我假设加密和解密算法都是模256完成的。
由于您使用两个 8 位密钥对单个字节进行加密和解密,因此该密码的密钥空间是消息空间的 256 倍。这意味着每个 (A,E) 对有 256 种可能的 K 和 K2 组合。
具体来说,如果A = (E - (KEY ^ KEY2)) ^ KEY,那么KEY2 = (E - (A ^ KEY)) ^ KEY。对给定的(A,E) 对使用此公式,您可以轻松地遍历KEY 的所有256 个值并获得KEY2 的对应值。对每对明文/密文字符重复此过程,并计算所有(KEY,KEY2) 对的结果集的交集。明文和密文中有足够数量的字符,应该会给你一个独特的结果。
我知道您将此问题标记为 c#,但在 Python 中执行此类操作更容易。下面的代码可能效率不高,但没关系,因为我们在这里只处理一个玩具密码。
def retrieve_keys(plain,cipher):
# Initialize set with all 65536 possible key pairs
key_pairs = set([(x,y) for x in range(256) for y in range(256)])
# Intersect this set with the set of 256 possible key pairs for
# each plaintext/ciphertext pair
for i in range(len(plain)):
a, e = ord(plain[i]), ord(cipher[i])
s = set([])
# if a = (e - (key ^ key2)) ^ key, then key2 = (e - (a ^ key)) ^ key
for key in range(256):
s.add((key, ((e - (a ^ key)) % 256) ^ key))
key_pairs = key_pairs.intersection(s)
# Print out the remaining set of possible key pairs
for kp in key_pairs:
print "KEY=%d, KEY2=%d" % kp
# Example (should output "KEY=117, KEY2=80" and "KEY=245, KEY2=80"):
plaintext = "Hello world, this is a test"
ciphertext = "b5>>?z'?,>6~z&BA+zA+z9z&5+&"
retrieve_keys(plaintext,ciphertext)
编辑:以下 C# 代码由 Eric Lippert 建议:
foreach (var kp in
Enumerable.Range(0, plain.Length).Aggregate(
( from x in Enumerable.Range(0, 256)
from y in Enumerable.Range(0, 256)
select new { x, y }).ToList(),
(pairs, i) => pairs.Intersect(
from x in Enumerable.Range(0, 256)
select new { x, y =
((cipher[i] - (plain[i] ^ x)) % 256) ^ x }).ToList()))
Console.WriteLine(kp);