mbedtls/library/bignum.c
Manuel Pégourié-Gonnard 9b75305d6a Fix potential buffer overflow in mpi_read_string()
Found by Guido Vranken.

Two possible integer overflows (during << 2 or addition in BITS_TO_LIMB())
could result in far too few memory to be allocated, then overflowing the
buffer in the subsequent for loop.

Both integer overflows happen when slen is close to or greater than
SIZE_T_MAX >> 2 (ie 2^30 on a 32 bit system).

Note: one could also avoid those overflows by changing BITS_TO_LIMB(s << 2) to
CHARS_TO_LIMB(s >> 1) but the solution implemented looks more robust with
respect to future code changes.
2015-10-01 16:59:55 +02:00

2181 lines
45 KiB
C

/*
* Multi-precision integer library
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
*
* This file is part of mbed TLS (https://polarssl.org)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* This MPI implementation is based on:
*
* http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
* http://www.stillhq.com/extracted/gnupg-api/mpi/
* http://math.libtomcrypt.com/files/tommath.pdf
*/
#include "polarssl/config.h"
#if defined(POLARSSL_BIGNUM_C)
#include "polarssl/bignum.h"
#include "polarssl/bn_mul.h"
#include <limits.h>
#include <stdlib.h>
/* Implementation that should never be optimized out by the compiler */
static void polarssl_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
#define ciL (sizeof(t_uint)) /* chars in limb */
#define biL (ciL << 3) /* bits in limb */
#define biH (ciL << 2) /* half limb size */
/*
* Convert between bits/chars and number of limbs
* Divide first in order to avoid potential overflows
*/
#define BITS_TO_LIMBS(i) ( (i) / biL + ( (i) % biL != 0 ) )
#define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) )
/*
* Initialize one MPI
*/
void mpi_init( mpi *X )
{
if( X == NULL )
return;
X->s = 1;
X->n = 0;
X->p = NULL;
}
/*
* Unallocate one MPI
*/
void mpi_free( mpi *X )
{
if( X == NULL )
return;
if( X->p != NULL )
{
polarssl_zeroize( X->p, X->n * ciL );
free( X->p );
}
X->s = 1;
X->n = 0;
X->p = NULL;
}
/*
* Enlarge to the specified number of limbs
*/
int mpi_grow( mpi *X, size_t nblimbs )
{
t_uint *p;
if( nblimbs > POLARSSL_MPI_MAX_LIMBS )
return( POLARSSL_ERR_MPI_MALLOC_FAILED );
if( X->n < nblimbs )
{
if( ( p = (t_uint *) malloc( nblimbs * ciL ) ) == NULL )
return( POLARSSL_ERR_MPI_MALLOC_FAILED );
memset( p, 0, nblimbs * ciL );
if( X->p != NULL )
{
memcpy( p, X->p, X->n * ciL );
polarssl_zeroize( X->p, X->n * ciL );
free( X->p );
}
X->n = nblimbs;
X->p = p;
}
return( 0 );
}
/*
* Copy the contents of Y into X
*/
int mpi_copy( mpi *X, const mpi *Y )
{
int ret;
size_t i;
if( X == Y )
return( 0 );
for( i = Y->n - 1; i > 0; i-- )
if( Y->p[i] != 0 )
break;
i++;
X->s = Y->s;
MPI_CHK( mpi_grow( X, i ) );
memset( X->p, 0, X->n * ciL );
memcpy( X->p, Y->p, i * ciL );
cleanup:
return( ret );
}
/*
* Swap the contents of X and Y
*/
void mpi_swap( mpi *X, mpi *Y )
{
mpi T;
memcpy( &T, X, sizeof( mpi ) );
memcpy( X, Y, sizeof( mpi ) );
memcpy( Y, &T, sizeof( mpi ) );
}
/*
* Set value from integer
*/
int mpi_lset( mpi *X, t_sint z )
{
int ret;
MPI_CHK( mpi_grow( X, 1 ) );
memset( X->p, 0, X->n * ciL );
X->p[0] = ( z < 0 ) ? -z : z;
X->s = ( z < 0 ) ? -1 : 1;
cleanup:
return( ret );
}
/*
* Get a specific bit
*/
int mpi_get_bit( const mpi *X, size_t pos )
{
if( X->n * biL <= pos )
return( 0 );
return ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01;
}
/*
* Set a bit to a specific value of 0 or 1
*/
int mpi_set_bit( mpi *X, size_t pos, unsigned char val )
{
int ret = 0;
size_t off = pos / biL;
size_t idx = pos % biL;
if( val != 0 && val != 1 )
return POLARSSL_ERR_MPI_BAD_INPUT_DATA;
if( X->n * biL <= pos )
{
if( val == 0 )
return ( 0 );
MPI_CHK( mpi_grow( X, off + 1 ) );
}
X->p[off] = ( X->p[off] & ~( 0x01 << idx ) ) | ( val << idx );
cleanup:
return( ret );
}
/*
* Return the number of least significant bits
*/
size_t mpi_lsb( const mpi *X )
{
size_t i, j, count = 0;
for( i = 0; i < X->n; i++ )
for( j = 0; j < biL; j++, count++ )
if( ( ( X->p[i] >> j ) & 1 ) != 0 )
return( count );
return( 0 );
}
/*
* Return the number of most significant bits
*/
size_t mpi_msb( const mpi *X )
{
size_t i, j;
for( i = X->n - 1; i > 0; i-- )
if( X->p[i] != 0 )
break;
for( j = biL; j > 0; j-- )
if( ( ( X->p[i] >> ( j - 1 ) ) & 1 ) != 0 )
break;
return( ( i * biL ) + j );
}
/*
* Return the total size in bytes
*/
size_t mpi_size( const mpi *X )
{
return( ( mpi_msb( X ) + 7 ) >> 3 );
}
/*
* Convert an ASCII character to digit value
*/
static int mpi_get_digit( t_uint *d, int radix, char c )
{
*d = 255;
if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30;
if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37;
if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57;
if( *d >= (t_uint) radix )
return( POLARSSL_ERR_MPI_INVALID_CHARACTER );
return( 0 );
}
/*
* Import from an ASCII string
*/
int mpi_read_string( mpi *X, int radix, const char *s )
{
int ret;
size_t i, j, slen, n;
t_uint d;
mpi T;
if( radix < 2 || radix > 16 )
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
mpi_init( &T );
slen = strlen( s );
if( radix == 16 )
{
if( slen > SIZE_T_MAX >> 2 )
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
n = BITS_TO_LIMBS( slen << 2 );
MPI_CHK( mpi_grow( X, n ) );
MPI_CHK( mpi_lset( X, 0 ) );
for( i = slen, j = 0; i > 0; i--, j++ )
{
if( i == 1 && s[i - 1] == '-' )
{
X->s = -1;
break;
}
MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) );
X->p[j / (2 * ciL)] |= d << ( (j % (2 * ciL)) << 2 );
}
}
else
{
MPI_CHK( mpi_lset( X, 0 ) );
for( i = 0; i < slen; i++ )
{
if( i == 0 && s[i] == '-' )
{
X->s = -1;
continue;
}
MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
MPI_CHK( mpi_mul_int( &T, X, radix ) );
if( X->s == 1 )
{
MPI_CHK( mpi_add_int( X, &T, d ) );
}
else
{
MPI_CHK( mpi_sub_int( X, &T, d ) );
}
}
}
cleanup:
mpi_free( &T );
return( ret );
}
/*
* Helper to write the digits high-order first
*/
static int mpi_write_hlp( mpi *X, int radix, char **p )
{
int ret;
t_uint r;
if( radix < 2 || radix > 16 )
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
MPI_CHK( mpi_mod_int( &r, X, radix ) );
MPI_CHK( mpi_div_int( X, NULL, X, radix ) );
if( mpi_cmp_int( X, 0 ) != 0 )
MPI_CHK( mpi_write_hlp( X, radix, p ) );
if( r < 10 )
*(*p)++ = (char)( r + 0x30 );
else
*(*p)++ = (char)( r + 0x37 );
cleanup:
return( ret );
}
/*
* Export into an ASCII string
*/
int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen )
{
int ret = 0;
size_t n;
char *p;
mpi T;
if( radix < 2 || radix > 16 )
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
n = mpi_msb( X );
if( radix >= 4 ) n >>= 1;
if( radix >= 16 ) n >>= 1;
n += 3;
if( *slen < n )
{
*slen = n;
return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL );
}
p = s;
mpi_init( &T );
if( X->s == -1 )
*p++ = '-';
if( radix == 16 )
{
int c;
size_t i, j, k;
for( i = X->n, k = 0; i > 0; i-- )
{
for( j = ciL; j > 0; j-- )
{
c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF;
if( c == 0 && k == 0 && ( i + j + 3 ) != 0 )
continue;
*(p++) = "0123456789ABCDEF" [c / 16];
*(p++) = "0123456789ABCDEF" [c % 16];
k = 1;
}
}
}
else
{
MPI_CHK( mpi_copy( &T, X ) );
if( T.s == -1 )
T.s = 1;
MPI_CHK( mpi_write_hlp( &T, radix, &p ) );
}
*p++ = '\0';
*slen = p - s;
cleanup:
mpi_free( &T );
return( ret );
}
#if defined(POLARSSL_FS_IO)
/*
* Read X from an opened file
*/
int mpi_read_file( mpi *X, int radix, FILE *fin )
{
t_uint d;
size_t slen;
char *p;
/*
* Buffer should have space for (short) label and decimal formatted MPI,
* newline characters and '\0'
*/
char s[ POLARSSL_MPI_RW_BUFFER_SIZE ];
memset( s, 0, sizeof( s ) );
if( fgets( s, sizeof( s ) - 1, fin ) == NULL )
return( POLARSSL_ERR_MPI_FILE_IO_ERROR );
slen = strlen( s );
if( slen == sizeof( s ) - 2 )
return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL );
if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; }
if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; }
p = s + slen;
while( --p >= s )
if( mpi_get_digit( &d, radix, *p ) != 0 )
break;
return( mpi_read_string( X, radix, p + 1 ) );
}
/*
* Write X into an opened file (or stdout if fout == NULL)
*/
int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout )
{
int ret;
size_t n, slen, plen;
/*
* Buffer should have space for (short) label and decimal formatted MPI,
* newline characters and '\0'
*/
char s[ POLARSSL_MPI_RW_BUFFER_SIZE ];
n = sizeof( s );
memset( s, 0, n );
n -= 2;
MPI_CHK( mpi_write_string( X, radix, s, (size_t *) &n ) );
if( p == NULL ) p = "";
plen = strlen( p );
slen = strlen( s );
s[slen++] = '\r';
s[slen++] = '\n';
if( fout != NULL )
{
if( fwrite( p, 1, plen, fout ) != plen ||
fwrite( s, 1, slen, fout ) != slen )
return( POLARSSL_ERR_MPI_FILE_IO_ERROR );
}
else
printf( "%s%s", p, s );
cleanup:
return( ret );
}
#endif /* POLARSSL_FS_IO */
/*
* Import X from unsigned binary data, big endian
*/
int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen )
{
int ret;
size_t i, j, n;
for( n = 0; n < buflen; n++ )
if( buf[n] != 0 )
break;
MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) );
MPI_CHK( mpi_lset( X, 0 ) );
for( i = buflen, j = 0; i > n; i--, j++ )
X->p[j / ciL] |= ((t_uint) buf[i - 1]) << ((j % ciL) << 3);
cleanup:
return( ret );
}
/*
* Export X into unsigned binary data, big endian
*/
int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen )
{
size_t i, j, n;
n = mpi_size( X );
if( buflen < n )
return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL );
memset( buf, 0, buflen );
for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- )
buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) );
return( 0 );
}
/*
* Left-shift: X <<= count
*/
int mpi_shift_l( mpi *X, size_t count )
{
int ret;
size_t i, v0, t1;
t_uint r0 = 0, r1;
v0 = count / (biL );
t1 = count & (biL - 1);
i = mpi_msb( X ) + count;
if( X->n * biL < i )
MPI_CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) );
ret = 0;
/*
* shift by count / limb_size
*/
if( v0 > 0 )
{
for( i = X->n; i > v0; i-- )
X->p[i - 1] = X->p[i - v0 - 1];
for( ; i > 0; i-- )
X->p[i - 1] = 0;
}
/*
* shift by count % limb_size
*/
if( t1 > 0 )
{
for( i = v0; i < X->n; i++ )
{
r1 = X->p[i] >> (biL - t1);
X->p[i] <<= t1;
X->p[i] |= r0;
r0 = r1;
}
}
cleanup:
return( ret );
}
/*
* Right-shift: X >>= count
*/
int mpi_shift_r( mpi *X, size_t count )
{
size_t i, v0, v1;
t_uint r0 = 0, r1;
v0 = count / biL;
v1 = count & (biL - 1);
if( v0 > X->n || ( v0 == X->n && v1 > 0 ) )
return mpi_lset( X, 0 );
/*
* shift by count / limb_size
*/
if( v0 > 0 )
{
for( i = 0; i < X->n - v0; i++ )
X->p[i] = X->p[i + v0];
for( ; i < X->n; i++ )
X->p[i] = 0;
}
/*
* shift by count % limb_size
*/
if( v1 > 0 )
{
for( i = X->n; i > 0; i-- )
{
r1 = X->p[i - 1] << (biL - v1);
X->p[i - 1] >>= v1;
X->p[i - 1] |= r0;
r0 = r1;
}
}
return( 0 );
}
/*
* Compare unsigned values
*/
int mpi_cmp_abs( const mpi *X, const mpi *Y )
{
size_t i, j;
for( i = X->n; i > 0; i-- )
if( X->p[i - 1] != 0 )
break;
for( j = Y->n; j > 0; j-- )
if( Y->p[j - 1] != 0 )
break;
if( i == 0 && j == 0 )
return( 0 );
if( i > j ) return( 1 );
if( j > i ) return( -1 );
for( ; i > 0; i-- )
{
if( X->p[i - 1] > Y->p[i - 1] ) return( 1 );
if( X->p[i - 1] < Y->p[i - 1] ) return( -1 );
}
return( 0 );
}
/*
* Compare signed values
*/
int mpi_cmp_mpi( const mpi *X, const mpi *Y )
{
size_t i, j;
for( i = X->n; i > 0; i-- )
if( X->p[i - 1] != 0 )
break;
for( j = Y->n; j > 0; j-- )
if( Y->p[j - 1] != 0 )
break;
if( i == 0 && j == 0 )
return( 0 );
if( i > j ) return( X->s );
if( j > i ) return( -Y->s );
if( X->s > 0 && Y->s < 0 ) return( 1 );
if( Y->s > 0 && X->s < 0 ) return( -1 );
for( ; i > 0; i-- )
{
if( X->p[i - 1] > Y->p[i - 1] ) return( X->s );
if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s );
}
return( 0 );
}
/*
* Compare signed values
*/
int mpi_cmp_int( const mpi *X, t_sint z )
{
mpi Y;
t_uint p[1];
*p = ( z < 0 ) ? -z : z;
Y.s = ( z < 0 ) ? -1 : 1;
Y.n = 1;
Y.p = p;
return( mpi_cmp_mpi( X, &Y ) );
}
/*
* Unsigned addition: X = |A| + |B| (HAC 14.7)
*/
int mpi_add_abs( mpi *X, const mpi *A, const mpi *B )
{
int ret;
size_t i, j;
t_uint *o, *p, c;
if( X == B )
{
const mpi *T = A; A = X; B = T;
}
if( X != A )
MPI_CHK( mpi_copy( X, A ) );
/*
* X should always be positive as a result of unsigned additions.
*/
X->s = 1;
for( j = B->n; j > 0; j-- )
if( B->p[j - 1] != 0 )
break;
MPI_CHK( mpi_grow( X, j ) );
o = B->p; p = X->p; c = 0;
for( i = 0; i < j; i++, o++, p++ )
{
*p += c; c = ( *p < c );
*p += *o; c += ( *p < *o );
}
while( c != 0 )
{
if( i >= X->n )
{
MPI_CHK( mpi_grow( X, i + 1 ) );
p = X->p + i;
}
*p += c; c = ( *p < c ); i++; p++;
}
cleanup:
return( ret );
}
/*
* Helper for mpi substraction
*/
static void mpi_sub_hlp( size_t n, t_uint *s, t_uint *d )
{
size_t i;
t_uint c, z;
for( i = c = 0; i < n; i++, s++, d++ )
{
z = ( *d < c ); *d -= c;
c = ( *d < *s ) + z; *d -= *s;
}
while( c != 0 )
{
z = ( *d < c ); *d -= c;
c = z; i++; d++;
}
}
/*
* Unsigned substraction: X = |A| - |B| (HAC 14.9)
*/
int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B )
{
mpi TB;
int ret;
size_t n;
if( mpi_cmp_abs( A, B ) < 0 )
return( POLARSSL_ERR_MPI_NEGATIVE_VALUE );
mpi_init( &TB );
if( X == B )
{
MPI_CHK( mpi_copy( &TB, B ) );
B = &TB;
}
if( X != A )
MPI_CHK( mpi_copy( X, A ) );
/*
* X should always be positive as a result of unsigned substractions.
*/
X->s = 1;
ret = 0;
for( n = B->n; n > 0; n-- )
if( B->p[n - 1] != 0 )
break;
mpi_sub_hlp( n, B->p, X->p );
cleanup:
mpi_free( &TB );
return( ret );
}
/*
* Signed addition: X = A + B
*/
int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B )
{
int ret, s = A->s;
if( A->s * B->s < 0 )
{
if( mpi_cmp_abs( A, B ) >= 0 )
{
MPI_CHK( mpi_sub_abs( X, A, B ) );
X->s = s;
}
else
{
MPI_CHK( mpi_sub_abs( X, B, A ) );
X->s = -s;
}
}
else
{
MPI_CHK( mpi_add_abs( X, A, B ) );
X->s = s;
}
cleanup:
return( ret );
}
/*
* Signed substraction: X = A - B
*/
int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B )
{
int ret, s = A->s;
if( A->s * B->s > 0 )
{
if( mpi_cmp_abs( A, B ) >= 0 )
{
MPI_CHK( mpi_sub_abs( X, A, B ) );
X->s = s;
}
else
{
MPI_CHK( mpi_sub_abs( X, B, A ) );
X->s = -s;
}
}
else
{
MPI_CHK( mpi_add_abs( X, A, B ) );
X->s = s;
}
cleanup:
return( ret );
}
/*
* Signed addition: X = A + b
*/
int mpi_add_int( mpi *X, const mpi *A, t_sint b )
{
mpi _B;
t_uint p[1];
p[0] = ( b < 0 ) ? -b : b;
_B.s = ( b < 0 ) ? -1 : 1;
_B.n = 1;
_B.p = p;
return( mpi_add_mpi( X, A, &_B ) );
}
/*
* Signed substraction: X = A - b
*/
int mpi_sub_int( mpi *X, const mpi *A, t_sint b )
{
mpi _B;
t_uint p[1];
p[0] = ( b < 0 ) ? -b : b;
_B.s = ( b < 0 ) ? -1 : 1;
_B.n = 1;
_B.p = p;
return( mpi_sub_mpi( X, A, &_B ) );
}
/*
* Helper for mpi multiplication
*/
static
#if defined(__APPLE__) && defined(__arm__)
/*
* Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
* appears to need this to prevent bad ARM code generation at -O3.
*/
__attribute__ ((noinline))
#endif
void mpi_mul_hlp( size_t i, t_uint *s, t_uint *d, t_uint b )
{
t_uint c = 0, t = 0;
#if defined(MULADDC_HUIT)
for( ; i >= 8; i -= 8 )
{
MULADDC_INIT
MULADDC_HUIT
MULADDC_STOP
}
for( ; i > 0; i-- )
{
MULADDC_INIT
MULADDC_CORE
MULADDC_STOP
}
#else
for( ; i >= 16; i -= 16 )
{
MULADDC_INIT
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_STOP
}
for( ; i >= 8; i -= 8 )
{
MULADDC_INIT
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_STOP
}
for( ; i > 0; i-- )
{
MULADDC_INIT
MULADDC_CORE
MULADDC_STOP
}
#endif
t++;
do {
*d += c; c = ( *d < c ); d++;
}
while( c != 0 );
}
/*
* Baseline multiplication: X = A * B (HAC 14.12)
*/
int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B )
{
int ret;
size_t i, j;
mpi TA, TB;
mpi_init( &TA ); mpi_init( &TB );
if( X == A ) { MPI_CHK( mpi_copy( &TA, A ) ); A = &TA; }
if( X == B ) { MPI_CHK( mpi_copy( &TB, B ) ); B = &TB; }
for( i = A->n; i > 0; i-- )
if( A->p[i - 1] != 0 )
break;
for( j = B->n; j > 0; j-- )
if( B->p[j - 1] != 0 )
break;
MPI_CHK( mpi_grow( X, i + j ) );
MPI_CHK( mpi_lset( X, 0 ) );
for( i++; j > 0; j-- )
mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] );
X->s = A->s * B->s;
cleanup:
mpi_free( &TB ); mpi_free( &TA );
return( ret );
}
/*
* Baseline multiplication: X = A * b
*/
int mpi_mul_int( mpi *X, const mpi *A, t_sint b )
{
mpi _B;
t_uint p[1];
_B.s = 1;
_B.n = 1;
_B.p = p;
p[0] = b;
return( mpi_mul_mpi( X, A, &_B ) );
}
/*
* Division by mpi: A = Q * B + R (HAC 14.20)
*/
int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B )
{
int ret;
size_t i, n, t, k;
mpi X, Y, Z, T1, T2;
if( mpi_cmp_int( B, 0 ) == 0 )
return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO );
mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
mpi_init( &T1 ); mpi_init( &T2 );
if( mpi_cmp_abs( A, B ) < 0 )
{
if( Q != NULL ) MPI_CHK( mpi_lset( Q, 0 ) );
if( R != NULL ) MPI_CHK( mpi_copy( R, A ) );
return( 0 );
}
MPI_CHK( mpi_copy( &X, A ) );
MPI_CHK( mpi_copy( &Y, B ) );
X.s = Y.s = 1;
MPI_CHK( mpi_grow( &Z, A->n + 2 ) );
MPI_CHK( mpi_lset( &Z, 0 ) );
MPI_CHK( mpi_grow( &T1, 2 ) );
MPI_CHK( mpi_grow( &T2, 3 ) );
k = mpi_msb( &Y ) % biL;
if( k < biL - 1 )
{
k = biL - 1 - k;
MPI_CHK( mpi_shift_l( &X, k ) );
MPI_CHK( mpi_shift_l( &Y, k ) );
}
else k = 0;
n = X.n - 1;
t = Y.n - 1;
MPI_CHK( mpi_shift_l( &Y, biL * (n - t) ) );
while( mpi_cmp_mpi( &X, &Y ) >= 0 )
{
Z.p[n - t]++;
MPI_CHK( mpi_sub_mpi( &X, &X, &Y ) );
}
MPI_CHK( mpi_shift_r( &Y, biL * (n - t) ) );
for( i = n; i > t ; i-- )
{
if( X.p[i] >= Y.p[t] )
Z.p[i - t - 1] = ~0;
else
{
/*
* The version of Clang shipped by Apple with Mavericks around
* 2014-03 can't handle 128-bit division properly. Disable
* 128-bits division for this version. Let's be optimistic and
* assume it'll be fixed in the next minor version (next
* patchlevel is probably a bit too optimistic).
*/
#if defined(POLARSSL_HAVE_UDBL) && \
! ( defined(__x86_64__) && defined(__APPLE__) && \
defined(__clang_major__) && __clang_major__ == 5 && \
defined(__clang_minor__) && __clang_minor__ == 0 )
t_udbl r;
r = (t_udbl) X.p[i] << biL;
r |= (t_udbl) X.p[i - 1];
r /= Y.p[t];
if( r > ((t_udbl) 1 << biL) - 1)
r = ((t_udbl) 1 << biL) - 1;
Z.p[i - t - 1] = (t_uint) r;
#else
/*
* __udiv_qrnnd_c, from gmp/longlong.h
*/
t_uint q0, q1, r0, r1;
t_uint d0, d1, d, m;
d = Y.p[t];
d0 = ( d << biH ) >> biH;
d1 = ( d >> biH );
q1 = X.p[i] / d1;
r1 = X.p[i] - d1 * q1;
r1 <<= biH;
r1 |= ( X.p[i - 1] >> biH );
m = q1 * d0;
if( r1 < m )
{
q1--, r1 += d;
while( r1 >= d && r1 < m )
q1--, r1 += d;
}
r1 -= m;
q0 = r1 / d1;
r0 = r1 - d1 * q0;
r0 <<= biH;
r0 |= ( X.p[i - 1] << biH ) >> biH;
m = q0 * d0;
if( r0 < m )
{
q0--, r0 += d;
while( r0 >= d && r0 < m )
q0--, r0 += d;
}
r0 -= m;
Z.p[i - t - 1] = ( q1 << biH ) | q0;
#endif
}
Z.p[i - t - 1]++;
do
{
Z.p[i - t - 1]--;
MPI_CHK( mpi_lset( &T1, 0 ) );
T1.p[0] = (t < 1) ? 0 : Y.p[t - 1];
T1.p[1] = Y.p[t];
MPI_CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) );
MPI_CHK( mpi_lset( &T2, 0 ) );
T2.p[0] = (i < 2) ? 0 : X.p[i - 2];
T2.p[1] = (i < 1) ? 0 : X.p[i - 1];
T2.p[2] = X.p[i];
}
while( mpi_cmp_mpi( &T1, &T2 ) > 0 );
MPI_CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) );
MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) );
MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) );
if( mpi_cmp_int( &X, 0 ) < 0 )
{
MPI_CHK( mpi_copy( &T1, &Y ) );
MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) );
MPI_CHK( mpi_add_mpi( &X, &X, &T1 ) );
Z.p[i - t - 1]--;
}
}
if( Q != NULL )
{
MPI_CHK( mpi_copy( Q, &Z ) );
Q->s = A->s * B->s;
}
if( R != NULL )
{
MPI_CHK( mpi_shift_r( &X, k ) );
X.s = A->s;
MPI_CHK( mpi_copy( R, &X ) );
if( mpi_cmp_int( R, 0 ) == 0 )
R->s = 1;
}
cleanup:
mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
mpi_free( &T1 ); mpi_free( &T2 );
return( ret );
}
/*
* Division by int: A = Q * b + R
*/
int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b )
{
mpi _B;
t_uint p[1];
p[0] = ( b < 0 ) ? -b : b;
_B.s = ( b < 0 ) ? -1 : 1;
_B.n = 1;
_B.p = p;
return( mpi_div_mpi( Q, R, A, &_B ) );
}
/*
* Modulo: R = A mod B
*/
int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B )
{
int ret;
if( mpi_cmp_int( B, 0 ) < 0 )
return POLARSSL_ERR_MPI_NEGATIVE_VALUE;
MPI_CHK( mpi_div_mpi( NULL, R, A, B ) );
while( mpi_cmp_int( R, 0 ) < 0 )
MPI_CHK( mpi_add_mpi( R, R, B ) );
while( mpi_cmp_mpi( R, B ) >= 0 )
MPI_CHK( mpi_sub_mpi( R, R, B ) );
cleanup:
return( ret );
}
/*
* Modulo: r = A mod b
*/
int mpi_mod_int( t_uint *r, const mpi *A, t_sint b )
{
size_t i;
t_uint x, y, z;
if( b == 0 )
return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO );
if( b < 0 )
return POLARSSL_ERR_MPI_NEGATIVE_VALUE;
/*
* handle trivial cases
*/
if( b == 1 )
{
*r = 0;
return( 0 );
}
if( b == 2 )
{
*r = A->p[0] & 1;
return( 0 );
}
/*
* general case
*/
for( i = A->n, y = 0; i > 0; i-- )
{
x = A->p[i - 1];
y = ( y << biH ) | ( x >> biH );
z = y / b;
y -= z * b;
x <<= biH;
y = ( y << biH ) | ( x >> biH );
z = y / b;
y -= z * b;
}
/*
* If A is negative, then the current y represents a negative value.
* Flipping it to the positive side.
*/
if( A->s < 0 && y != 0 )
y = b - y;
*r = y;
return( 0 );
}
/*
* Fast Montgomery initialization (thanks to Tom St Denis)
*/
static void mpi_montg_init( t_uint *mm, const mpi *N )
{
t_uint x, m0 = N->p[0];
unsigned int i;
x = m0;
x += ( ( m0 + 2 ) & 4 ) << 1;
for( i = biL; i >= 8; i /= 2 )
x *= ( 2 - ( m0 * x ) );
*mm = ~x + 1;
}
/*
* Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36)
*/
static void mpi_montmul( mpi *A, const mpi *B, const mpi *N, t_uint mm, const mpi *T )
{
size_t i, n, m;
t_uint u0, u1, *d;
memset( T->p, 0, T->n * ciL );
d = T->p;
n = N->n;
m = ( B->n < n ) ? B->n : n;
for( i = 0; i < n; i++ )
{
/*
* T = (T + u0*B + u1*N) / 2^biL
*/
u0 = A->p[i];
u1 = ( d[0] + u0 * B->p[0] ) * mm;
mpi_mul_hlp( m, B->p, d, u0 );
mpi_mul_hlp( n, N->p, d, u1 );
*d++ = u0; d[n + 1] = 0;
}
memcpy( A->p, d, (n + 1) * ciL );
if( mpi_cmp_abs( A, N ) >= 0 )
mpi_sub_hlp( n, N->p, A->p );
else
/* prevent timing attacks */
mpi_sub_hlp( n, A->p, T->p );
}
/*
* Montgomery reduction: A = A * R^-1 mod N
*/
static void mpi_montred( mpi *A, const mpi *N, t_uint mm, const mpi *T )
{
t_uint z = 1;
mpi U;
U.n = U.s = (int) z;
U.p = &z;
mpi_montmul( A, &U, N, mm, T );
}
/*
* Sliding-window exponentiation: X = A^E mod N (HAC 14.85)
*/
int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
{
int ret;
size_t wbits, wsize, one = 1;
size_t i, j, nblimbs;
size_t bufsize, nbits;
t_uint ei, mm, state;
mpi RR, T, W[ 2 << POLARSSL_MPI_WINDOW_SIZE ], Apos;
int neg;
if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 )
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
if( mpi_cmp_int( E, 0 ) < 0 )
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
/*
* Init temps and window size
*/
mpi_montg_init( &mm, N );
mpi_init( &RR ); mpi_init( &T );
mpi_init( &Apos );
memset( W, 0, sizeof( W ) );
i = mpi_msb( E );
wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1;
if( wsize > POLARSSL_MPI_WINDOW_SIZE )
wsize = POLARSSL_MPI_WINDOW_SIZE;
j = N->n + 1;
MPI_CHK( mpi_grow( X, j ) );
MPI_CHK( mpi_grow( &W[1], j ) );
MPI_CHK( mpi_grow( &T, j * 2 ) );
/*
* Compensate for negative A (and correct at the end)
*/
neg = ( A->s == -1 );
if( neg )
{
MPI_CHK( mpi_copy( &Apos, A ) );
Apos.s = 1;
A = &Apos;
}
/*
* If 1st call, pre-compute R^2 mod N
*/
if( _RR == NULL || _RR->p == NULL )
{
MPI_CHK( mpi_lset( &RR, 1 ) );
MPI_CHK( mpi_shift_l( &RR, N->n * 2 * biL ) );
MPI_CHK( mpi_mod_mpi( &RR, &RR, N ) );
if( _RR != NULL )
memcpy( _RR, &RR, sizeof( mpi ) );
}
else
memcpy( &RR, _RR, sizeof( mpi ) );
/*
* W[1] = A * R^2 * R^-1 mod N = A * R mod N
*/
if( mpi_cmp_mpi( A, N ) >= 0 )
{
MPI_CHK( mpi_mod_mpi( &W[1], A, N ) );
}
else
MPI_CHK( mpi_copy( &W[1], A ) );
mpi_montmul( &W[1], &RR, N, mm, &T );
/*
* X = R^2 * R^-1 mod N = R mod N
*/
MPI_CHK( mpi_copy( X, &RR ) );
mpi_montred( X, N, mm, &T );
if( wsize > 1 )
{
/*
* W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
*/
j = one << (wsize - 1);
MPI_CHK( mpi_grow( &W[j], N->n + 1 ) );
MPI_CHK( mpi_copy( &W[j], &W[1] ) );
for( i = 0; i < wsize - 1; i++ )
mpi_montmul( &W[j], &W[j], N, mm, &T );
/*
* W[i] = W[i - 1] * W[1]
*/
for( i = j + 1; i < (one << wsize); i++ )
{
MPI_CHK( mpi_grow( &W[i], N->n + 1 ) );
MPI_CHK( mpi_copy( &W[i], &W[i - 1] ) );
mpi_montmul( &W[i], &W[1], N, mm, &T );
}
}
nblimbs = E->n;
bufsize = 0;
nbits = 0;
wbits = 0;
state = 0;
while( 1 )
{
if( bufsize == 0 )
{
if( nblimbs == 0 )
break;
nblimbs--;
bufsize = sizeof( t_uint ) << 3;
}
bufsize--;
ei = (E->p[nblimbs] >> bufsize) & 1;
/*
* skip leading 0s
*/
if( ei == 0 && state == 0 )
continue;
if( ei == 0 && state == 1 )
{
/*
* out of window, square X
*/
mpi_montmul( X, X, N, mm, &T );
continue;
}
/*
* add ei to current window
*/
state = 2;
nbits++;
wbits |= (ei << (wsize - nbits));
if( nbits == wsize )
{
/*
* X = X^wsize R^-1 mod N
*/
for( i = 0; i < wsize; i++ )
mpi_montmul( X, X, N, mm, &T );
/*
* X = X * W[wbits] R^-1 mod N
*/
mpi_montmul( X, &W[wbits], N, mm, &T );
state--;
nbits = 0;
wbits = 0;
}
}
/*
* process the remaining bits
*/
for( i = 0; i < nbits; i++ )
{
mpi_montmul( X, X, N, mm, &T );
wbits <<= 1;
if( (wbits & (one << wsize)) != 0 )
mpi_montmul( X, &W[1], N, mm, &T );
}
/*
* X = A^E * R * R^-1 mod N = A^E mod N
*/
mpi_montred( X, N, mm, &T );
if( neg )
{
X->s = -1;
MPI_CHK( mpi_add_mpi( X, N, X ) );
}
cleanup:
for( i = (one << (wsize - 1)); i < (one << wsize); i++ )
mpi_free( &W[i] );
mpi_free( &W[1] ); mpi_free( &T ); mpi_free( &Apos );
if( _RR == NULL || _RR->p == NULL )
mpi_free( &RR );
return( ret );
}
/*
* Greatest common divisor: G = gcd(A, B) (HAC 14.54)
*/
int mpi_gcd( mpi *G, const mpi *A, const mpi *B )
{
int ret;
size_t lz, lzt;
mpi TG, TA, TB;
mpi_init( &TG ); mpi_init( &TA ); mpi_init( &TB );
MPI_CHK( mpi_copy( &TA, A ) );
MPI_CHK( mpi_copy( &TB, B ) );
lz = mpi_lsb( &TA );
lzt = mpi_lsb( &TB );
if ( lzt < lz )
lz = lzt;
MPI_CHK( mpi_shift_r( &TA, lz ) );
MPI_CHK( mpi_shift_r( &TB, lz ) );
TA.s = TB.s = 1;
while( mpi_cmp_int( &TA, 0 ) != 0 )
{
MPI_CHK( mpi_shift_r( &TA, mpi_lsb( &TA ) ) );
MPI_CHK( mpi_shift_r( &TB, mpi_lsb( &TB ) ) );
if( mpi_cmp_mpi( &TA, &TB ) >= 0 )
{
MPI_CHK( mpi_sub_abs( &TA, &TA, &TB ) );
MPI_CHK( mpi_shift_r( &TA, 1 ) );
}
else
{
MPI_CHK( mpi_sub_abs( &TB, &TB, &TA ) );
MPI_CHK( mpi_shift_r( &TB, 1 ) );
}
}
MPI_CHK( mpi_shift_l( &TB, lz ) );
MPI_CHK( mpi_copy( G, &TB ) );
cleanup:
mpi_free( &TG ); mpi_free( &TA ); mpi_free( &TB );
return( ret );
}
/*
* Fill X with size bytes of random.
*
* Use a temporary bytes representation to make sure the result is the same
* regardless of the platform endianness (usefull when f_rng is actually
* deterministic, eg for tests).
*/
int mpi_fill_random( mpi *X, size_t size,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int ret;
unsigned char buf[POLARSSL_MPI_MAX_SIZE];
if( size > POLARSSL_MPI_MAX_SIZE )
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( size ) ) );
MPI_CHK( mpi_lset( X, 0 ) );
MPI_CHK( f_rng( p_rng, buf, size ) );
MPI_CHK( mpi_read_binary( X, buf, size ) );
cleanup:
return( ret );
}
/*
* Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64)
*/
int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N )
{
int ret;
mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
if( mpi_cmp_int( N, 0 ) <= 0 )
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
mpi_init( &TA ); mpi_init( &TU ); mpi_init( &U1 ); mpi_init( &U2 );
mpi_init( &G ); mpi_init( &TB ); mpi_init( &TV );
mpi_init( &V1 ); mpi_init( &V2 );
MPI_CHK( mpi_gcd( &G, A, N ) );
if( mpi_cmp_int( &G, 1 ) != 0 )
{
ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE;
goto cleanup;
}
MPI_CHK( mpi_mod_mpi( &TA, A, N ) );
MPI_CHK( mpi_copy( &TU, &TA ) );
MPI_CHK( mpi_copy( &TB, N ) );
MPI_CHK( mpi_copy( &TV, N ) );
MPI_CHK( mpi_lset( &U1, 1 ) );
MPI_CHK( mpi_lset( &U2, 0 ) );
MPI_CHK( mpi_lset( &V1, 0 ) );
MPI_CHK( mpi_lset( &V2, 1 ) );
do
{
while( ( TU.p[0] & 1 ) == 0 )
{
MPI_CHK( mpi_shift_r( &TU, 1 ) );
if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 )
{
MPI_CHK( mpi_add_mpi( &U1, &U1, &TB ) );
MPI_CHK( mpi_sub_mpi( &U2, &U2, &TA ) );
}
MPI_CHK( mpi_shift_r( &U1, 1 ) );
MPI_CHK( mpi_shift_r( &U2, 1 ) );
}
while( ( TV.p[0] & 1 ) == 0 )
{
MPI_CHK( mpi_shift_r( &TV, 1 ) );
if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 )
{
MPI_CHK( mpi_add_mpi( &V1, &V1, &TB ) );
MPI_CHK( mpi_sub_mpi( &V2, &V2, &TA ) );
}
MPI_CHK( mpi_shift_r( &V1, 1 ) );
MPI_CHK( mpi_shift_r( &V2, 1 ) );
}
if( mpi_cmp_mpi( &TU, &TV ) >= 0 )
{
MPI_CHK( mpi_sub_mpi( &TU, &TU, &TV ) );
MPI_CHK( mpi_sub_mpi( &U1, &U1, &V1 ) );
MPI_CHK( mpi_sub_mpi( &U2, &U2, &V2 ) );
}
else
{
MPI_CHK( mpi_sub_mpi( &TV, &TV, &TU ) );
MPI_CHK( mpi_sub_mpi( &V1, &V1, &U1 ) );
MPI_CHK( mpi_sub_mpi( &V2, &V2, &U2 ) );
}
}
while( mpi_cmp_int( &TU, 0 ) != 0 );
while( mpi_cmp_int( &V1, 0 ) < 0 )
MPI_CHK( mpi_add_mpi( &V1, &V1, N ) );
while( mpi_cmp_mpi( &V1, N ) >= 0 )
MPI_CHK( mpi_sub_mpi( &V1, &V1, N ) );
MPI_CHK( mpi_copy( X, &V1 ) );
cleanup:
mpi_free( &TA ); mpi_free( &TU ); mpi_free( &U1 ); mpi_free( &U2 );
mpi_free( &G ); mpi_free( &TB ); mpi_free( &TV );
mpi_free( &V1 ); mpi_free( &V2 );
return( ret );
}
#if defined(POLARSSL_GENPRIME)
static const int small_prime[] =
{
3, 5, 7, 11, 13, 17, 19, 23,
29, 31, 37, 41, 43, 47, 53, 59,
61, 67, 71, 73, 79, 83, 89, 97,
101, 103, 107, 109, 113, 127, 131, 137,
139, 149, 151, 157, 163, 167, 173, 179,
181, 191, 193, 197, 199, 211, 223, 227,
229, 233, 239, 241, 251, 257, 263, 269,
271, 277, 281, 283, 293, 307, 311, 313,
317, 331, 337, 347, 349, 353, 359, 367,
373, 379, 383, 389, 397, 401, 409, 419,
421, 431, 433, 439, 443, 449, 457, 461,
463, 467, 479, 487, 491, 499, 503, 509,
521, 523, 541, 547, 557, 563, 569, 571,
577, 587, 593, 599, 601, 607, 613, 617,
619, 631, 641, 643, 647, 653, 659, 661,
673, 677, 683, 691, 701, 709, 719, 727,
733, 739, 743, 751, 757, 761, 769, 773,
787, 797, 809, 811, 821, 823, 827, 829,
839, 853, 857, 859, 863, 877, 881, 883,
887, 907, 911, 919, 929, 937, 941, 947,
953, 967, 971, 977, 983, 991, 997, -103
};
/*
* Miller-Rabin primality test (HAC 4.24)
*/
int mpi_is_prime( mpi *X,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int ret, xs;
size_t i, j, n, s;
mpi W, R, T, A, RR;
if( mpi_cmp_int( X, 0 ) == 0 ||
mpi_cmp_int( X, 1 ) == 0 )
return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE );
if( mpi_cmp_int( X, 2 ) == 0 )
return( 0 );
mpi_init( &W ); mpi_init( &R ); mpi_init( &T ); mpi_init( &A );
mpi_init( &RR );
xs = X->s; X->s = 1;
/*
* test trivial factors first
*/
if( ( X->p[0] & 1 ) == 0 )
return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE );
for( i = 0; small_prime[i] > 0; i++ )
{
t_uint r;
if( mpi_cmp_int( X, small_prime[i] ) <= 0 )
return( 0 );
MPI_CHK( mpi_mod_int( &r, X, small_prime[i] ) );
if( r == 0 )
return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE );
}
/*
* W = |X| - 1
* R = W >> lsb( W )
*/
MPI_CHK( mpi_sub_int( &W, X, 1 ) );
s = mpi_lsb( &W );
MPI_CHK( mpi_copy( &R, &W ) );
MPI_CHK( mpi_shift_r( &R, s ) );
i = mpi_msb( X );
/*
* HAC, table 4.4
*/
n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 :
( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 :
( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 );
for( i = 0; i < n; i++ )
{
/*
* pick a random A, 1 < A < |X| - 1
*/
MPI_CHK( mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
if( mpi_cmp_mpi( &A, &W ) >= 0 )
{
j = mpi_msb( &A ) - mpi_msb( &W );
MPI_CHK( mpi_shift_r( &A, j + 1 ) );
}
A.p[0] |= 3;
/*
* A = A^R mod |X|
*/
MPI_CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) );
if( mpi_cmp_mpi( &A, &W ) == 0 ||
mpi_cmp_int( &A, 1 ) == 0 )
continue;
j = 1;
while( j < s && mpi_cmp_mpi( &A, &W ) != 0 )
{
/*
* A = A * A mod |X|
*/
MPI_CHK( mpi_mul_mpi( &T, &A, &A ) );
MPI_CHK( mpi_mod_mpi( &A, &T, X ) );
if( mpi_cmp_int( &A, 1 ) == 0 )
break;
j++;
}
/*
* not prime if A != |X| - 1 or A == 1
*/
if( mpi_cmp_mpi( &A, &W ) != 0 ||
mpi_cmp_int( &A, 1 ) == 0 )
{
ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE;
break;
}
}
cleanup:
X->s = xs;
mpi_free( &W ); mpi_free( &R ); mpi_free( &T ); mpi_free( &A );
mpi_free( &RR );
return( ret );
}
/*
* Prime number generation
*/
int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int ret;
size_t k, n;
mpi Y;
if( nbits < 3 || nbits > POLARSSL_MPI_MAX_BITS )
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
mpi_init( &Y );
n = BITS_TO_LIMBS( nbits );
MPI_CHK( mpi_fill_random( X, n * ciL, f_rng, p_rng ) );
k = mpi_msb( X );
if( k < nbits ) MPI_CHK( mpi_shift_l( X, nbits - k ) );
if( k > nbits ) MPI_CHK( mpi_shift_r( X, k - nbits ) );
X->p[0] |= 3;
if( dh_flag == 0 )
{
while( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) != 0 )
{
if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE )
goto cleanup;
MPI_CHK( mpi_add_int( X, X, 2 ) );
}
}
else
{
MPI_CHK( mpi_sub_int( &Y, X, 1 ) );
MPI_CHK( mpi_shift_r( &Y, 1 ) );
while( 1 )
{
if( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) == 0 )
{
if( ( ret = mpi_is_prime( &Y, f_rng, p_rng ) ) == 0 )
break;
if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE )
goto cleanup;
}
if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE )
goto cleanup;
MPI_CHK( mpi_add_int( &Y, X, 1 ) );
MPI_CHK( mpi_add_int( X, X, 2 ) );
MPI_CHK( mpi_shift_r( &Y, 1 ) );
}
}
cleanup:
mpi_free( &Y );
return( ret );
}
#endif
#if defined(POLARSSL_SELF_TEST)
#define GCD_PAIR_COUNT 3
static const int gcd_pairs[GCD_PAIR_COUNT][3] =
{
{ 693, 609, 21 },
{ 1764, 868, 28 },
{ 768454923, 542167814, 1 }
};
/*
* Checkup routine
*/
int mpi_self_test( int verbose )
{
int ret, i;
mpi A, E, N, X, Y, U, V;
mpi_init( &A ); mpi_init( &E ); mpi_init( &N ); mpi_init( &X );
mpi_init( &Y ); mpi_init( &U ); mpi_init( &V );
MPI_CHK( mpi_read_string( &A, 16,
"EFE021C2645FD1DC586E69184AF4A31E" \
"D5F53E93B5F123FA41680867BA110131" \
"944FE7952E2517337780CB0DB80E61AA" \
"E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) );
MPI_CHK( mpi_read_string( &E, 16,
"B2E7EFD37075B9F03FF989C7C5051C20" \
"34D2A323810251127E7BF8625A4F49A5" \
"F3E27F4DA8BD59C47D6DAABA4C8127BD" \
"5B5C25763222FEFCCFC38B832366C29E" ) );
MPI_CHK( mpi_read_string( &N, 16,
"0066A198186C18C10B2F5ED9B522752A" \
"9830B69916E535C8F047518A889A43A5" \
"94B6BED27A168D31D4A52F88925AA8F5" ) );
MPI_CHK( mpi_mul_mpi( &X, &A, &N ) );
MPI_CHK( mpi_read_string( &U, 16,
"602AB7ECA597A3D6B56FF9829A5E8B85" \
"9E857EA95A03512E2BAE7391688D264A" \
"A5663B0341DB9CCFD2C4C5F421FEC814" \
"8001B72E848A38CAE1C65F78E56ABDEF" \
"E12D3C039B8A02D6BE593F0BBBDA56F1" \
"ECF677152EF804370C1A305CAF3B5BF1" \
"30879B56C61DE584A0F53A2447A51E" ) );
if( verbose != 0 )
printf( " MPI test #1 (mul_mpi): " );
if( mpi_cmp_mpi( &X, &U ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
ret = 1;
goto cleanup;
}
if( verbose != 0 )
printf( "passed\n" );
MPI_CHK( mpi_div_mpi( &X, &Y, &A, &N ) );
MPI_CHK( mpi_read_string( &U, 16,
"256567336059E52CAE22925474705F39A94" ) );
MPI_CHK( mpi_read_string( &V, 16,
"6613F26162223DF488E9CD48CC132C7A" \
"0AC93C701B001B092E4E5B9F73BCD27B" \
"9EE50D0657C77F374E903CDFA4C642" ) );
if( verbose != 0 )
printf( " MPI test #2 (div_mpi): " );
if( mpi_cmp_mpi( &X, &U ) != 0 ||
mpi_cmp_mpi( &Y, &V ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
ret = 1;
goto cleanup;
}
if( verbose != 0 )
printf( "passed\n" );
MPI_CHK( mpi_exp_mod( &X, &A, &E, &N, NULL ) );
MPI_CHK( mpi_read_string( &U, 16,
"36E139AEA55215609D2816998ED020BB" \
"BD96C37890F65171D948E9BC7CBAA4D9" \
"325D24D6A3C12710F10A09FA08AB87" ) );
if( verbose != 0 )
printf( " MPI test #3 (exp_mod): " );
if( mpi_cmp_mpi( &X, &U ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
ret = 1;
goto cleanup;
}
if( verbose != 0 )
printf( "passed\n" );
#if defined(POLARSSL_GENPRIME)
MPI_CHK( mpi_inv_mod( &X, &A, &N ) );
MPI_CHK( mpi_read_string( &U, 16,
"003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
"C3DBA76456363A10869622EAC2DD84EC" \
"C5B8A74DAC4D09E03B5E0BE779F2DF61" ) );
if( verbose != 0 )
printf( " MPI test #4 (inv_mod): " );
if( mpi_cmp_mpi( &X, &U ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
ret = 1;
goto cleanup;
}
if( verbose != 0 )
printf( "passed\n" );
#endif
if( verbose != 0 )
printf( " MPI test #5 (simple gcd): " );
for ( i = 0; i < GCD_PAIR_COUNT; i++)
{
MPI_CHK( mpi_lset( &X, gcd_pairs[i][0] ) );
MPI_CHK( mpi_lset( &Y, gcd_pairs[i][1] ) );
MPI_CHK( mpi_gcd( &A, &X, &Y ) );
if( mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 )
{
if( verbose != 0 )
printf( "failed at %d\n", i );
ret = 1;
goto cleanup;
}
}
if( verbose != 0 )
printf( "passed\n" );
cleanup:
if( ret != 0 && verbose != 0 )
printf( "Unexpected error, return code = %08X\n", ret );
mpi_free( &A ); mpi_free( &E ); mpi_free( &N ); mpi_free( &X );
mpi_free( &Y ); mpi_free( &U ); mpi_free( &V );
if( verbose != 0 )
printf( "\n" );
return( ret );
}
#endif
#endif