Michael Altfield's gravatar

Eavesdropping Analysis of PGP Metadata

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

  1. The Key ID of the message’s recipient(s)
  2. The encryption algorithm used
  3. 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..

1 comment to Eavesdropping Analysis of PGP Metadata

  • […] 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. […]

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>