SecurityInnovation / PGPy

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

PGPy does not calculate private key checksums correctly #172

Closed meskio closed 7 years ago

meskio commented 7 years ago

Using keys generated by PGPy I can encrypt using gpg without problems, but I'm unable to decrypt messages with gpg. I'm getting an error:

gpg: public key decryption failed: checksum error
gpg: decryption failed: secret key not available

To test it I'm using the following script: https://gist.github.com/meskio/a9ccb19fa629e7bcf991cdea2018db26 It produces the same error with gpg 2.1 or gpg 1.4.

Am I doing something wrong? Or there is there an issue on the key generation/export of PGPy?

Commod0re commented 7 years ago

What version of Python are you using?

meskio commented 7 years ago

python 2.7, I'll try out with python3

dkg commented 7 years ago

This looks like #168 all over again.

can you try gpg --import with --batch?

dkg commented 7 years ago

sorry, i take it back -- you're already using --batch and the only thing that supplying it does is to move the checksum failure to later (during the first use of the key, instead of the import).

dkg commented 7 years ago

fwiw, i'm seeing the same issue with python3

meskio commented 7 years ago

I updated the gist, now it works in python 3.5 as well as python 2.7 and gives the same error.

Commod0re commented 7 years ago

I ran your original script with Python 2 and gpg fails to decrypt in either case:

gpg: public key decryption failed: Checksum error
gpg: decryption failed: No secret key
===> gpg->gpg:
gpg: public key decryption failed: Checksum error
gpg: decryption failed: No secret key
===> pgpy->gpg:

but PGPy decrypts both fine:

===> gpg->pgpy: gpg encrypted
===> pgpy->pgpy: pgpy encrypted

so I think there's a gpg invocation trick that's missing here, even though it's not identical to #168

dkg commented 7 years ago

I think it's possible that pgpy isn't testing the checksum correctly on import if self.s2k.usage == 0 (see decrypt_keyblob() in pgpy/packet/fields.py )

Commod0re commented 7 years ago

confirmed, PGPy 0.4.1 is not computing that checksum correctly:

In [1]: from pgpy import PGPKey

In [2]: key, _ = PGPKey.from_file('tests/testdata/keys/rsa.1.sec.asc')

In [3]: key._key.keymaterial.chksum
Out[3]: bytearray(b'5\xd9')

In [4]: key._key.keymaterial._compute_chksum()

In [5]: key._key.keymaterial.chksum
Out[5]: bytearray(b'\xb7\x10')

The bad news is this means #168 is actually valid (oops) The good news is the fix is simple, I expect to have it and a new unit test in git tonight.

Once I track down #171, this will go out as v0.4.2

meskio commented 7 years ago

I can confirm that this fix solves my issue and now my tests work fine.

Thank you.

Commod0re commented 7 years ago

Glad to hear it! Thank you for the bug report, by the way - I'm glad to have this fixed!