From 93a96e3c0c33370248f6570d8285c4e811d305d4 Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Tue, 22 Oct 2013 14:26:53 +0200
Subject: [PATCH 1/2] Use blinding for the RSA secret operation.

* cipher/random.c (randomize_mpi): New.
* g10/gpgv.c (randomize_mpi): New stub.
* cipher/rsa.c (USE_BLINDING): Define macro.
(secret): Implement blinding.
--

GPG 1.x has never used any protection against timing attacks on the
RSA secret operation.  The rationale for this has been that there was
no way to mount a remote timing attack on GnuPG.  With the turning up
of Acoustic Cryptanalysis (http://cs.tau.ac.il/~tromer/acoustic) this
assumption no longer holds true and thus we need to do do something
about it.  Blinding seems to be a suitable mitigation to the threat of
key extraction.  It does not help against distinguishing used keys,
though.

Note that GPG 2.x uses Libgcrypt which does blinding by default.

The performance penalty is negligible: Modifying the core pubkey_sign
or pubkey_decrypt function to run 100 times in a loop, the entire
execution times for signing or decrypting a small message using a 4K
RSA key on a Thinkpad X220 are

  Without blinding:  5.2s  (8.9s)
  With blinding:     5.6s  (9.3s)

The numbers in parentheses give the values without the recently
implemented k-ary exponentiation code.  Thus for the next release the
user will actually experience faster signing and decryption.  A
drawback of blinding is that we need random numbers even for
decryption (albeit at low quality).

Signed-off-by: Werner Koch <wk@gnupg.org>

CVE-id: CVE-2013-4576
---
 cipher/random.c | 12 ++++++++++++
 cipher/random.h |  1 +
 cipher/rsa.c    | 58 ++++++++++++++++++++++++++++++++++++++++-----------------
 g10/gpgv.c      |  1 +
 4 files changed, 55 insertions(+), 17 deletions(-)

diff --git a/cipher/random.c b/cipher/random.c
index b634161..7549517 100644
--- a/cipher/random.c
+++ b/cipher/random.c
@@ -284,6 +284,18 @@ randomize_buffer( byte *buffer, size_t length, int level )
 }
 
 
+/* Randomize the MPI by setting it to NBITS of random of quality LEVEL.  */
+void
+randomize_mpi (MPI mpi, size_t nbits, int level)
+{
+  unsigned char *buffer;
+
+  buffer = get_random_bits (nbits, level, mpi_is_secure (mpi));
+  mpi_set_buffer (mpi, buffer, (nbits+7)/8, 0);
+  xfree (buffer);
+}
+
+
 int
 random_is_faked()
 {
diff --git a/cipher/random.h b/cipher/random.h
index ca02df1..01ee11b 100644
--- a/cipher/random.h
+++ b/cipher/random.h
@@ -30,6 +30,7 @@ int  quick_random_gen( int onoff );
 int  random_is_faked(void);
 void random_disable_locking (void);
 void randomize_buffer( byte *buffer, size_t length, int level );
+void randomize_mpi (MPI mpi, size_t nbits, int level);
 byte *get_random_bits( size_t nbits, int level, int secure );
 void fast_random_poll( void );
 
diff --git a/cipher/rsa.c b/cipher/rsa.c
index 1cdc600..c52704c 100644
--- a/cipher/rsa.c
+++ b/cipher/rsa.c
@@ -1,5 +1,5 @@
 /* rsa.c  -  RSA function
- *	Copyright (C) 1997, 1998, 1999 by Werner Koch (dd9jn)
+ *	Copyright (C) 1997, 1998, 1999, 2013 by Werner Koch (dd9jn)
  *	Copyright (C) 2000, 2001 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
@@ -22,7 +22,7 @@
    which expires on September 20, 2000.  The patent holder placed that
    patent into the public domain on Sep 6th, 2000.
 */
- 
+
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -32,6 +32,10 @@
 #include "cipher.h"
 #include "rsa.h"
 
+/* Blinding is used to mitigate side-channel attacks.  You may undef
+   this to speed up the operation in case the system is secured
+   against physical and network mounted side-channel attacks.  */
+#define USE_BLINDING 1
 
 typedef struct {
     MPI n;	    /* modulus */
@@ -103,7 +107,7 @@ generate( RSA_secret_key *sk, unsigned nbits )
 
     /* make sure that nbits is even so that we generate p, q of equal size */
     if ( (nbits&1) )
-      nbits++; 
+      nbits++;
 
     n = mpi_alloc ( mpi_nlimb_hint_from_nbits (nbits) );
 
@@ -146,7 +150,7 @@ generate( RSA_secret_key *sk, unsigned nbits )
        65537 as the new best practice.  See FIPS-186-3.
      */
     e = mpi_alloc ( mpi_nlimb_hint_from_nbits (32) );
-    mpi_set_ui( e, 65537); 
+    mpi_set_ui( e, 65537);
     while( !mpi_gcd(t1, e, phi) ) /* (while gcd is not 1) */
       mpi_add_ui( e, e, 2);
 
@@ -268,7 +272,7 @@ stronger_key_check ( RSA_secret_key *skey )
     mpi_invm(t, skey->p, skey->q );
     if ( mpi_cmp(t, skey->u ) )
         log_info ( "RSA Oops: u is wrong\n");
-   
+
     log_info ( "RSA secret key check finished\n");
 
     mpi_free (t);
@@ -286,9 +290,9 @@ stronger_key_check ( RSA_secret_key *skey )
  *
  * Or faster:
  *
- *      m1 = c ^ (d mod (p-1)) mod p 
- *      m2 = c ^ (d mod (q-1)) mod q 
- *      h = u * (m2 - m1) mod q 
+ *      m1 = c ^ (d mod (p-1)) mod p
+ *      m2 = c ^ (d mod (q-1)) mod q
+ *      h = u * (m2 - m1) mod q
  *      m = m1 + h * p
  *
  * Where m is OUTPUT, c is INPUT and d,n,p,q,u are elements of SKEY.
@@ -299,13 +303,26 @@ secret(MPI output, MPI input, RSA_secret_key *skey )
 #if 0
     mpi_powm( output, input, skey->d, skey->n );
 #else
-    MPI m1   = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 );
-    MPI m2   = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 );
-    MPI h    = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 );
-
+    int nlimbs = mpi_get_nlimbs (skey->n)+1;
+    MPI m1   = mpi_alloc_secure (nlimbs);
+    MPI m2   = mpi_alloc_secure (nlimbs);
+    MPI h    = mpi_alloc_secure (nlimbs);
+# ifdef USE_BLINDING
+    MPI r    = mpi_alloc_secure (nlimbs);
+    MPI bdata= mpi_alloc_secure (nlimbs);
+
+    /* Blind:  bdata = (data * r^e) mod n   */
+    randomize_mpi (r, mpi_get_nbits (skey->n), 0);
+    mpi_fdiv_r (r, r, skey->n);
+    mpi_powm (bdata, r, skey->e, skey->n);
+    mpi_mulm (bdata, bdata, input, skey->n);
+    input = bdata;
+# endif /* USE_BLINDING */
+
+    /* RSA secret operation:  */
     /* m1 = c ^ (d mod (p-1)) mod p */
     mpi_sub_ui( h, skey->p, 1  );
-    mpi_fdiv_r( h, skey->d, h );   
+    mpi_fdiv_r( h, skey->d, h );
     mpi_powm( m1, input, h, skey->p );
     /* m2 = c ^ (d mod (q-1)) mod q */
     mpi_sub_ui( h, skey->q, 1  );
@@ -313,14 +330,21 @@ secret(MPI output, MPI input, RSA_secret_key *skey )
     mpi_powm( m2, input, h, skey->q );
     /* h = u * ( m2 - m1 ) mod q */
     mpi_sub( h, m2, m1 );
-    if ( mpi_is_neg( h ) ) 
+    if ( mpi_is_neg( h ) )
         mpi_add ( h, h, skey->q );
-    mpi_mulm( h, skey->u, h, skey->q ); 
+    mpi_mulm( h, skey->u, h, skey->q );
     /* m = m2 + h * p */
     mpi_mul ( h, h, skey->p );
     mpi_add ( output, m1, h );
-    /* ready */
-    
+
+# ifdef USE_BLINDING
+    /* Unblind: output = (output * r^(-1)) mod n  */
+    mpi_free (bdata);
+    mpi_invm (r, r, skey->n);
+    mpi_mulm (output, output, r, skey->n);
+    mpi_free (r);
+# endif /* USE_BLINDING */
+
     mpi_free ( h );
     mpi_free ( m1 );
     mpi_free ( m2 );
diff --git a/g10/gpgv.c b/g10/gpgv.c
index a337fc7..b679853 100644
--- a/g10/gpgv.c
+++ b/g10/gpgv.c
@@ -389,6 +389,7 @@ void cipher_sync( CIPHER_HANDLE c ) {}
 void random_dump_stats(void) {}
 int quick_random_gen( int onoff ) { return -1;}
 void randomize_buffer( byte *buffer, size_t length, int level ) {}
+void randomize_mpi (MPI mpi, size_t nbits, int level) {}
 int random_is_faked() { return -1;}
 byte *get_random_bits( size_t nbits, int level, int secure ) { return NULL;}
 void set_random_seed_file( const char *name ) {}
-- 
1.8.4.3

From d0d72d98f34579213230b3febfebd2fd8dff272b Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Wed, 27 Nov 2013 14:22:10 +0100
Subject: [PATCH 2/2] Normalize the MPIs used as input to secret key functions.

* cipher/rsa.c (secret): Normalize the INPUT.
(rsa_decrypt): Pass reduced data to secret.
* cipher/elgamal.c (decrypt): Normalize A and B.
* cipher/dsa.c (sign): Normalize HASH.
--

mpi_normalize is in general not required because extra leading zeroes
do not harm the computation.  However, adding extra all zero limbs or
padding with multiples of N may be useful in side-channel attacks. In
particular they are used by the acoustic crypt-analysis.  This is an
extra pre-caution which alone would not be sufficient to mitigate the
described attack.

CVE-id: CVE-2013-4576

Signed-off-by: Werner Koch <wk@gnupg.org>
---
 cipher/dsa.c     |  6 ++++--
 cipher/elgamal.c |  3 +++
 cipher/rsa.c     | 22 ++++++++++++++++++----
 3 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/cipher/dsa.c b/cipher/dsa.c
index 69b7d1b..e23f05c 100644
--- a/cipher/dsa.c
+++ b/cipher/dsa.c
@@ -274,7 +274,7 @@ check_secret_key( DSA_secret_key *sk )
 /****************
  * Make a DSA signature from HASH and put it into r and s.
  *
- * Without generating the k this function runs in 
+ * Without generating the k this function runs in
  * about 26ms on a 300 Mhz Mobile Pentium
  */
 
@@ -285,6 +285,8 @@ sign(MPI r, MPI s, MPI hash, DSA_secret_key *skey )
     MPI kinv;
     MPI tmp;
 
+    mpi_normalize (hash);
+
     /* select a random k with 0 < k < q */
     k = gen_k( skey->q );
 
@@ -311,7 +313,7 @@ sign(MPI r, MPI s, MPI hash, DSA_secret_key *skey )
 /****************
  * Returns true if the signature composed from R and S is valid.
  *
- * Without the checks this function runs in 
+ * Without the checks this function runs in
  * about 31ms on a 300 Mhz Mobile Pentium
  */
 static int
diff --git a/cipher/elgamal.c b/cipher/elgamal.c
index c3f0862..5143ecc 100644
--- a/cipher/elgamal.c
+++ b/cipher/elgamal.c
@@ -374,6 +374,9 @@ decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey )
 {
     MPI t1 = mpi_alloc_secure( mpi_get_nlimbs( skey->p ) );
 
+    mpi_normalize (a);
+    mpi_normalize (b);
+
     /* output = b/(a^x) mod p */
     mpi_powm( t1, a, skey->x, skey->p );
     mpi_invm( t1, t1, skey->p );
diff --git a/cipher/rsa.c b/cipher/rsa.c
index c52704c..c4d5161 100644
--- a/cipher/rsa.c
+++ b/cipher/rsa.c
@@ -308,9 +308,14 @@ secret(MPI output, MPI input, RSA_secret_key *skey )
     MPI m2   = mpi_alloc_secure (nlimbs);
     MPI h    = mpi_alloc_secure (nlimbs);
 # ifdef USE_BLINDING
-    MPI r    = mpi_alloc_secure (nlimbs);
     MPI bdata= mpi_alloc_secure (nlimbs);
+    MPI r    = mpi_alloc_secure (nlimbs);
+# endif /* USE_BLINDING */
+
+    /* Remove superfluous leading zeroes from INPUT.  */
+    mpi_normalize (input);
 
+# ifdef USE_BLINDING
     /* Blind:  bdata = (data * r^e) mod n   */
     randomize_mpi (r, mpi_get_nbits (skey->n), 0);
     mpi_fdiv_r (r, r, skey->n);
@@ -338,8 +343,8 @@ secret(MPI output, MPI input, RSA_secret_key *skey )
     mpi_add ( output, m1, h );
 
 # ifdef USE_BLINDING
-    /* Unblind: output = (output * r^(-1)) mod n  */
     mpi_free (bdata);
+    /* Unblind: output = (output * r^(-1)) mod n  */
     mpi_invm (r, r, skey->n);
     mpi_mulm (output, output, r, skey->n);
     mpi_free (r);
@@ -419,6 +424,7 @@ int
 rsa_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
 {
     RSA_secret_key sk;
+    MPI input;
 
     if( algo != 1 && algo != 2 )
 	return G10ERR_PUBKEY_ALGO;
@@ -429,8 +435,16 @@ rsa_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
     sk.p = skey[3];
     sk.q = skey[4];
     sk.u = skey[5];
-    *result = mpi_alloc_secure( mpi_get_nlimbs( sk.n ) );
-    secret( *result, data[0], &sk );
+
+    /* Better make sure that there are no superfluous leading zeroes
+       in the input and it has not been padded using multiples of N.
+       This mitigates side-channel attacks (CVE-2013-4576).  */
+    input = mpi_alloc (0);
+    mpi_normalize (data[0]);
+    mpi_fdiv_r (input, data[0], sk.n);
+    *result = mpi_alloc_secure (mpi_get_nlimbs (sk.n));
+    secret (*result, input, &sk);
+    mpi_free (input);
     return 0;
 }
 
-- 
1.8.4.3

