This post attempts to answer the following question: If an evesdropper intercepts a message encrypted with gpg, how much information will they be able to extract from the message without a decryption key?
I will show the unencrypted metadata added to a GPG-encypted message, and I will present commands that can be used to extract this unencrypted metadata.
The format of a PGP packet is defined by RFC 4880 & RFC 1991. Each PGP packet includes a header that has unencrypted metadata describing the contents of the PGP packet. Such information includes
- The Key ID of the message’s recipient(s)
- The encryption algorithm used
- The length of the packet
In the below execution, I demonstarte the creation of a key, the encryption of a file, the deletion of the secret key, and the analysis of the encrypted file without the ability to decrypt its contents
root@Microknoppix:/tmp/test# gpg --gen-key ... root@Microknoppix:/tmp/test# gpg --list-keys /root/.gnupg/pubring.gpg ------------------------ pub 1024R/07994C5E 2013-10-18 [expires: 2014-03-17] uid Heinrich Heine (Der Dichter) sub 1024R/5D0D3E9C 2013-10-18 [expires: 2014-03-17] root@Microknoppix:/tmp/test# echo 'hello world!' > test.txt root@Microknoppix:/tmp/test# gpg --recipient 07994C5E --encrypt test.txt root@Microknoppix:/tmp/test# ls test.txt test.txt.gpg root@Microknoppix:/tmp/test# gpg --delete-secret-key 5D0D3E9C gpg (GnuPG) 1.4.12; Copyright (C) 2012 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. sec 1024R/07994C5E 2013-10-18 Heinrich Heine (Der Dichter) Delete this key from the keyring? (y/N) y This is a secret key! - really delete? (y/N) y root@Microknoppix:/tmp/test# gpg --delete-key 07994C5E gpg (GnuPG) 1.4.12; Copyright (C) 2012 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. pub 1024R/07994C5E 2013-10-18 Heinrich Heine (Der Dichter) Delete this key from the keyring? (y/N) y root@Microknoppix:/tmp/test#
Now that all the files are created and the secret key has been deleted, let’s try to analyze the pgp file to see what unencrypted data we can pull out.
root@Microknoppix:/tmp/test# gpg --list-packets test.txt.gpg :pubkey enc packet: version 3, algo 1, keyid D65FA0A95D0D3E9C data: [1023 bits] :encrypted data packet: length: 80 mdc_method: 2 gpg: encrypted with RSA key, ID 5D0D3E9C gpg: decryption failed: secret key not available
As you can see above, this message was encrypted using the key “D65FA0A95D0D3E9C” using RSA.
Let’s try another (more human readable) tool for dumping unencrypted data from PGP files: PGPdump.
root@Microknoppix:/tmp/test# pgpdump test.txt.gpg Old: Public-Key Encrypted Session Key Packet(tag 1)(140 bytes) New version(3) Key ID - 0xD65FA0A95D0D3E9C Pub alg - RSA Encrypt or Sign(pub 1) RSA m^e mod n(1023 bits) - ... -> m = sym alg(1 byte) + checksum(2 bytes) + PKCS-1 block type 02 New: Symmetrically Encrypted and MDC Packet(tag 18)(80 bytes) Ver 1 Encrypted data [sym alg is specified in pub-key encrypted session key] (plain text + MDC SHA1(20 bytes))
As you can see, pgpdump seems to have pulled the same data, but it’s expounded a bit on what RSA does. It also appears to include information about a symmetric key, which makes sense but isn’t obvious from the `gpg –list-packets` command above.
Hiding Recipient Data
Now, let’s try to hide the recipient of the message using `gpg –hidden-recipient` instead of `gpg –recipient`.
First, let’s delete the old file, create a new secret key, encrypt the file again, and delete the secret key again.
root@Microknoppix:/tmp/test# gpg --gen-key ... root@Microknoppix:/tmp/test# gpg --list-keys /root/.gnupg/pubring.gpg ------------------------ pub 1024R/37B00052 2013-10-19 [expires: 2014-02-16] uid Heinrich Heine (Der Dichter) sub 1024R/726D167A 2013-10-19 [expires: 2014-02-16] ... root@Microknoppix:/tmp/test# rm -rf test.txt.gpg
root@Microknoppix:/tmp/test# gpg –hidden-recipient 37B00052 –encrypt test.txt
root@Microknoppix:/tmp/test# ls
test.txt test.txt.gpg
root@Microknoppix:/tmp/test# gpg –delete-secret-key 37B00052
…
root@Microknoppix:/tmp/test# gpg –delete-key 37B00052
…
And below we peek at the gpg file’s packet’s headers to see if we can still see the recipeient.
root@Microknoppix:/tmp/test# gpg --list-packets test.txt.gpg :pubkey enc packet: version 3, algo 1, keyid 0000000000000000 data: [1022 bits] :encrypted data packet: length: 80 mdc_method: 2 gpg: encrypted with RSA key, ID 00000000 gpg: decryption failed: secret key not available root@Microknoppix:/tmp/test# pgpdump test.txt.gpg Old: Public-Key Encrypted Session Key Packet(tag 1)(140 bytes) New version(3) Key ID - 0x0000000000000000 Pub alg - RSA Encrypt or Sign(pub 1) RSA m^e mod n(1022 bits) - ... -> m = sym alg(1 byte) + checksum(2 bytes) + PKCS-1 block type 02 New: Symmetrically Encrypted and MDC Packet(tag 18)(80 bytes) Ver 1 Encrypted data [sym alg is specified in pub-key encrypted session key] (plain text + MDC SHA1(20 bytes))
Success! We’ve hidden the key id of the recipient!
Open question to the internet: is it possible to achieve (even better) plausable deniability with PGP? ie: can users hide the remaining unencrypted metadata? I understand that it would result in an ambigious packet, but perhaps pgp will attempt all keys in the keyring and all supported crypto algorithms until something works..
Related Posts
Hi, I’m Michael Altfield. I write articles about opsec, privacy, and devops ➡
[…] PGP tried to accomplish this, but failed. No matter how many implementations I used over the years (and some were pretty good), they were just too complicated and strange for most people to adopt. More importantly, they did not provide forward secrecy and your metadata was still unobscured. […]