Last night, Serge Mister and Robert Zuccherato published a paper
reporting on an attack against OpenPGP symmetric encryption.
This attack, while very significant from a cryptographic point of
view, is not generally effective in the real world. To be specific,
unless you have your OpenPGP program set up as part of an automated
system to accept encrypted messages, decrypt them, and then provide a
response to the submitter, then this does not affect you at all.
There is a very good writeup on the attack that goes into more depth
at http://www.pgp.com/library/ctocorner/openpgp.html
There will undoubtedly be further discussion of this over the next
several days, but I wanted to provide a few comments now, to try and
answer some questions that may arise:
1) This is not a bug in any particular OpenPGP implementation (GnuPG,
PGP, Hushmail, etc). Rather, this is an attack against the OpenPGP
protocol itself.
2) The attack requires an average of 32,768 probes to get two bytes of
plaintext. This is why it is completely ineffective against
human beings, who will presumably wonder why a stranger wants them
to decrypt thousands and thousands of messages that won't decrypt,
and then tell them what errors were seen.
3) It might be effective against an automated process that
incorporates OpenPGP decryption, if that process returns errors
back to the sender.
4) The OpenPGP Working Group will be discussing this issue and coming
up with an effective and permanent fix. In the meantime, I have
attached two patches to this mail. These patches disable a
portion of the OpenPGP protocol that the attack is exploiting.
This change should not be user visible. With the patch in place,
this attack will not work using a public-key encrypted message. It
will still work using a passphrase-encrypted message. These
patches will be part of the 1.2.8 and 1.4.1 releases of GnuPG.
5) The full paper is available at http://eprint.iacr.org/2005/033
It's a great piece of work.
David
-------------- next part --------------
Index: include/cipher.h
==================================================================RCS file:
/cvs/gnupg/gnupg/include/cipher.h,v
retrieving revision 1.53.2.6
diff -u -r1.53.2.6 cipher.h
--- include/cipher.h 29 Nov 2004 21:07:43 -0000 1.53.2.6
+++ include/cipher.h 8 Feb 2005 04:12:12 -0000
@@ -76,6 +76,7 @@
int keylen;
int algo_info_printed;
int use_mdc;
+ int symmetric;
byte key[32]; /* this is the largest used keylen (256 bit) */
} DEK;
Index: g10/mainproc.c
==================================================================RCS file:
/cvs/gnupg/gnupg/g10/mainproc.c,v
retrieving revision 1.112.2.27
diff -u -r1.112.2.27 mainproc.c
--- g10/mainproc.c 27 Jun 2004 18:26:49 -0000 1.112.2.27
+++ g10/mainproc.c 8 Feb 2005 04:12:13 -0000
@@ -317,6 +317,8 @@
c->dek = passphrase_to_dek( NULL, 0, algo, &enc->s2k, 0, NULL, NULL
);
if(c->dek)
{
+ c->dek->symmetric=1;
+
/* FIXME: This doesn't work perfectly if a symmetric key
comes before a public key in the message - if the user
doesn't know the passphrase, then there is a chance
Index: g10/encr-data.c
==================================================================RCS file:
/cvs/gnupg/gnupg/g10/encr-data.c,v
retrieving revision 1.29
diff -u -r1.29 encr-data.c
--- g10/encr-data.c 29 Jun 2002 13:46:33 -0000 1.29
+++ g10/encr-data.c 8 Feb 2005 04:12:14 -0000
@@ -120,7 +120,7 @@
cipher_sync( dfx.cipher_hd );
p = temp;
/* log_hexdump( "prefix", temp, nprefix+2 ); */
- if( p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1] ) {
+ if( dek->symmetric && (p[nprefix-2] != p[nprefix] ||
p[nprefix-1] != p[nprefix+1]) ) {
rc = G10ERR_BAD_KEY;
goto leave;
}
-------------- next part --------------
Index: include/cipher.h
==================================================================RCS file:
/cvs/gnupg/gnupg/include/cipher.h,v
retrieving revision 1.63
diff -u -r1.63 cipher.h
--- include/cipher.h 29 Nov 2004 21:14:18 -0000 1.63
+++ include/cipher.h 8 Feb 2005 04:10:29 -0000
@@ -75,6 +75,7 @@
int keylen;
int algo_info_printed;
int use_mdc;
+ int symmetric;
byte key[32]; /* this is the largest used keylen (256 bit) */
} DEK;
Index: g10/mainproc.c
==================================================================RCS file:
/cvs/gnupg/gnupg/g10/mainproc.c,v
retrieving revision 1.161
diff -u -r1.161 mainproc.c
--- g10/mainproc.c 21 Oct 2004 19:18:47 -0000 1.161
+++ g10/mainproc.c 8 Feb 2005 04:10:30 -0000
@@ -330,6 +330,8 @@
if(c->dek)
{
+ c->dek->symmetric=1;
+
/* FIXME: This doesn't work perfectly if a symmetric
key comes before a public key in the message - if
the user doesn't know the passphrase, then there is
Index: g10/encr-data.c
==================================================================RCS file:
/cvs/gnupg/gnupg/g10/encr-data.c,v
retrieving revision 1.30
diff -u -r1.30 encr-data.c
--- g10/encr-data.c 8 Oct 2004 21:54:26 -0000 1.30
+++ g10/encr-data.c 8 Feb 2005 04:10:30 -0000
@@ -125,7 +125,7 @@
cipher_sync( dfx.cipher_hd );
p = temp;
/* log_hexdump( "prefix", temp, nprefix+2 ); */
- if( p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1] ) {
+ if( dek->symmetric && (p[nprefix-2] != p[nprefix] ||
p[nprefix-1] != p[nprefix+1]) ) {
rc = G10ERR_BAD_KEY;
goto leave;
}