Python:有没有好的方法检查文本是否被加密?

6 投票
3 回答
7093 浏览
提问于 2025-04-16 23:13

我最近在玩一个叫做 cryptocat 的在线聊天服务,这个服务挺有意思的,它可以让你用一个密钥来加密你的消息,只有拥有相同密钥的人才能读懂你的消息。我觉得这个服务一个很有趣的地方是,如果用不同的密钥加密的文本,它会显示为 “[encrypted]”,而不是一堆看不懂的乱码。我的问题是,在Python中,有没有好的方法来判断一段文本是否是密文?我这次用的是RC4加密算法,因为这是我能实现的最快的算法(参考了维基百科上的伪代码)。谢谢。

3 个回答

0

判断的方法之一是看填充。你可以在消息的末尾加上标准的填充。如果解密后的消息最后没有这个标准的填充,那说明用错了钥匙。反过来说,虽然不一定,但通常也是对的。

5

每种有名的加密方式都会产生看起来完全随机的输出。你可以利用这个特点,快速判断你处理的是加密文本还是某种未知协议的数据。如果数据是加密的,你可以检查你监听到的字节流中字节值的分布情况——如果所有的值分布得很均匀,那么很有可能你在处理的是加密文本。

为了更有把握,你可以进行更复杂的测试,比如分析字节对或字节组三个字节的分布等。

另一方面,你也可以将你感兴趣的特定语言的统计数据(比如字母组合的出现频率)与观察到的数据进行比较。如果你的数据表现得很相似,那么更有可能你看到的是明文(未加密的文本)。

16

没有绝对的方法可以判断,但实际上你可以做两件事:

  1. 检查是否有很多非ASCII字符(如果你期待别人发送的是英文文本的话)。

  2. 检查字符出现的分布。在正常文本中,有些字母比其他字母出现得更频繁。但在加密文本中,所有字符出现的概率大致相同。

简单的方法是查看是否有任何字符出现的次数超过了(N/256) + 5 * sqrt(N/256),其中N是字符的总数。如果超过这个次数,那很可能是自然语言(没有加密的文本)。

在Python中(反转上面的逻辑,当文本是加密时返回“真”):

def encrypted(text):
    scores = defaultdict(lambda: 0)
    for letter in text: scores[letter] += 1
    largest = max(scores.values())
    average = len(text) / 256.0
    return largest < average + 5 * sqrt(average)

这个数学公式来源于平均数的高斯分布,方差等于平均数——虽然不是完美的,但应该足够接近。默认情况下(在文本量小的时候,这个方法不太可靠),这个方法会返回假(抱歉;之前我有一个错误的版本用“max()”,逻辑对于小数字是反的)。

撰写回答