以下简短的 Python 脚本采用三个命令行参数:密码短语、输入路径和输出路径。 然后,它使用密码短语解密输入路径的内容,并将解密的内容放在输出路径中。
from gpg import Context
import sys
pp = sys.argv[1] # passphrase
enc = sys.argv[2] # input file (assumed to be encrypted)
dec = sys.argv[3] # output file
with open(enc, 'rb') as reader, open(dec, 'wb') as writer, Context() as ctx:
try:
ctx.decrypt(reader, sink=writer, passphrase=pp)
except Exception as e:
print(str(e), file=sys.stderr)
只要提供正确的密码,此解密就可以正常工作,但它显然会导致缓存此类正确的密码短语,因此无论提供的密码短语如何,任何后续解密尝试都会成功。 (我在这篇文章的末尾给出了更全面的说明我的意思,以及版本细节。
显然,有一些密码缓存正在进行,但我并不真正了解细节。
我想知道的是:如何修改 Python 脚本以使其禁用密码短语的缓存? 请注意,我对如何在脚本之外禁用密码缓存不感兴趣! 我希望脚本自动禁用密码缓存。 这可能吗?
这是我上面提到的一个详细例子。 脚本./demo.py
是我上面列出的其来源的脚本。 重要提示:下面给出的代码仅在我从命令行执行时显示。 如果我将其放入文件中并将其作为脚本执行(或获取),则所有具有错误密码的解密都将失败,无论之前使用正确密码短语的任何成功解密。
# Prologue: preparation
# First, define some variables
% ORIGINAL=/tmp/original.txt
% ENCRYPTED=/tmp/encrypted.gpg
% DECRYPTED=/tmp/decrypted.txt
% PASSPHRASE=yowzayowzayowza
# Next, create a cleartext original:
% echo 'Cool story, bro!' > "$ORIGINAL"
# Next, encrypt the original using /usr/bin/gpg
% rm -f "$ENCRYPTED"
% /usr/bin/gpg --batch --symmetric --cipher-algo=AES256 --compress-algo=zlib --passphrase="$PASSPHRASE" --output="$ENCRYPTED" "$ORIGINAL"
# Confirm encryption
% od -c "$ENCRYPTED"
0000000 214 r 004 t 003 002 304 006 020 % q 353 335 212 361 322
0000020 U 001 w 350 335 K 347 320 260 224 227 025 275 274 033 X
0000040 020 352 002 006 254 331 374 300 221 265 021 376 254 9 $ <
0000060 233 275 361 226 340 177 330 ! c 372 017 & 300 352 $ k
0000100 252 205 244 336 222 N 027 200 | 211 371 r Z ] 353 6
0000120 261 177 b 336 026 023 367 220 354 210 265 002 : r 262 037
0000140 367 L H 262 370
0000146
# Now, the demonstration proper.
# Initially, decryption with the wrong passphrase fails:
% rm -f "$DECRYPTED"
% python ./demo.py "certainly the wrong $PASSPHRASE" "$ENCRYPTED" "$DECRYPTED"
gpgme_op_decrypt_verify: GPGME: Decryption failed
# Decryption with the right passphrase succeeds:
% rm -f "$DECRYPTED"
% python ./demo.py "$PASSPHRASE" "$ENCRYPTED" "$DECRYPTED"
% od -c "$DECRYPTED"
0000000 C o o l s t o r y , b r o !
0000020 n
0000021
# After the first successful decryption with the right
# passphrase, decryption with the wrong passphrase always
# succeeds:
% rm -f "$DECRYPTED"
% python ./demo.py "certainly the wrong $PASSPHRASE" "$ENCRYPTED" "$DECRYPTED"
% od -c "$DECRYPTED"
0000000 C o o l s t o r y , b r o !
0000020 n
0000021
# Some relevant version info
% python -c 'import gpg; print((gpg.version.versionstr, gpg.version.gpgme_versionstr))'
('1.10.0', '1.8.0')
% gpg --version
gpg (GnuPG) 2.1.18
libgcrypt 1.7.6-beta
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Home: /home/kj146/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2
% python --version
Python 3.5.3
% uname -ar
Linux parakeet 3.16.0-4-amd64 #1 SMP Debian 3.16.43-2 (2017-04-30) x86_64 GNU/Linux
挖掘 Cgpgme
库(这是您使用的 Python 库正在包装的内容),有:
https://www.gnupg.org/documentation/manuals/gpgme/Context-Flags.html#Context-Flags
"no-symkey-cache"
For OpenPGP disable the passphrase cache used for symmetrical en- and decryption.
This cache is based on the message specific salt value. Requires at least GnuPG
2.2.7 to have an effect.
我不确定上下文如何与文件系统或 GPG 代理交互,但您的第一次尝试应该是将此标志设置为 true。
-
根据消息来源:
Context.decrypt
可以使用"pinentry"获取密码短语,我认为默认情况下上下文使用它(在您的情况下是某种 gpg 代理) -
根据您的桌面环境,某些"代理"可能会用作 Pinentry 的一部分,以便它"记住"密码短语。
-
我认为您应该使用
pinentry_mode=gpg.constants.SOME_CONSTANT
初始化上下文(也许gpg.constants.PINENTRY_MODE_ERROR
...我不确定:没有gpgme的经验,只是调查了文档和代码)模式:查看文档 -
或者你可以停止/杀死
gpg-agent
/kde-wallet
/gnome-keyring
:其中一个正在执行"缓存"。 -
或将行
no-use-agent
添加到~/.gnupg/gpg.conf
-
也许初始化后调用
ctx.set_ctx_flag("no-symkey-cache", "1")
可以解决您的问题(请参阅其他答案)
没有纯粹的pythonic方法可以做到这一点。你可以做的最python化的是将PYTHONDONTWRITEBYTECODE
环境变量设置为1
。下面是设置变量的代码:
import os
os.environ['PYTHONDONTWRITEBYTECODE'] = 1
注意:此代码还将禁用其他 python 脚本上的缓存
在 GnuPG 文档的第 9.6 章下,有一个名为"所有命令和选项的列表">的部分。
其中显示了可用于执行以下操作的--forget
选项:
"从缓存中刷新给定缓存 ID 的密码。">
在"GnuPG Made Easy">参考手册的第 7.5 章密钥管理下,有一个名为删除密钥的部分,其中包含一个名为gpgme_op_delete_ext
的函数的文档,该函数允许您删除公钥。
您还可以使用GPGME_DELETE_ALLOW_SECRET
标志删除私钥,根据文档
"如果未设置,则仅删除公钥。如果设置,密钥也会被删除(如果支持)。
注意:要跳过用户确认,您可以使用GPGME_DELETE_FORCE
标志。
祝你好运。