mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
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
This commit is contained in:
parent
b135372176
commit
93a96e3c0c
@ -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()
|
||||
{
|
||||
|
@ -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 );
|
||||
|
||||
|
56
cipher/rsa.c
56
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 );
|
||||
|
@ -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 ) {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user