Page MenuHome GnuPG

Data decrypted via a pk-esk packet should be better checked
Open, NormalPublic

Description

Consider the following:

$ ./gpgcompose --pk-esk neal --pk-esk --session-key new werner --encrypted-mdc
--literal --value foo | gpg2 -d
gpg: encrypted with 2048-bit RSA key, ID 0x1E0FE11D664D7444, created 2014-01-02

"Werner Koch <wk@gnupg.org>"

gpg: encrypted with 2048-bit RSA key, ID 0xC2B819056C652598, created 2015-04-07

"Neal H. Walfield <neal@walfield.org>"

gpg: packet(1) with unknown version 34
gpg: WARNING: encrypted message has been manipulated!

This creates a PK-ESK for me, it then creates a PK-ESK for werner with a new
session key and encrypts the data with Werner's session key. When I decrypt it
(using the first PK-ESK), I get junk, which gpg interprets as an OpenPGP message
(see above).

This could be largely avoided if we implemented OpenPGP's simple integrity check
(making sure the bytes at blocksize-2 and blocksize-1 match the bytes at
blocksize and blocksize + 1). Interestingly, we do this check when the session
key is extracted from an SK-ESK packet (from decrypt_data in decrypt-data.c):

  if (dek->symmetric
      && (p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1]) )
    {
      rc = gpg_error (GPG_ERR_BAD_KEY);
      goto leave;
    }

Why don't we do this when the session key is taken from a PK-ESK packet?

Event Timeline

Werner pointed out that the quick integrity check is not used due to an attack
by Mister and Zuccherato. However, this attack does not make use of any
information from the PK-ESK packet. It just uses the session key. As such, the
quick integrity check should not be done in the dek->symmetric case either.

I think it is possible to fix this issue so that we can use the quick integrity
check in the future. My post about this to the openpgp group is here:
http://mailarchive.ietf.org/arch/msg/openpgp/A_r93YIukOqzvrmd44F-Jl3dHbc .

My suggestion is a not-backwards compatible change. For messages that currently
exist, it is acceptable to do the quick integrity check if we can rate limit the
oracle (to recover the first two bytes from N blocks costs (N+1) * 2^15
decryption attempts). This is definitely safe, as Mister and Zuccerato point
out, in the interactive case. Do we have a way to reliably detect this?