作者选择了开放互联网/言论自由基金会 ,作为Write for DOnations计划的一部分,获得300美元的捐赠。
介绍
GnuPG软件包为生成和存储加密密钥提供了一个完整的解决方案。 它还允许您加密和签名数据和通信。
在本教程中,您将创建一系列使用Python 3和python-gnupg模块的脚本。 这些脚本将允许您签署和加密多个文件,并在运行之前验证脚本的完整性。
先决条件
在继续本教程之前,请完成以下先决条件:
- 按照Ubuntu 16.04 初始服务器安装教程设置Ubuntu 16.04服务器 。 遵循本教程之后,您应该可以访问非root用户的sudo用户帐户。 在本教程中,我们的用户将被命名为sammy 。
- 确保您已安装了Python 3和
pip
,请按照如何安装Python 3以及在Ubuntu 16.04上设置本地编程环境的第1步进行安装 。 - 按照这个GnuPG教程创建一个GnuPG密钥对。
第1步 - 检索密钥对信息
在完成必备条件中的GnuPG教程之后,您将在主目录下的.gnupg
存储密钥对。 GnuPG将密钥与用户名和电子邮件一起存储以帮助识别密钥对。 在这个例子中,我们的用户名是sammy ,我们的电子邮件地址是sammy@example.com
。
运行下面的命令以获取可用密钥的列表:
gpg --list-keys
Output/home/sammy/.gnupg/pubring.gpg
-----------------------------
pub 2048R/4920B23F 2018-04-23
uid Sammy <sammy@example.com>
sub 2048R/50C06279 2018-04-23
记下输出的uid
行中显示的电子邮件地址。 稍后您将需要它来识别您的密钥。
第2步 - 安装Python-GnuPG并签名文件
使用您的密钥,您可以安装python-gnupg
模块,该模块充当GnuPG的包装,以实现GnuPG和Python 3之间的交互。使用此模块,您将能够创建执行以下操作的Python脚本:
- 为文件创建分离的签名,通过将签名与文件解耦来为签名过程添加一层安全性。
- 加密文件。
- 解密文件。
- 验证分离的签名和脚本。
在继续测试这些文件上的脚本之前,您将首先创建脚本以及一些测试文件。
首先,让我们安装python-gnupg
模块以及fs
软件包,它将允许您打开,读取和编写测试文件。 更新你的软件包索引,并用pip
安装这些软件包:
sudo apt-get update
sudo pip3 install python-gnupg fs
有了这些软件包,我们就可以开始创建脚本和测试文件。
要存储脚本和测试文件,请在您的主目录中创建一个名为python-test
的文件夹:
cd ~/
mkdir python-test
移至此目录:
cd python-test/
接下来,我们创建三个测试文件:
echo "This is the first test file" > test1.txt
echo "print('This test file is a Python script')" > test2.py
echo "This is the last test file" > test3.txt
要为我们的测试文件创建分离的签名,我们创建一个名为signdetach.py
的脚本,该脚本将signdetach.py
执行目录中的所有文件为目标。 签名用作时间戳并证明文档的真实性。
分离的签名将存储在名为signatures/
的新文件夹中,该文件夹将在脚本运行时创建。
使用nano
或您最喜爱的文本编辑器打开一个名为signdetach.py
的新文件:
nano signdetach.py
我们首先导入脚本的所有必需模块。 这些包括启用文件导航的os
和fs
软件包,以及gnupg
:
#!/usr/bin/env python3
import os
import fs
from fs import open_fs
import gnupg
现在让我们设置GnuPG将找到其加密密钥的目录。 GnuPG默认将其密钥存储在.gnupg
,因此我们使用我们的用户名来配置它。 请务必将sammy替换为非root用户的名称:
...
gpg = gnupg.GPG(gnupghome="/home/sammy/.gnupg")
接下来,让我们创建一个home_fs
变量来将当前目录位置存储为一个文件对象。 这将使脚本可以在其执行的目录中工作:
...
home_fs = open_fs(".")
现在你的脚本将如下所示:
#!/usr/bin/env python3
import os
import fs
from fs import open_fs
import gnupg
gpg = gnupg.GPG(gnupghome="/home/sammy/.gnupg")
home_fs = open_fs(".")
此配置块是您在脚本中使用的基本模板,当您浏览本教程时。
接下来,添加代码来检查是否存在名为signatures/
的文件夹,如果它不存在,则创建它:
...
if os.path.exists("signatures/"):
print("Signatures directory already created")
else:
home_fs.makedir(u"signatures")
print("Created signatures directory")
创建一个空数组来存储文件名,然后扫描当前目录,并将所有文件名附加到files_dir
数组中:
...
files_dir = []
files = [f for f in os.listdir(".") if os.path.isfile(f)]
for f in files:
files_dir.append(f)
脚本的下一件事是为文件生成分离的签名。 通过files_dir
数组循环将使用密钥环上的第一个私钥为每个文件创建一个签名。 要访问私钥,您需要使用您设置的密码解锁。 将"my passphrase"
替换为您在先决条件中生成密钥对时使用的密码:
...
for x in files_dir:
with open(x, "rb") as f:
stream = gpg.sign_file(f,passphrase="my passphrase",detach = True, output=files_dir[files_dir.index(x)]+".sig")
os.rename(files_dir[files_dir.index(x)]+".sig", "signatures/"+files_dir[files_dir.index(x)]+".sig")
print(x+" ", stream.status)
完成后,所有签名将被移至signatures/
文件夹。 您的脚本将如下所示:
#!/usr/bin/env python3
import os
import fs
from fs import open_fs
import gnupg
gpg = gnupg.GPG(gnupghome="/home/sammy/.gnupg")
home_fs = open_fs(".")
if os.path.exists("signatures/"):
print("Signatures directory already created")
else:
home_fs.makedir(u"signatures")
print("Created signatures directory")
files_dir = []
files = [f for f in os.listdir(".") if os.path.isfile(f)]
for f in files:
files_dir.append(f)
for x in files_dir:
with open(x, "rb") as f:
stream = gpg.sign_file(f,passphrase="my passphrase",detach = True, output=files_dir[files_dir.index(x)]+".sig")
os.rename(files_dir[files_dir.index(x)]+".sig", "signatures/"+files_dir[files_dir.index(x)]+".sig")
print(x+" ", stream.status)
现在我们可以继续加密文件了。
第3步 - 加密文件
在文件夹中执行加密脚本将导致该文件夹内的所有文件在名为encrypted/
的新文件夹中被复制和加密。 用于加密文件的公钥是与您在密钥对配置中指定的电子邮件相对应的公钥。
打开一个名为encryptfiles.py
的新文件:
nano encryptfiles.py
首先,导入所有必需的模块,设置GnuPG的主目录,并创建当前的工作目录变量:
#!/usr/bin/env python3
import os
import fs
from fs import open_fs
import gnupg
gpg = gnupg.GPG(gnupghome="/home/sammy/.gnupg")
home_fs = open_fs(".")
接下来,让我们添加代码来检查当前目录是否已经有一个名为encrypted/
的文件夹,如果它不存在,就创建它:
...
if os.path.exists("encrypted/"):
print("Encrypt directory exists")
else:
home_fs.makedir(u"encrypted")
print("Created encrypted directory")
在搜索要加密的文件之前,让我们创建一个空数组来存储文件名:
...
files_dir = []
接下来,创建一个循环来扫描文件夹中的文件并将它们追加到数组中:
...
files = [f for f in os.listdir(".") if os.path.isfile(f)]
for f in files:
files_dir.append(f)
最后,让我们创建一个循环来加密文件夹中的所有文件。 完成后,所有加密文件将被传输到encrypted/
文件夹。 在本例中, sammy@example.com
是加密过程中使用的密钥的电子邮件ID。 请务必将其替换为您在第1步中记下的电子邮件地址:
...
for x in files_dir:
with open(x, "rb") as f:
status = gpg.encrypt_file(f,recipients=["sammy@example.com"],output= files_dir[files_dir.index(x)]+".gpg")
print("ok: ", status.ok)
print("status: ", status.status)
print("stderr: ", status.stderr)
os.rename(files_dir[files_dir.index(x)] + ".gpg", 'encrypted/' +files_dir[files_dir.index(x)] + ".gpg")
如果您的.gnupg
文件夹中存储了多个密钥,并且想要使用特定公用密钥或多个公用密钥进行加密,则需要通过添加其他收件人或替换当前收件人来修改recipients
数组。
完成后,您的encryptfiles.py
脚本文件将如下所示:
#!/usr/bin/env python3
import os
import fs
from fs import open_fs
import gnupg
gpg = gnupg.GPG(gnupghome="/home/sammy/.gnupg")
home_fs = open_fs(".")
if os.path.exists("encrypted/"):
print("Encrypt directory exists")
else:
home_fs.makedir(u"encrypted")
print("Created encrypted directory")
files_dir = []
files = [f for f in os.listdir(".") if os.path.isfile(f)]
for f in files:
files_dir.append(f)
for x in files_dir:
with open(x, "rb") as f:
status = gpg.encrypt_file(f,recipients=["sammy@example.com"],output= files_dir[files_dir.index(x)]+".gpg")
print("ok: ", status.ok)
print("status: ", status.status)
print("stderr: ", status.stderr)
os.rename(files_dir[files_dir.index(x)] + ".gpg", "encrypted/" +files_dir[files_dir.index(x)] + ".gpg")
现在让我们看看这个过程的第二部分:一次解密和验证多个文件。
第4步 - 解密文件
解密脚本的作用与加密脚本非常相似,只不过它意味着要在encrypted/
目录中执行。 启动时, decryptfiles.py
将首先识别使用的公钥,然后在.gnupg
文件夹中搜索相应的私钥以解密文件。 解密后的文件将被存储在一个名为decrypted/
的新文件夹中。
使用nano
或您最喜爱的编辑器打开一个名为decryptfiles.py
的新文件:
nano decryptfiles.py
首先插入配置设置:
#!/usr/bin/env python3
import os
import fs
from fs import open_fs
import gnupg
gpg = gnupg.GPG(gnupghome="/home/sammy/.gnupg")
home_fs = open_fs(".")
接下来,在脚本执行期间创建两个空数组来存储数据:
...
files_dir = []
files_dir_clean = []
这里的目标是脚本将解密后的文件放入自己的文件夹中; 否则,加密和解密的文件会混合在一起,导致难以找到特定的解密文件。 要解决此问题,您可以添加将扫描当前文件夹的代码,以查看decrypted/
文件夹是否存在,如果不存在,则创建该文件夹:
...
if os.path.exists("decrypted/"):
print("Decrypted directory already exists")
else:
home_fs.makedir(u"decrypted/")
print("Created decrypted directory")
扫描该文件夹并将所有文件名追加到files_dir
数组中:
...
files = [f for f in os.listdir(".") if os.path.isfile(f)]
for f in files:
files_dir.append(f)
所有加密文件都将.gpg
扩展名添加到文件名中,以表明它们已加密。 但是,当解密它们时,我们希望在没有这个扩展的情况下保存它们,因为它们不再被加密。
为此,循环访问files_dir
数组并从每个文件名中删除.gpg
扩展名:
...
for x in files_dir:
length = len(x)
endLoc = length - 4
clean_file = x[0:endLoc]
files_dir_clean.append(clean_file)
新的“清理过的”文件名存储在file_dir_clean
数组中。
接下来,让我们遍历这些文件并解密它们。 用您的密码替换"my passphrase"
以解锁私钥:
...
for x in files_dir:
with open(x, "rb") as f:
status = gpg.decrypt_file(f, passphrase="my passphrase",output=files_dir_clean[files_dir.index(x)])
print("ok: ", status.ok)
print("status: ", status.status)
print("stderr: ", status.stderr)
os.rename(files_dir_clean[files_dir.index(x)], "decrypted/" + files_dir_clean[files_dir.index(x)])
完成后,您的脚本文件将如下所示:
#!/usr/bin/env python3
import os
import fs
from fs import open_fs
import gnupg
gpg = gnupg.GPG(gnupghome="/home/sammy/.gnupg")
home_fs = open_fs(".")
files_dir = []
files_dir_clean = []
if os.path.exists("decrypted/"):
print("Decrypted directory already exists")
else:
home_fs.makedir(u"decrypted/")
print("Created decrypted directory")
files = [f for f in os.listdir(".") if os.path.isfile(f)]
for f in files:
files_dir.append(f)
for x in files_dir:
length = len(x)
endLoc = length - 4
clean_file = x[0:endLoc]
files_dir_clean.append(clean_file)
for x in files_dir:
with open(x, "rb") as f:
status = gpg.decrypt_file(f, passphrase="my passphrase",output=files_dir_clean[files_dir.index(x)])
print("ok: ", status.ok)
print("status: ", status.status)
print("stderr: ", status.stderr)
os.rename(files_dir_clean[files_dir.index(x)], "decrypted/" + files_dir_clean[files_dir.index(x)])
使用我们的解密脚本,我们可以继续验证多个文件的分离签名。
第5步 - 验证分离签名
要验证多个文件的分离数字签名,我们来编写一个verifydetach.py
脚本。 该脚本将搜索工作目录内的signatures/
文件夹,并验证每个文件的签名。
打开一个名为verifydetach.py
的新文件:
nano verifydetach.py
导入所有必需的库,设置工作目录和主目录,并创建空的files_dir
数组,如前面的示例中所示:
#!/usr/bin/env python3
import os
import fs
from fs import open_fs
import gnupg
gpg = gnupg.GPG(gnupghome="/home/sammy/.gnupg")
home_fs = open_fs(".")
files_dir = []
接下来,让我们扫描包含我们要验证的文件的文件夹。 文件名将被追加到空的files_dir
数组中:
...
files = [f for f in os.listdir(".") if os.path.isfile(f)]
for f in files:
files_dir.append(f)
最后,让我们使用自己的分离签名验证每个文件,使用循环移动files_dir
数组以搜索signatures/
文件夹内每个文件的分离签名。 当它发现分离的签名时,它将用它来验证文件。 最后一行输出每个文件验证的状态:
...
for i in files_dir:
with open("../../signatures/" + i + ".sig", "rb") as f:
verify = gpg.verify_file(f, i)
print(i + " ", verify.status)
完成后,您的脚本将如下所示:
#!/usr/bin/env python3
import os
import fs
from fs import open_fs
import gnupg
gpg = gnupg.GPG(gnupghome="/home/sammy/.gnupg")
home_fs = open_fs(".")
files_dir = []
files = [f for f in os.listdir(".") if os.path.isfile(f)]
for f in files:
files_dir.append(f)
for i in files_dir:
with open("../../signatures/" + i + ".sig", "rb") as f:
verify = gpg.verify_file(f, i)
print(i + " ", verify.status)
接下来,我们来看看在服务器上执行文件之前如何验证文件的签名。
第6步 - 验证文件
最终脚本将在脚本执行之前验证它们。 从这个意义上说,它与verifydetach
类似,但它具有启动已验证脚本的附加功能。 它通过将脚本名称作为参数,然后验证该文件的签名来工作。 如果验证成功,脚本将向控制台发送消息并启动已验证的脚本。 如果验证过程失败,脚本会将错误发布到控制台并中止文件的执行。
创建一个名为verifyfile.py
的新文件:
nano verifyfile.py
我们先导入必要的库并设置工作目录:
#!/usr/bin/env python3
import os
import fs
from fs import open_fs
import gnupg
gpg = gnupg.GPG(gnupghome="/home/sammy/.gnupg")
home_fs = open_fs(".")
要使脚本正常工作,需要存储要验证和执行的文件的名称。 为此,我们创建一个名为script_to_run
的新变量:
...
script_to_run = str(sys.argv[1])
该变量接受第一个参数并将其存储在新创建的变量中。 接下来,脚本将打开分离的签名文件,使用其签名验证script_to_run
的文件,然后在通过验证时执行它:
...
with open("../../signatures/" + script_to_run + ".sig", "rb") as f:
verify = gpg.verify_file(f, script_to_run)
print(script_to_run + " ", verify.status)
if verify.status == "signature valid":
print("Signature valid, launching script...")
exec(open(script_to_run).read())
else:
print("Signature invalid or missing, ")
print("aborting script execution")
完成的脚本将如下所示:
#!/usr/bin/env python3
import os
import sys
import fs
from fs import open_fs
import gnupg
gpg = gnupg.GPG(gnupghome="/home/sammy/.gnupg")
home_fs = open_fs(".")
script_to_run = str(sys.argv[1])
with open("../../signatures/" + script_to_run + ".sig", "rb") as f:
verify = gpg.verify_file(f, script_to_run)
print(script_to_run + " ", verify.status)
if verify.status == "signature valid":
print("Signature valid, launching script...")
exec(open(script_to_run).read())
else:
print("Signature invalid or missing, ")
print("aborting script execution")
我们已经完成了脚本的创建,但目前它们只能从当前文件夹中启动。 在下一步中,我们将修改他们的权限以使其全局可访问。
第7步 - 使系统范围内的脚本可用
为便于使用,我们让脚本可以从系统上的任何目录或文件夹执行,并将它们放在我们的$PATH
。 使用chmod
命令为您的非root用户提供文件所有者的可执行权限:
chmod +x *.py
现在找到您的$PATH
设置,运行以下命令:
echo $PATH
Output-bash: /home/sammy/bin:/home/sammy/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
如果目录的权限允许,则存储在$PATH
文件将可以从系统中的任何文件夹访问。 您可以将脚本放置在$PATH
任何位置,但现在让我们将脚本从python-test/
目录移至/usr/local/bin/
。
请注意,我们在复制文件时将删除.py
扩展名。 如果你看看我们创建的脚本的第一行,你会看到#!usr/bin/env python3
。 该行被称为shebang ,它帮助操作系统识别执行代码时使用的bash解释器或环境。 当我们执行脚本时,操作系统会注意到我们将Python指定为环境,并将代码传递给Python执行。 这意味着我们不再需要文件扩展名来帮助识别我们想要工作的环境:
sudo mv encryptfiles.py /usr/local/bin/encryptfiles
sudo mv decryptfiles.py /usr/local/bin/decryptfiles
sudo mv signdetach.py /usr/local/bin/signdetach
sudo mv verifyfile.py /usr/local/bin/verifyfile
sudo mv verifydetach.py /usr/local/bin/verifydetach
现在,脚本可以在系统中的任何位置执行,只需运行脚本名称以及脚本可能从命令行执行的任何参数即可。 下一步,我们将看看如何使用这些脚本的一些示例。
第8步 - 测试脚本
现在我们已经将脚本移动到我们的$PATH
,我们可以从服务器上的任何文件夹运行它们。
首先,用pwd
命令检查你是否仍在python-test
目录中工作:
pwd
输出应该是:
Output/home/sammy/python-test
您在本教程的早期创建了三个测试文件。 运行ls -l
命令列出文件夹中的文件:
ls -l
你应该看到三个文件存储在python-test
文件夹中:
Output-rw-rw-r-- 1 sammy sammy 15 Apr 15 10:08 test1.txt
-rwxrwxr-x 1 sammy sammy 15 Apr 15 10:08 test2.py
-rw-rw-r-- 1 sammy sammy 15 Apr 15 10:08 test3.txt
我们将测试这三个文件上的脚本。 您可以使用cat
命令快速显示加密前的文件内容,如下所示:
cat test1.txt
OutputThis is the first test file
我们首先创建所有文件的分离签名。 为此,请从当前文件夹内执行signdetach
脚本:
signdetach
OutputCreated signatures directory
test2.py signature created
test1.txt signature created
test3.txt signature created
注意输出中脚本检测到signatures/
目录不存在并生成它。 然后它创建文件签名。
我们可以通过再次运行ls -l
命令来确认:
ls -l
Outputtotal 16
drwxrwxr-x 2 sammy sammy 4096 Apr 21 14:11 signatures
-rw-rw-r-- 1 sammy sammy 15 Apr 15 10:08 test1.txt
-rwxrwxr-x 1 sammy sammy 15 Apr 15 10:08 test2.py
-rw-rw-r-- 1 sammy sammy 15 Apr 15 10:08 test3.txt
注意列表中项目之间的新signatures
目录。 让我们列出这个文件夹的内容,仔细看看其中一个签名。
要列出所有签名,请输入:
ls -l signatures/
Outputtotal 12
-rw-rw-r-- 1 sammy sammy 473 Apr 21 14:11 test1.txt.sig
-rw-rw-r-- 1 sammy sammy 473 Apr 21 14:11 test2.py.sig
-rw-rw-r-- 1 sammy sammy 473 Apr 21 14:11 test3.txt.sig
分离的签名文件可以通过.sig
扩展名进行标识。 同样, cat
命令可以显示其中一个签名的内容。 我们来看看签名test1.txt.sig
的内容:
cat signatures/test1.txt.sig
Output-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQEcBAABAgAGBQJa20aGAAoJENVtx+Y8cX3mMhMH+gOZsLJX3aEgUPZzDlKRWYec
AyrXEGp5yIABj7eoLDKGUxftwGt+c4HZud1iEUy8AhtW/Ea6eRlMFPTso2hb9+cw
/MyffTrWGpa0AGjNvf4wbxdq7TNpAlw4nmcwKpeYqkUu2fP3c18oZ3G3R3+P781w
GWori9FK3eTyVPs9E0dVgdo7S8G1pF/ECo8Cl4Mrj80rERAitQAMbSaN/dF0wUKu
okRZPJPVjd6GwqRRkXoqwh0vm4c+p3nAhFV+v7uK2BOUIJKPFbbn58vmmn+LVaBS
MFWSb+X85KwwftIezqCV/hqsMKAuhkvfIi+YQFCDXElJMtjPBxxuvZFjQFjEHe8=
=4NB5
-----END PGP SIGNATURE-----
此输出是test1.txt
的分离签名。
使用签名后,可以继续对我们的文件进行加密。 为此,请执行encryptfiles
脚本:
encryptfiles
OutputCreated encrypted directory
ok: True
status: encryption ok
stderr: [GNUPG:] BEGIN_ENCRYPTION 2 9
[GNUPG:] END_ENCRYPTION
ok: True
status: encryption ok
stderr: [GNUPG:] BEGIN_ENCRYPTION 2 9
[GNUPG:] END_ENCRYPTION
ok: True
status: encryption ok
stderr: [GNUPG:] BEGIN_ENCRYPTION 2 9
[GNUPG:] END_ENCRYPTION
从输出中,请注意脚本创建了encrypted/
文件夹。 另请注意,所有文件均已成功加密。 再次运行ls -l
命令并注意目录中的新文件夹:
ls -l
Outputtotal 20
drwxrwxr-x 2 sammy sammy 4096 Apr 21 14:42 encrypted
drwxrwxr-x 2 sammy sammy 4096 Apr 21 14:11 signatures
-rw-rw-r-- 1 sammy sammy 15 Apr 15 10:08 test1.txt
-rw-rw-r-- 1 sammy sammy 15 Apr 15 10:08 test2.py
-rw-rw-r-- 1 sammy sammy 15 Apr 15 10:08 test3.txt
我们来看看test1.txt
的消息现在看起来是如何加密的:
cat encrypted/test1.txt.gpg
Output-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
hQEMA9Vtx+Y8cX3mAQf9FijeaCOKFRUWOrwOkUw7efvr5uQbSnxxbE/Dkv0y0w8S
Y2IxQPv4xS6VrjhZQC6K2R968ZQDvd+XkStKfy6NJLsfKZM+vMIWiZmqJmKxY2OT
8MG/b9bnNCORRI8Nm9etScSYcRu4eqN7AeUdWOXAFX+mo7K00IdEQH+0Ivyc+P1d
53WBgWstt8jHY2cn1sLdoHh4m70O7v1rnkHOvrQW3AAsBbKzvdzxOa0/5IKGCOYF
yC8lEYfOihyEetsasx0aDDXqrMZVviH3KZ8vEiH2n7hDgC5imgJTx5kpC17xJZ4z
LyEiNPu7foWgVZyPzD2jGPvjW8GVIeMgB+jXsAfvEdJJAQqX6qcHbf1SPSRPJ2jU
GX5M/KhdQmBcO9Sih9IQthHDXpSbSVw/UejheVfaw4i1OX4aaOhNJlnPSUDtlcl4
AUoBjuBpQMp4RQ==
=xJST
-----END PGP MESSAGE-----
作为加密过程的结果,存储在原始文件中的句子已被转换为一系列复杂的字符和数字。
现在文件已经被签名和加密,可以删除原始文件并从加密文件中恢复原始信息。
要删除原件,请键入:
rm *.txt *.py
再次运行ls -l
命令以确保所有原始文件已被删除:
ls -l
Outputtotal 8
drwxrwxr-x 2 sammy sammy 4096 Apr 21 14:42 encrypted
drwxrwxr-x 2 sammy sammy 4096 Apr 21 14:11 signatures
随着原始文件消失,让我们解密并验证加密文件。 转到encrypted
文件夹并列出所有文件:
cd encrypted/ && ls -l
Outputtotal 12
-rw-rw-r-- 1 sammy sammy 551 Apr 21 14:42 test1.txt.gpg
-rw-rw-r-- 1 sammy sammy 551 Apr 21 14:42 test2.py.gpg
-rw-rw-r-- 1 sammy sammy 551 Apr 21 14:42 test3.txt.gpg
要解密文件,请从当前文件夹中运行解密文件脚本:
decryptfiles
OutputCreated decrypted directory
ok: True
status: decryption ok
stderr: [GNUPG:] ENC_TO D56DC7E63C717DE6 1 0
[GNUPG:] USERID_HINT D56DC7E63C717DE6 Autogenerated Key <sammy@example.com>
[GNUPG:] NEED_PASSPHRASE D56DC7E63C717DE6 D56DC7E63C717DE6 1 0
[GNUPG:] GOOD_PASSPHRASE
gpg: encrypted with 2048-bit RSA key, ID 3C717DE6, created 2018-04-15
"Autogenerated Key <sammy@example.com>"
[GNUPG:] BEGIN_DECRYPTION
[GNUPG:] DECRYPTION_INFO 2 9
[GNUPG:] PLAINTEXT 62 1524321773
[GNUPG:] PLAINTEXT_LENGTH 15
[GNUPG:] DECRYPTION_OKAY
[GNUPG:] GOODMDC
[GNUPG:] END_DECRYPTION
ok: True
status: decryption ok
stderr: [GNUPG:] ENC_TO D56DC7E63C717DE6 1 0
[GNUPG:] USERID_HINT D56DC7E63C717DE6 Autogenerated Key <sammy@example.com>
[GNUPG:] NEED_PASSPHRASE D56DC7E63C717DE6 D56DC7E63C717DE6 1 0
[GNUPG:] GOOD_PASSPHRASE
gpg: encrypted with 2048-bit RSA key, ID 3C717DE6, created 2018-04-15
"Autogenerated Key <sammy@example.com>"
[GNUPG:] BEGIN_DECRYPTION
[GNUPG:] DECRYPTION_INFO 2 9
[GNUPG:] PLAINTEXT 62 1524321773
[GNUPG:] PLAINTEXT_LENGTH 15
[GNUPG:] DECRYPTION_OKAY
[GNUPG:] GOODMDC
[GNUPG:] END_DECRYPTION
ok: True
status: decryption ok
stderr: [GNUPG:] ENC_TO D56DC7E63C717DE6 1 0
[GNUPG:] USERID_HINT D56DC7E63C717DE6 Autogenerated Key <sammy@example.com>
[GNUPG:] NEED_PASSPHRASE D56DC7E63C717DE6 D56DC7E63C717DE6 1 0
[GNUPG:] GOOD_PASSPHRASE
gpg: encrypted with 2048-bit RSA key, ID 3C717DE6, created 2018-04-15
"Autogenerated Key <sammy@example.com>"
[GNUPG:] BEGIN_DECRYPTION
[GNUPG:] DECRYPTION_INFO 2 9
[GNUPG:] PLAINTEXT 62 1524321773
[GNUPG:] PLAINTEXT_LENGTH 15
[GNUPG:] DECRYPTION_OKAY
[GNUPG:] GOODMDC
[GNUPG:] END_DECRYPTION
该脚本返回status: decryption ok
每个文件的status: decryption ok
,表示每个文件都被成功解密。
更改为新的decrypted/
文件夹,并使用cat
命令显示test1.txt
的内容:
cd decrypted/ && cat test1.txt
OutputThis is the first test file
我们已经恢复了存储在我们删除的test1.txt
文件中的消息。
接下来,让我们通过使用verifydetach
脚本验证其签名来确认此消息确实是原始消息。
签名文件包含签名者的身份以及使用签名文档中的数据计算出的哈希值。 在验证过程中, gpg
将采用发件人的公钥,并将其与哈希算法一起用于计算数据的哈希值。 所计算的散列值和存储在签名内的值需要匹配以便验证成功。
任何篡改原始文件,签名文件或发件人的公钥都会导致哈希值发生变化,验证过程失败。
从decrypted
文件夹中运行脚本:
verifydetach
Outputtest2.py signature valid
test1.txt signature valid
test3.txt signature valid
您可以从输出中看到所有文件都具有有效签名,这意味着文档在此过程中未被篡改。
现在让我们看看在签名后更改文档时会发生什么。 使用nano
打开test1.txt
文件:
nano test1.txt
现在将下面的句子添加到文件中:
This is the first test file
Let's add a sentence after signing the file
保存并关闭文件。
现在重新运行verifydetach
脚本并注意输出如何变化:
verifydetach
Outputtest2.py signature valid
test1.txt signature bad
test3.txt signature valid
请注意,GnuPG在验证test1.txt
时返回了signature bad
。 这是因为我们在签名后对文件进行了更改。 请记住,在验证过程中, gpg
会将存储在签名文件中的哈希值与它从您签名的文档中计算出的哈希值进行比较。 我们对文档所做的更改导致gpg
为test1.txt
计算不同的哈希值。 有关哈希算法如何工作的更详细的讨论可以在这里找到。
对于我们的最后一个测试,让我们在执行之前使用verifyfile
来验证脚本。 该脚本可以看作是verifydetach
脚本的扩展,但有以下区别:如果脚本通过验证过程,验证verifyfile
将继续启动它。
test2.py
脚本在启动时向控制台输出一个字符串。 让我们用它来演示验证verifyfile
脚本的工作方式。
使用verifyfile
运行test2.py
脚本:
verifyfile test2.py
Outputtest2.py signature valid
Signature valid, launching script...
The second test file is a Python script
从输出中您可以看到脚本验证了文件的签名,根据验证打印了适当的结果,然后启动了脚本。
让我们通过向文件添加一行代码来测试验证过程。 打开test2.py
并插入以下代码行:
nano test2.py
print "The second test file is a Python script"
print "This line will cause the verification script to abort"
现在重新运行verifyfile
脚本:
verifyfile test2.py
Outputtest2.py signature bad
Signature invalid,
aborting script execution
脚本验证失败,导致脚本启动中止。
结论
python-gnupg
模块允许在各种加密工具和Python之间进行集成。 快速加密或验证数据流完整性的能力在某些情况下至关重要,例如查询数据或将数据存储到远程数据库服务器。 GnuPG密钥也可用于创建备份和SSH验证等功能,或与VPN设置结合使用。
要了解关于python-gnupg
模块的更多信息,可以访问python-gnupg项目页面 。 有关文件散列的更多信息,请参阅本指南关于如何验证下载的文件 。