用RAW键在Python中解密GPG加密文件
我正在尝试使用Python使用RAW键解密GPG加密文件。不是密钥环中的密码,而不是一个格式化的文件,而只是该文件已加密的键的字面原始字节。
我首先创建了一个测试文件:
~$ echo "It would be really cool if this worked" >> PGPDecryptorTest1.txt
然后,我使用AES256加密使用密码“ A”和SHA256密钥推导:
~$ gpg --symmetric --s2k-mode 0 --s2k-digest-algo SHA256 --cipher-algo AES256 PGPDecryptorTest1.txt
我编写了以下简短脚本来解码文件:
import sys
from Crypto.Cipher import AES
# With s2k-mode 0 specified, key is just SHA256 hash of passphrase
hash_a = b"\xca\x97\x81\x12\xca\x1b\xbd\xca\xfa\xc2\x31\xb3\x9a\x23\xdc\x4d\xa7\x86\xef\xf8\x14\x7c\x4e\x72\xb9\x80\x77\x85\xaf\xee\x48\xbb"
key = hash_a
def main(filename):
with open(filename, "rb") as f:
# First 9 bytes are header, ignore them and read the rest
contents = f.read()[9:]
# IV is size (block size + 2)
# AES uses 16-byte (128-bit) blocks
# Last two bytes are for checksum
iv = contents[0:16 + 2]
# Rest of contents should be ciphertext
ciphertext = contents[16 + 2:]
# Use openPGP special cipher mode
cipher = AES.new(key, AES.MODE_OPENPGP, iv=iv)
plaintext = cipher.decrypt(ciphertext)
print("Output: " + str(plaintext))
if __name__ == "__main__":
if (len(sys.argv) > 1):
main(sys.argv[1])
else:
main(input("Please specify an input file: "))
但是,此程序的输出是无法理解的垃圾。
~$ python3 PGPDecryptor.py PGPDecryptorTest1.txt.gpg
Output: b'\x11\xd6\xf4\x8d\xf7/o.\x13k#D\xd1!\xce\xf5\xf9\xd9\x0b,\xdb\xe4\xd6,\xb8\x80\xcb2N\xd1^\x96\x8chP\xfb\xb0?Z\xb2\xed?\xce==\xfb9\xcf5o{\xb6\x12\xf3\xf7\xc9QC\xc3\xb5\xe4\x95ab?\x17\x9d\xd3\xd3\xc6\xa8j#K\x8cMf\xc6\x00V\x89Y\xe2\xe7~\xc4B\xd5\x1b\x8f\xe9&t'
我已经通过其他方法验证了密钥,所以我相信这是正确的。我必须非常接近适当的解决方案,因为更改IV或键甚至会导致以下错误出现:
ValueError: Failed integrity check for OPENPGP IV
这表明我得到了键并且IV正确。我尝试了一个嵌套的循环来尝试使用密文的开始和终端索引的每种有效组合,以防万一某个地方还有一些额外的垃圾/标头数据,但每种组合都同样无用的输出。
如果有人能告诉我我在做错什么/如何纠正它,我会非常感激。我怀疑错误非常简单,但是问题的性质使得很难进行故障排除。
我目前有一个Janky替代解决方案,涉及修改PGPY库,但是我的问题是导入大型文件处理(〜500MB)需要很长时间(〜20-30分钟)。我也看着gnupg,但它只是一个包装纸 - 它可以用密码酶解密,但不能用原键进行解密。
I'm trying to use Python to decrypt a GPG-encrypted file using the raw key. Not the passphrase, not a nicely formatted file from a keyring, just the literal raw bytes of the key that the file was encrypted with.
I first created a test file:
~$ echo "It would be really cool if this worked" >> PGPDecryptorTest1.txt
I then encrypted the file using AES256 with the passphrase "a" and SHA256 key derivation:
~$ gpg --symmetric --s2k-mode 0 --s2k-digest-algo SHA256 --cipher-algo AES256 PGPDecryptorTest1.txt
I wrote the following short script to decode the file:
import sys
from Crypto.Cipher import AES
# With s2k-mode 0 specified, key is just SHA256 hash of passphrase
hash_a = b"\xca\x97\x81\x12\xca\x1b\xbd\xca\xfa\xc2\x31\xb3\x9a\x23\xdc\x4d\xa7\x86\xef\xf8\x14\x7c\x4e\x72\xb9\x80\x77\x85\xaf\xee\x48\xbb"
key = hash_a
def main(filename):
with open(filename, "rb") as f:
# First 9 bytes are header, ignore them and read the rest
contents = f.read()[9:]
# IV is size (block size + 2)
# AES uses 16-byte (128-bit) blocks
# Last two bytes are for checksum
iv = contents[0:16 + 2]
# Rest of contents should be ciphertext
ciphertext = contents[16 + 2:]
# Use openPGP special cipher mode
cipher = AES.new(key, AES.MODE_OPENPGP, iv=iv)
plaintext = cipher.decrypt(ciphertext)
print("Output: " + str(plaintext))
if __name__ == "__main__":
if (len(sys.argv) > 1):
main(sys.argv[1])
else:
main(input("Please specify an input file: "))
However, the output for this program is unintelligible garbage.
~$ python3 PGPDecryptor.py PGPDecryptorTest1.txt.gpg
Output: b'\x11\xd6\xf4\x8d\xf7/o.\x13k#D\xd1!\xce\xf5\xf9\xd9\x0b,\xdb\xe4\xd6,\xb8\x80\xcb2N\xd1^\x96\x8chP\xfb\xb0?Z\xb2\xed?\xce==\xfb9\xcf5o{\xb6\x12\xf3\xf7\xc9QC\xc3\xb5\xe4\x95ab?\x17\x9d\xd3\xd3\xc6\xa8j#K\x8cMf\xc6\x00V\x89Y\xe2\xe7~\xc4B\xd5\x1b\x8f\xe9&t'
I have verified the key by other methods, so I'm confident that it's correct. I must be very close to a proper solution, because changing either the IV or the key even slightly causes the following error to appear:
ValueError: Failed integrity check for OPENPGP IV
This suggests that I'm getting the key and IV correct. I've tried a nested for loop to try every valid combination of start and end indices for the ciphertext, just in case there was some additional garbage/header data somewhere, but with equally useless output for every combination.
If anyone can tell me what I'm doing wrong/how to correct it, I'd be very grateful. I suspect the error is very simple, but the nature of the problem makes it difficult to troubleshoot.
I currently have a janky alternative solution that involves modifying the pgpy library, but my problem with this is that importing large files to process (~500MB) takes a long time (~20-30 minutes). I looked at gnupg as well, but it's just a wrapper--it can decrypt with passphrases, but not with raw keys.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
使用
aes.mode_openpgp
可能适用于对称加密的数据包(TAG 9),因为它只是包含加密的数据(参考)。但是,这不是您使用
gpg
调用所产生的。为了了解我们实际处理的内容,您可以使用- list-packets
命令:两件事要注意:
警告:下面的代码只是戳戳的粗略演示
OpenPGP消息格式。这是脆弱的,不应该重复使用。主要要点是,可靠地解析OpenPGP消息并不小,您应该使用经过良好测试的库。
我使用的主要参考文献是:
更容易地证明挖掘此信息,我发出了一个加密消息,并关闭了压缩:
这是解决方案实现:
Using
AES.MODE_OPENPGP
would probably work for a Symmetrically Encrypted Data packet (tag 9), as it simply contains the encrypted data (reference).However, that's not what you've produced with your
gpg
invocation. To get some insight into what we're actually dealing with, you can use the--list-packets
command:Two things of note:
WARNING: The code below is just a rough demonstration of poking around
OpenPGP message format. It is brittle and shouldn't be reused. The main takeaway is that reliably parsing OpenPGP messages isn't trivial and you should use a well tested library.
The main references I used are:
To more easily demonstrate digging into this, I've produced an encrypted message with compression turned off:
Here's the solution implementation: