使用Python 3和子进程在GPG中加密文件

3

如何使用子进程对文件进行加密,以便输出结果为字符串。

 password = '%030x' % random.randrange(16**30)
 encrypted_file = subprocess.geststatusoutput("echo "+password+
 "|gpg --password-fd 0 < "+ name_of_selected_file)

我希望将加密的文件转换为字符串,以便在使用post请求上传时使用加密文件。
使用gnupg库最好的方法是什么?


1
我从未尝试过,但有一个Python库可以使用GPG:https://pythonhosted.org/python-gnupg/。 - hiro protagonist
我不想为了一些可以简单编写脚本的东西而使用另一个外部库。 - user4511836
6
手动接口GnuPG有很多非常好的理由不要这样做。像你这样传递密码就是其中之一,当GnuPG正在工作时,系统上的每个人都可以通过读取命令行参数来读取它。它还会处理许多其他可能发生的问题,包括正确的错误处理。 - Jens Erat
1个回答

3
您可以使用subprocess.Popen()来执行类似于以下的gpg命令:
import shlex
import random
from subprocess import Popen, PIPE

passphrase = '%030x' % random.randrange(16**30)
source_filename = '/tmp/somefile'
cmd = 'gpg --batch --symmetric --cipher-algo AES256 --passphrase-fd 0 --output - {}'.format(source_filename)

# error handling omitted
p = Popen(shlex.split(cmd), stdout=PIPE, stdin=PIPE, stderr=PIPE)
encrypted_data = p.communicate(passphrase.encode())[0]

# Decryption - should work for Python 2 & 3
import os

r, w = os.pipe()    # pipe for sending passphrase from parent to child
try:
    os.set_inheritable(r, True)
except AttributeError:      # new in version 3.4
    pass
cmd = 'gpg --batch --decrypt --passphrase-fd {}'.format(r)
p = Popen(shlex.split(cmd), stdout=PIPE, stdin=PIPE, stderr=PIPE, close_fds=False)
os.close(r)    # closes fd in parent, child needs it
f = os.fdopen(w, 'w')
f.write(passphrase + '\n')    # '\n' seems required for Python 2 ???
f.close()
decrypted_data, stderr = p.communicate(encrypted_data)

# check that data was successfully roundtripped
assert open(source_filename).read() == decrypted_data.decode()

或者,仅适用于Python 3的解密:

import os
r, w = os.pipe()
cmd = 'gpg --batch --decrypt --passphrase-fd {}'.format(r)
p = Popen(shlex.split(cmd), stdout=PIPE, stdin=PIPE, stderr=PIPE, pass_fds=(r,))
os.close(r)    # closes fd in parent, child needs it
open(w, 'w').write(passphrase)
decrypted_data, stderr = p.communicate(encrypted_data)

# check that data was successfully roundtripped
assert open(source_filename).read() == decrypted_data.decode()

现在我并不是关于此方法安全性的专家,然而,使用communicate()将口令直接写入子进程的stdin比在命令行上回显口令更好——因为这样做会对任何能运行ps或等效命令的人可见。
另外,依赖于您的命令的shell级IO重定向需要shell=True参数传递给Popen,这可能会有其他安全隐患(请参阅Popen()文档中的警告)。
在我的gpg命令中,我假设您打算使用对称加密(您的示例没有暗示其他)。如果远程服务器需要能够解密加密文件内容,那么您将如何共享生成的口令?
您最好考虑使用公钥加密。

1
“你打算如何分享生成的口令?” 这是个好问题。 - msw
你的代码在Python 3上无法运行。你可以传递 passphrase = binascii.hexlify(os.urandom(15)).zfill(30) - jfs
1
@J.F.Sebastian是正确的,这段代码无法正常工作。现在我真的考虑使用gnupg库来找到解决方法。 - user4511836
1
解密过程非常类似。但是,由于加密的数据被发送到子进程的标准输入,您需要通过一个新的管道从父进程向子进程发送口令。我已经在我的答案中添加了一个通用的Python解决方案以及一个仅适用于Python 3的版本。 - mhawke
1
我发布的代码确实可以解密流。encrypted_data通过communicate()传递给gpg子进程。这将被发送到子进程的stdin。 - mhawke
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接