SecurityInnovation / PGPy

Pretty Good Privacy for Python
BSD 3-Clause "New" or "Revised" License
314 stars 98 forks source link

Test loading separated subkeys #77

Open Commod0re opened 10 years ago

Commod0re commented 10 years ago

It should be possible to load subkeys that have been separated from their primary key, so we should split a subkey from its primary using gpgsplit and then test loading them.

altsalt commented 3 years ago

This does not appear to be working in 0.5.4 and while exploring issues to see whether I've missed something this one popped up. Unsure whether I'll be bumping all related issues, but as this one is extremely relevant, I figured it was worth a message. Below is a MWE that demonstrates the error. Happy to share the keys I'm testing with if that would help. This is an ECC Curve25519 key generated with GnuPG 2.2.27 then split into three separate subkeys for each function.

>>> import  os
>>> import  sys
>>> import  pgpy
>>> privkey_passphrase = "example subkey passphrase"
>>> privkey, _ = pgpy.PGPKey.from_file('./rootless_subkey.asc')
>>> privkey.is_protected
True
>>> privkey.is_unlocked
False
>>> with privkey.unlock(privkey_passphrase):
...   privkey.is_unlocked
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.9/contextlib.py", line 117, in __enter__
    return next(self.gen)
  File "/home/salt/.local/lib/python3.9/site-packages/pgpy/pgp.py", line 1795, in unlock
    sk._key.unprotect(passphrase)
  File "/home/salt/.local/lib/python3.9/site-packages/pgpy/packet/packets.py", line 940, in unprotect
    self.keymaterial.decrypt_keyblob(passphrase)
  File "/home/salt/.local/lib/python3.9/site-packages/pgpy/packet/fields.py", line 1557, in decrypt_keyblob
    kb = super(EdDSAPriv, self).decrypt_keyblob(passphrase)
  File "/home/salt/.local/lib/python3.9/site-packages/pgpy/packet/fields.py", line 1252, in decrypt_keyblob
    sessionkey = self.s2k.derive_key(passphrase)
  File "/home/salt/.local/lib/python3.9/site-packages/pgpy/packet/fields.py", line 1019, in derive_key
    keylen = self.encalg.key_size
  File "/home/salt/.local/lib/python3.9/site-packages/pgpy/constants.py", line 236, in key_size
    raise NotImplementedError(repr(self))
NotImplementedError: <SymmetricKeyAlgorithm.Plaintext: 0>
altsalt commented 3 years ago

Ah, figured this particular issue out. Since there was no longer a root key, there was nothing to unlock at that level. Instead, I have to loop through the subkeys, unlocking each. MWE:

import os
import sys
import pgpy
subkey_passphrase = "example subkey passphrase"
privkey, _ = pgpy.PGPKey.from_file('./rootless_subkey.asc')
privkey.is_protected
privkey.is_unlocked
for subkey, value in privkey._children.items():
  print('subkey id', subkey)
  value.is_protected
  value.is_unlocked
  with value.unlock(subkey_passphrase):
    value.is_protected
    value.is_unlocked