您现在的位置是:网站首页> 编程资料编程资料

Python编程密码学文件加密与解密代码解析_python_

2023-05-26 391人已围观

简介 Python编程密码学文件加密与解密代码解析_python_

在之前的章节中,编写的程序只能操作较少的信息,这些信息往往是以字符串的形式直接写在代码中的。但本章中的程序可以对整个文件进行加密和解密,文件的大小可以包括成千上万个字符。

本章要点

open()方法。

读、写文件。

write()、close()及read()文件对象操作方法。

os.path.exists()方法。

upper()、lower()及title()字符串操作方法。

startswith()及endswith()字符串操作方法。

time模块及time.time()方法

1 纯文本文件

对文件进行置换操作的程序只对纯文本(无格式文本)文件进行加/解密,这类文件指的是那些后缀名为 .txt 且文件中不包含除文本数据以外的内容的文件。要编写这类文件,可以选择在Windows系统下使用Notepad、在macOS系统下使用TextEdit,或者在Linux系统下使用gedit。(Word这样的文本处理程序同样也可以生成纯文本文件,但记住这些文件不能保存字体样式、字体大小、颜色或其他任何格式。)除上述文本编辑软件外,读者甚至可以使用IDLE文本编辑器,只要将文件后缀保存为 .txt 而不是通常使用的 .py 即可。

如果需要纯文本文件的样例,则可以从网络上下载一些txt小说,要将纯文本手动输入程序中,可能要花费很多时间,但如果使用现成的txt文件,则程序在数秒内就可以完成加密操作。

2 使用置换密码加密文件的源代码

在前两章置换密码测试程序的基础上,针对文件的置换密码程序引入了transposition Encrypt.py和transpositionDecrypt.py这两个文件,这样就可以调用encryptMessage()和decryptMessage() 这两个函数。因此,编写这个新程序将不用重新输入两个函数的代码。

选中 File▶New File,打开一个新的编辑窗口,将下列代码输入编辑窗口并将其存储为transpositionFileCipher.py。接下来,访问本书配套资源下载一个名为frankenstein.txt的文件,并将其放置在与py文件相同的路径之下,按下F5键运行这个程序。

transpositionFileCipher.py

 # 置换密码加/解密文件 # https://www.nostarch.com/crackingcodes/ (BSD Licensed) import time, os, sys, transpositionEncrypt, transpositionDecrypt def main():    inputFilename = 'frankenstein.txt'    # 注意,如果具有outputFilename 名称的文件已存在,则此程序    # 覆盖该文件    outputFilename = 'frankenstein.encrypted.txt'    myKey = 10    myMode = 'encrypt' # 设置为'encrypt'或'decrypt'    # 如果输入文件不存在,则程序提前终止    if not os.path.exists(inputFilename):      print('The file %s does not exist. Quitting...' % (inputFilename))      sys.exit()    # 如果输出文件已存在,则给用户退出的机会    if os.path.exists(outputFilename):      print('This will overwrite the file %s. (C)ontinue or (Q)uit?' %       (outputFilename))      response = input('> ')      if not response.lower().startswith('c'):        sys.exit()    # 从输入文件中读取消息    fileObj = open(inputFilename)    content = fileObj.read()    fileObj.close()    print('%sing...' % (myMode.title()))    # 测量加/解密所需时间    startTime = time.time()    if myMode == 'encrypt':      translated = transpositionEncrypt.encryptMessage(myKey, content)    elif myMode == 'decrypt':      translated = transpositionDecrypt.decryptMessage(myKey, content)    totalTime = round(time.time() - startTime, 2)    print('%sion time: %s seconds' % (myMode.title(), totalTime))    # 将置换后的消息写入输出文件    outputFileObj = open(outputFilename, 'w')    outputFileObj.write(translated)    outputFileObj.close()    print('Done %sing %s (%s characters).' % (myMode, inputFilename,     len(content)))    print('%sed file is %s.' % (myMode.title(), outputFilename)) # 如果运行 transpositionCipherFile.py (而不是作为模块引入),则 # 调用main() 函数 if __name__ == '__main__':    main()

3 运行置换密码加密文件程序的样例

运行transpositionFileCipher.py得到的输出如下。

Encrypting... Encryption time: 1.21 seconds Done encrypting frankenstein.txt (441034 characters). Encrypted file is frankenstein.encrypted.txt. 

这样就创建出了一个名为frankenstein.encrypted.txt 的新文件,该文件与 transposition FileCipher.py 在同一个路径下。使用IDLE文件编辑器打开这个新文件,就可以看到frankenstein.txt 中的文本内容被加密后的结果了。它应有的格式如下所示。

PtFiyedleo a arnvmt eneeGLchongnes Mmuyedlsu0#uiSHTGA r sy,n t ys s nuaoGeL sc7s, --snip--

每次加密一个文件,都可以将加密的结果发送给另一个人去解密它,对方同样需要文件置换操作程序的源代码。

要解密密文,可以对源代码进行下述改变(粗体部分),随后再次运行这个程序。

   inputFilename = 'frankenstein.encrypted.txt'    # 如果具有outputFilename 名称的文件已存在,则此程序    # 覆盖该文件    outputFilename = 'frankenstein.decrypted.txt'    myKey = 10    myMode = 'decrypt' # 设置为 'encrypt'或'decrypt

这时候运行该程序,就会在当前文件夹下创建出一个名为 frankenstein.decrypted.txt 的新文件,此时这个新文件的内容和原始明文是一致的。

4 文件操作

在深入研究 transpositionFileCipher.py 文件的源代码之前,首先要明白Python是如何对文件进行操作的。读取文件内容的3个步骤分别是打开文件、读取文件内容并将其存储到一个变量中、关闭文件。类似地,要将新内容写入文件中时,首先必须打开(或创建)一个文件,接着将新的内容写入其中,最后关闭这个文件。

4.1 打开文件

Python可以通过open()方法打开一个文件以供读取、写入内容时使用,其第一个参数为文件名。当要打开的文件和Python程序处于同一个文件夹下时,可以直接使用文件名,例如“thetimemachine.txt”,如果当前文件夹存在这么一个文件,则打开它的Python指令如下所示。

fileObj = open('thetimemachine.txt')

这样,一个文件对象就被存储在变量 fileObj 中了,之后进行读写操作时使用这个变量即可。

还可以用文件的绝对路径(absolute path)作为第一个参数,这样引号内就需要包括文件所在的文件夹及其所有父文件夹的名称,举个例子,类似“C:\\Users\\Al\\frankenstein.txt”(Windows系统下),或“/Users/Al/frankenstein.txt”(macOS及Linux系统下)格式的都是绝对路径。记住,Windows系统下,反斜线(/)前一定要多加一个反斜线用于转义。

举个例子,若想打开“frankenstein.txt”文件,则需要将其路径以字符串的形式作为open()方法的第一个参数(绝对路径的格式由使用的操作系统决定)。

fileObj = open('C:\\Users\\Al\\frankenstein.txt')

文件对象有多种用于读取、写入和关闭文件的方法,下面将对这些方法进行详细介绍,为方便说明这里调换一下顺序。

4.2 数据写入及文件关闭

对于文件的加密程序而言,在读取文本内容之后就需要将加密的数据写入一个新的文件中,这时用到的方法就是write()。

要想使用一个文件对象的write()方法,首先需要将文件以写模式打开,即将字符串 ‘w’ 传入open()方法作为其二个参数。open()方法的第二个参数是一个可选参数(optional parameter),这意味着open()方法在没有第二个参数的情况下仍然能够被调用。例如,将下列代码输入交互式运行环境中。

>>> fileObj = open('spam.txt', 'w')

这一行以写模式创建了一个名为“spam.txt”的文件,则可以对其进行编辑。如果在open()方法创建新文件的路径下存在一个同名文件,则该同名文件将被重写,因此,以写模式使用opne()方法时需要万分小心。

spam.txt 以写模式打开后,就可以调用write()方法往其中写入内容了。write()方法有一个参数:存储在一个字符串中的、将要被写入文件的内容。将下列代码输入交互式运行环境,把字符串Hello, world!写入 spam.txt 中。

>>> fileObj.write('Hello, world!')13

上述代码将字符串Hello, world!作为参数传入write()方法,把该字符串写入文件 spam.txt 中并打印出数字13,这个数字代表了写入文件中的字符数。

对文件的操作执行完成之后,需要通过调用文件对象的close()方法告知Python此事。

>>> fileObj.close()

除上述必定会覆盖原文件内容的写模式之外,还存在一个附加模式,在该模式下字符串会被添加到文件已有内容的末尾。尽管本章程序中没有用到这个模式,读者也可以自己尝试以附加模式打开文件,只需要将字符串 ‘a’ 作为 open() 方法的第二个参数即可。

如果在调用文件对象的write()方法时,遇到了“io.UnsupportedOperation: not readable”的报错信息,则可能是因为没有以写模式打开文件。调用open()方法的过程中若没有包括可选参数,则其默认值将被自动设置为写模式(‘r’),该模式下只允许使用者调用文件对象的read()方法。

4.3 读取文件

read()方法能够以字符串的形式返回文件中包含的所有内容,为验证其功能,本节将读取之前用wirte()方法创建的 spam.txt 文件。在交互式运行环境中运行如下代码。

>>> fileObj = open('spam.txt', 'r') >>> content = fileObj.read() >>> print(content) Hello world! >>> fileObj.close()

打开文件之后创建的文件对象存储在变量 fileObj 中,如果该对象存在,则可以使用read()方法读取文件的内容并将其存储在变量 content 中,随后打印该变量的值。执行完上述对文件对象的操作后,使用close()方法关闭该文件。

如果遇到“IOError: [Errno 2] No such file or directory”的报错信息,请确保想要打开的文件就在读者认为的路径下,并再次检查文件名和文件夹的名称是否正确输入。(文件夹即路径。)

在transpositionFileCipher.py程序中,对文件进行的加密和解密需要用到上文提到的所有open()、write() 及 close()方法。

5 创建main()函数

transpositionFileCipher.py 程序的第一部分应该看起来十分眼熟,第4行是一个import 语句,引入了transpositionEncypt.py和transpositionDecrypt.py两个程序和Python库中的time、os及sys模块,接下来的部分即main()函数,其中创建了程序需要用到的变量。

 # 置换密码加/解密文件 # https://www.nostarch.com/crackingcodes/ (BSD Licensed) import time, os, sys, transpositionEncrypt, transpositionDecrypt def main():    inputFilename = 'frankenstein.txt'    # 注意,如果具有outputFilename 名称的文件已存在,则此程序    # 覆盖该文件    outputFilename = 'frankenstein.encrypted.txt'    myKey = 10    myMode = 'encrypt' # 设置为 'encrypt'或'decrypt' 

变量 inputFilename 存储了待读取文件名的字符串,而加密后(或解密后)的内容写入以变量 outputFilename 的值命名的文件内。程序涉及的置换密码使用一个整数作为密钥,并存储在myKey中,同时,程序需要一个变量 myMode 存储字符串encrypt或decrypt以决定对 inputFilename 存储的文件进行何种操作。在读取 inputFilename 文件之前,首先要使用 os.path.exists() 检查该文件是否存在。

6 检查文件是否存在

读取文件往往不会存在什么危害,但往文件中写入内容时就需要多加小心了,这是因为以写模式调用open()方法时,若原文件已存在,会覆盖掉原文件中的内容。针对这个潜在问题,程序可以使用os.path.exists() 方法,检查要打开的文件是否已经存在。

6.1 os.path.exists() 方法

os.path.exists()方法只有一个参数,即文件名或指向文件的文件路径,如果文件存在,则返回True;否则返回False。该方法包含在path模块内,而path模块包含在

-六神源码网