这个Python加密脚本中到底发生了什么?

时间:2018-07-18 22:14:15

标签: python-3.x encryption binary binaryfiles

我目前正在学习将Python用于二进制文件。我在正在阅读的书中遇到以下代码:

FILENAME = 'pc_rose_copy.txt'

def display_contents(filename):
    fp = open(filename, 'rb')
    print(fp.read())
    fp.close()

def encrypt(filename):
    fp = open(filename, 'r+b')
    text = fp.read()
    fp.seek(0)
    for c in text:
        if c <= 128:
            fp.write(bytes([c+128]))
        else:
            fp.write(bytes([c-128]))
    fp.close()

display_contents(FILENAME)
encrypt(FILENAME)
display_contents(FILENAME)

我对此代码有一些疑问,我在书中找不到答案:

1)在第13行(“ if c <= 128”)中,由于文件是以二进制模式打开的,因此每个字符都将作为其在ASCII表中的索引被读取(即,等同于'if ord(c )<= 128'文件不是处于二进制模式吗?

2)如果是,那么检查任何字符的索引是否高于128有什么意义,因为这是一个.txt文件,其中包含罗密欧与朱丽叶的一段文字?

3)这一点更多是出于好奇,所以请原谅天真。我知道这在这种情况下不适用,但是说脚本遇到一个字节值为128的'c',因此将其添加128。 256字节是什么样子-是11111111 00000001吗?

2 个答案:

答案 0 :(得分:2)

真正发生的是该脚本切换了每个字节的最高有效位。等效于每个字节加减128。您可以通过在运行脚本之前/之后查看文件内容来查看此内容(Linux或Mac上的xxd -b file.txt可以让您看到确切的位/字节)。

下面是一些示例文本:

之前的文件内容:

11110000 10011111 10011000 10000100 00001010

之后的文件内容:

01110000 00011111 00011000 00000100 10001010

运行脚本两次(或任何偶数次)可以通过将所有高位切换回原始值来恢复原始文本。

问题/解答:

1)如果文件是ASCII编码的,则为是。例如对于文件abc\nc的值为97、98、99和10(换行符)。您可以通过在循环中添加print(c)来验证这一点。此脚本也可以在非ASCII编码的文件上运行*(上面的示例是UTF-8)。

2)这样我们就可以翻转位。即使我们仅处理ASCII文件(不保证),但由于我们已将每个字节添加128,因此从加密 ASCII文件获得的字节将大于128。因此,我们仍然需要处理这种情况才能解密自己的文件。

3)照原样,脚本崩溃,因为bytes()要求的值在0 <= x < 256范围内(请参阅documentation)。您可以创建一个使用echo -n -e '\x80\x80\x80' > 128.txt来中断脚本的文件。该脚本应该使用<来正确处理这种情况。

* 3除外)

答案 1 :(得分:1)

我认为加密功能也应该是解密功能。 加密从文本文件变为只有高字节的二进制文件。但是else子句用于从高字节返回到文本。我认为,如果您添加了额外的encrypt(FILENAME),您将获得原始文件。

'c'在文本文件中不能真正为128。最高值为126(〜),127为del“字符”。但是c = 128并加上128作为字节将在我们对256进行模运算时为0(环绕)。在C中,情况就是这样(对于无符号字符)。