diff --git a/mpi/mpi-add.c b/mpi/mpi-add.c index 41dc3900..51dc71b7 100644 --- a/mpi/mpi-add.c +++ b/mpi/mpi-add.c @@ -1,239 +1,261 @@ /* mpi-add.c - MPI functions * Copyright (C) 1994, 1996, 1998, 2001, 2002, 2003 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1-or-later * * Note: This code is heavily based on the GNU MP Library. * Actually it's the same code with only minor changes in the * way the data is stored; this is to support the abstraction * of an optional secure memory allocation which may be used * to avoid revealing of sensitive data due to paging etc. */ #include #include #include #include "mpi-internal.h" /**************** * Add the unsigned integer V to the mpi-integer U and store the * result in W. U and V may be the same. */ void _gcry_mpi_add_ui (gcry_mpi_t w, gcry_mpi_t u, unsigned long v ) { mpi_ptr_t wp, up; mpi_size_t usize, wsize; int usign, wsign; usize = u->nlimbs; usign = u->sign; wsign = 0; /* If not space for W (and possible carry), increase space. */ wsize = usize + 1; if( w->alloced < wsize ) mpi_resize(w, wsize); /* These must be after realloc (U may be the same as W). */ up = u->d; wp = w->d; if( !usize ) { /* simple */ wp[0] = v; wsize = v? 1:0; } else if( !usign ) { /* mpi is not negative */ mpi_limb_t cy; cy = _gcry_mpih_add_1(wp, up, usize, v); wp[usize] = cy; wsize = usize + cy; } else { /* The signs are different. Need exact comparison to determine * which operand to subtract from which. */ if( usize == 1 && up[0] < v ) { wp[0] = v - up[0]; wsize = 1; } else { _gcry_mpih_sub_1(wp, up, usize, v); /* Size can decrease with at most one limb. */ wsize = usize - (wp[usize-1]==0); wsign = 1; } } w->nlimbs = wsize; w->sign = wsign; } static void _gcry_mpi_add_inv_sign(gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, int inv_v_sign) { mpi_ptr_t wp, up, vp; mpi_size_t usize, vsize, wsize; int usign, vsign, wsign; if( u->nlimbs < v->nlimbs ) { /* Swap U and V. */ usize = v->nlimbs; usign = v->sign ^ inv_v_sign; vsize = u->nlimbs; vsign = u->sign; wsize = usize + 1; RESIZE_IF_NEEDED(w, wsize); /* These must be after realloc (u or v may be the same as w). */ up = v->d; vp = u->d; } else { usize = u->nlimbs; usign = u->sign; vsize = v->nlimbs; vsign = v->sign ^ inv_v_sign; wsize = usize + 1; RESIZE_IF_NEEDED(w, wsize); /* These must be after realloc (u or v may be the same as w). */ up = u->d; vp = v->d; } wp = w->d; wsign = 0; if( !vsize ) { /* simple */ MPN_COPY(wp, up, usize ); wsize = usize; wsign = usign; } else if( usign != vsign ) { /* different sign */ /* This test is right since USIZE >= VSIZE */ if( usize != vsize ) { _gcry_mpih_sub(wp, up, usize, vp, vsize); wsize = usize; MPN_NORMALIZE(wp, wsize); wsign = usign; } else if( _gcry_mpih_cmp(up, vp, usize) < 0 ) { _gcry_mpih_sub_n(wp, vp, up, usize); wsize = usize; MPN_NORMALIZE(wp, wsize); if( !usign ) wsign = 1; } else { _gcry_mpih_sub_n(wp, up, vp, usize); wsize = usize; MPN_NORMALIZE(wp, wsize); if( usign ) wsign = 1; } } else { /* U and V have same sign. Add them. */ mpi_limb_t cy = _gcry_mpih_add(wp, up, usize, vp, vsize); wp[usize] = cy; wsize = usize + cy; if( usign ) wsign = 1; } w->nlimbs = wsize; w->sign = wsign; } /**************** * Subtract the unsigned integer V from the mpi-integer U and store the * result in W. */ void _gcry_mpi_sub_ui(gcry_mpi_t w, gcry_mpi_t u, unsigned long v ) { mpi_ptr_t wp, up; mpi_size_t usize, wsize; int usign, wsign; usize = u->nlimbs; usign = u->sign; wsign = 0; /* If not space for W (and possible carry), increase space. */ wsize = usize + 1; if( w->alloced < wsize ) mpi_resize(w, wsize); /* These must be after realloc (U may be the same as W). */ up = u->d; wp = w->d; if( !usize ) { /* simple */ wp[0] = v; wsize = v? 1:0; wsign = 1; } else if( usign ) { /* mpi and v are negative */ mpi_limb_t cy; cy = _gcry_mpih_add_1(wp, up, usize, v); wp[usize] = cy; wsize = usize + cy; wsign = 1; } else { /* The signs are different. Need exact comparison to determine * which operand to subtract from which. */ if( usize == 1 && up[0] < v ) { wp[0] = v - up[0]; wsize = 1; wsign = 1; } else { _gcry_mpih_sub_1(wp, up, usize, v); /* Size can decrease with at most one limb. */ wsize = usize - (wp[usize-1]==0); } } w->nlimbs = wsize; w->sign = wsign; } void _gcry_mpi_add(gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v) { _gcry_mpi_add_inv_sign (w, u, v, 0); } void _gcry_mpi_sub(gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v) { _gcry_mpi_add_inv_sign (w, u, v, 1); } void _gcry_mpi_addm( gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, gcry_mpi_t m) { + gcry_mpi_t temp_m = NULL; + + if (w == m) + { + temp_m = mpi_copy (m); + m = temp_m; + } + mpi_add (w, u, v); mpi_mod (w, w, m); + + if (temp_m) + mpi_free(temp_m); } void _gcry_mpi_subm( gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, gcry_mpi_t m) { + gcry_mpi_t temp_m = NULL; + + if (w == m) + { + temp_m = mpi_copy (m); + m = temp_m; + } + mpi_sub (w, u, v); mpi_mod (w, w, m); + + if (temp_m) + mpi_free(temp_m); } diff --git a/mpi/mpi-mul.c b/mpi/mpi-mul.c index 60f1ca48..e8e57475 100644 --- a/mpi/mpi-mul.c +++ b/mpi/mpi-mul.c @@ -1,212 +1,223 @@ /* mpi-mul.c - MPI functions * Copyright (C) 1994, 1996, 1998, 2001, 2002, 2003 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1-or-later * * Note: This code is heavily based on the GNU MP Library. * Actually it's the same code with only minor changes in the * way the data is stored; this is to support the abstraction * of an optional secure memory allocation which may be used * to avoid revealing of sensitive data due to paging etc. */ #include #include #include #include "mpi-internal.h" void _gcry_mpi_mul_ui (gcry_mpi_t prod, gcry_mpi_t mult, unsigned long small_mult) { mpi_size_t size, prod_size; mpi_ptr_t prod_ptr; mpi_limb_t cy; int sign; size = mult->nlimbs; sign = mult->sign; if( !size || !small_mult ) { prod->nlimbs = 0; prod->sign = 0; return; } prod_size = size + 1; if( prod->alloced < prod_size ) mpi_resize( prod, prod_size ); prod_ptr = prod->d; cy = _gcry_mpih_mul_1( prod_ptr, mult->d, size, (mpi_limb_t)small_mult ); if( cy ) prod_ptr[size++] = cy; prod->nlimbs = size; prod->sign = sign; } void _gcry_mpi_mul_2exp (gcry_mpi_t w, gcry_mpi_t u, unsigned long cnt) { mpi_size_t usize, wsize, limb_cnt; mpi_ptr_t wp; mpi_limb_t wlimb; int usign, wsign; usize = u->nlimbs; usign = u->sign; if( !usize ) { w->nlimbs = 0; w->sign = 0; return; } limb_cnt = cnt / BITS_PER_MPI_LIMB; wsize = usize + limb_cnt + 1; if( w->alloced < wsize ) mpi_resize(w, wsize ); wp = w->d; wsize = usize + limb_cnt; wsign = usign; cnt %= BITS_PER_MPI_LIMB; if( cnt ) { wlimb = _gcry_mpih_lshift( wp + limb_cnt, u->d, usize, cnt ); if( wlimb ) { wp[wsize] = wlimb; wsize++; } } else { MPN_COPY_DECR( wp + limb_cnt, u->d, usize ); } /* Zero all whole limbs at low end. Do it here and not before calling * mpn_lshift, not to lose for U == W. */ MPN_ZERO( wp, limb_cnt ); w->nlimbs = wsize; w->sign = wsign; } void _gcry_mpi_mul (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v) { mpi_size_t usize, vsize, wsize; mpi_ptr_t up, vp, wp; mpi_limb_t cy; int usign, vsign, usecure, vsecure, sign_product; int assign_wp=0; mpi_ptr_t tmp_limb=NULL; unsigned int tmp_limb_nlimbs = 0; if( u->nlimbs < v->nlimbs ) { /* Swap U and V. */ usize = v->nlimbs; usign = v->sign; usecure = mpi_is_secure(v); up = v->d; vsize = u->nlimbs; vsign = u->sign; vsecure = mpi_is_secure(u); vp = u->d; } else { usize = u->nlimbs; usign = u->sign; usecure = mpi_is_secure(u); up = u->d; vsize = v->nlimbs; vsign = v->sign; vsecure = mpi_is_secure(v); vp = v->d; } sign_product = usign ^ vsign; wp = w->d; /* Ensure W has space enough to store the result. */ wsize = usize + vsize; if ( !mpi_is_secure (w) && (mpi_is_secure (u) || mpi_is_secure (v)) ) { /* w is not allocated in secure space but u or v is. To make sure * that no temporray results are stored in w, we temporary use * a newly allocated limb space for w */ wp = mpi_alloc_limb_space( wsize, 1 ); assign_wp = 2; /* mark it as 2 so that we can later copy it back to * mormal memory */ } else if( w->alloced < wsize ) { if( wp == up || wp == vp ) { wp = mpi_alloc_limb_space( wsize, mpi_is_secure(w) ); assign_wp = 1; } else { mpi_resize(w, wsize ); wp = w->d; } } else { /* Make U and V not overlap with W. */ if( wp == up ) { /* W and U are identical. Allocate temporary space for U. */ tmp_limb_nlimbs = usize; up = tmp_limb = mpi_alloc_limb_space( usize, usecure ); /* Is V identical too? Keep it identical with U. */ if( wp == vp ) vp = up; /* Copy to the temporary space. */ MPN_COPY( up, wp, usize ); } else if( wp == vp ) { /* W and V are identical. Allocate temporary space for V. */ tmp_limb_nlimbs = vsize; vp = tmp_limb = mpi_alloc_limb_space( vsize, vsecure ); /* Copy to the temporary space. */ MPN_COPY( vp, wp, vsize ); } } if( !vsize ) wsize = 0; else { cy = _gcry_mpih_mul( wp, up, usize, vp, vsize ); wsize -= cy? 0:1; } if( assign_wp ) { if (assign_wp == 2) { /* copy the temp wp from secure memory back to normal memory */ mpi_ptr_t tmp_wp = mpi_alloc_limb_space (wsize, 0); MPN_COPY (tmp_wp, wp, wsize); _gcry_mpi_free_limb_space (wp, 0); wp = tmp_wp; } _gcry_mpi_assign_limb_space( w, wp, wsize ); } w->nlimbs = wsize; w->sign = sign_product; if( tmp_limb ) _gcry_mpi_free_limb_space (tmp_limb, tmp_limb_nlimbs); } void _gcry_mpi_mulm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, gcry_mpi_t m) { + gcry_mpi_t temp_m = NULL; + + if (w == m) + { + temp_m = mpi_copy (m); + m = temp_m; + } + mpi_mul (w, u, v); _gcry_mpi_tdiv_r (w, w, m); + + if (temp_m) + mpi_free(temp_m); } diff --git a/tests/mpitests.c b/tests/mpitests.c index 48ea18b2..2ee08bd3 100644 --- a/tests/mpitests.c +++ b/tests/mpitests.c @@ -1,715 +1,768 @@ /* mpitests.c - basic mpi tests * Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. * Copyright (C) 2013 g10 Code GmbH * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #ifdef _GCRYPT_IN_LIBGCRYPT # include "../src/gcrypt-int.h" #else # include #endif #define PGM "mpitests" #include "t-common.h" /* Set up some test patterns */ /* 48 bytes with value 1: this results in 8 limbs for 64bit limbs, 16limb for 32 bit limbs */ unsigned char ones[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; /* 48 bytes with value 2: this results in 8 limbs for 64bit limbs, 16limb for 32 bit limbs */ unsigned char twos[] = { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }; /* 48 bytes with value 3: this results in 8 limbs for 64bit limbs, 16limb for 32 bit limbs */ unsigned char threes[] = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 }; /* 48 bytes with value 0x80: this results in 8 limbs for 64bit limbs, 16limb for 32 bit limbs */ unsigned char eighties[] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; /* 48 bytes with value 0xff: this results in 8 limbs for 64bit limbs, 16limb for 32 bit limbs */ unsigned char manyff[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; static int test_const_and_immutable (void) { gcry_mpi_t one, second_one; one = gcry_mpi_set_ui (NULL, 1); if (gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE) || gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST)) die ("immutable or const flag initially set\n"); second_one = gcry_mpi_copy (one); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE)) die ("immutable flag set after copy\n"); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST)) die ("const flag set after copy\n"); gcry_mpi_release (second_one); gcry_mpi_set_flag (one, GCRYMPI_FLAG_IMMUTABLE); if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE)) die ("failed to set immutable flag\n"); if (gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST)) die ("const flag unexpectly set\n"); second_one = gcry_mpi_copy (one); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE)) die ("immutable flag not cleared after copy\n"); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST)) die ("const flag unexpectly set after copy\n"); gcry_mpi_release (second_one); gcry_mpi_clear_flag (one, GCRYMPI_FLAG_IMMUTABLE); if (gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE)) die ("failed to clear immutable flag\n"); if (gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST)) die ("const flag unexpectly set\n"); gcry_mpi_set_flag (one, GCRYMPI_FLAG_CONST); if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST)) die ("failed to set const flag\n"); if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE)) die ("failed to set immutable flag with const flag\n"); second_one = gcry_mpi_copy (one); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE)) die ("immutable flag not cleared after copy\n"); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST)) die ("const flag not cleared after copy\n"); gcry_mpi_release (second_one); gcry_mpi_clear_flag (one, GCRYMPI_FLAG_IMMUTABLE); if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE)) die ("clearing immutable flag not ignored for a constant MPI\n"); if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST)) die ("const flag unexpectly cleared\n"); second_one = gcry_mpi_set (NULL, GCRYMPI_CONST_ONE); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE)) die ("immutable flag not cleared by mpi_set (NULL,x)\n"); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST)) die ("const flag not cleared by mpi_set (NULL,x)\n"); gcry_mpi_release (second_one); second_one = gcry_mpi_set_ui (NULL, 42); gcry_mpi_set (second_one, GCRYMPI_CONST_ONE); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE)) die ("immutable flag not cleared after mpi_set (a,x)\n"); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST)) die ("const flag not cleared mpi_set (a,x)\n"); gcry_mpi_release (second_one); /* Due to the the constant flag the release below should be a NOP and will leak memory. */ gcry_mpi_release (one); return 1; } static void test_opaque (void) { gcry_mpi_t a; char *p; unsigned int nbits; p = gcry_xstrdup ("This is a test buffer"); a = gcry_mpi_set_opaque (NULL, p, 21*8+1); /* (a non byte aligned length) */ if (!gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) die ("opaque flag not set\n"); p = gcry_mpi_get_opaque (a, &nbits); if (!p) die ("gcry_mpi_get_opaque returned NULL\n"); if (nbits != 21*8+1) die ("gcry_mpi_get_opaque returned a changed bit size\n"); if (strcmp (p, "This is a test buffer")) die ("gcry_mpi_get_opaque returned a changed buffer\n"); if (debug) gcry_log_debugmpi ("mpi", a); gcry_mpi_release (a); p = gcry_xstrdup ("This is a test buffer"); a = gcry_mpi_set_opaque_copy (NULL, p, 21*8+1); gcry_free (p); if (!gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) die ("opaque flag not set\n"); p = gcry_mpi_get_opaque (a, &nbits); if (!p) die ("gcry_mpi_get_opaque returned NULL\n"); if (nbits != 21*8+1) die ("gcry_mpi_get_opaque returned a changed bit size\n"); if (strcmp (p, "This is a test buffer")) die ("gcry_mpi_get_opaque returned a changed buffer\n"); if (debug) gcry_log_debugmpi ("mpi", a); gcry_mpi_release (a); } static void test_maxsize (void) { gpg_error_t err; gcry_mpi_t a; unsigned int val; char buffer[2+2048]; /* For PGP: 2 length bytes and 16384 bits. */ memset (buffer, 0x55, sizeof buffer); /* We use a short buffer but a give a too large length to simulate a * programming error. In case this test fails (i.e. die() is * called) the scan function may have access data outside of BUFFER * which may result in a segv but we ignore that to avoid actually * allocating such a long buffer. */ err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, buffer, 16*1024*1024 +1, NULL); if (gpg_err_code (err) != GPG_ERR_INV_OBJ) die ("gcry_mpi_scan does not detect its generic input limit\n"); /* Now test the PGP limit. The scan code check the two length bytes * from the buffer and thus it is sufficient to fake them. */ buffer[0] = (16385 >> 8); buffer[1] = (16385 & 0xff); err = gcry_mpi_scan (&a, GCRYMPI_FMT_PGP, buffer, sizeof buffer, NULL); if (gpg_err_code (err) != GPG_ERR_INV_OBJ) die ("gcry_mpi_scan does not detect the PGP input limit\n"); buffer[0] = (16384 >> 8); buffer[1] = (16384 & 0xff); err = gcry_mpi_scan (&a, GCRYMPI_FMT_PGP, buffer, sizeof buffer, NULL); if (err) die ("gcry_mpi_scan did not parse a large PGP: %s\n", gpg_strerror (err)); /* Let's also test get_ui. */ gcry_mpi_set_ui (a, 0); val = 4711; err = gcry_mpi_get_ui (&val, a); if (err || val != 0) die ("gcry_mpi_get_ui failed at %d: %s\n", __LINE__, gpg_strerror (err)); gcry_mpi_sub_ui (a, a, 1); val = 4711; err = gcry_mpi_get_ui (&val, a); if (gpg_err_code (err) != GPG_ERR_ERANGE || val != 4711) die ("gcry_mpi_get_ui failed at %d: %s\n", __LINE__, gpg_strerror (err)); gcry_mpi_set_ui (a, 0xffffffff); val = 4711; err = gcry_mpi_get_ui (&val, a); if (err || val != 0xffffffff) die ("gcry_mpi_get_ui failed at %d: %s\n", __LINE__, gpg_strerror (err)); if (sizeof (val) == 4) { gcry_mpi_add_ui (a, a, 1); err = gcry_mpi_get_ui (&val, a); if (gpg_err_code (err) != GPG_ERR_ERANGE) die ("gcry_mpi_get_ui failed at %d: %s\n", __LINE__,gpg_strerror (err)); } gcry_mpi_release (a); } static void test_cmp (void) { gpg_error_t rc; gcry_mpi_t zero, zero2; gcry_mpi_t one; gcry_mpi_t two; gcry_mpi_t all_ones; gcry_mpi_t opa1, opa2; gcry_mpi_t opa1s, opa2s; gcry_mpi_t opa0, opa02; zero = gcry_mpi_new (0); zero2= gcry_mpi_set_ui (NULL, 0); one = gcry_mpi_set_ui (NULL, 1); two = gcry_mpi_set_ui (NULL, 2); rc = gcry_mpi_scan (&all_ones, GCRYMPI_FMT_USG, ones, sizeof(ones), NULL); if (rc) die ("scanning number failed at line %d", __LINE__); opa0 = gcry_mpi_set_opaque (NULL, gcry_xstrdup ("a"), 0); opa02 = gcry_mpi_set_opaque (NULL, gcry_xstrdup ("b"), 0); opa1 = gcry_mpi_set_opaque (NULL, gcry_xstrdup ("aaaaaaaaaaaaaaaa"), 16*8); opa1s = gcry_mpi_set_opaque (NULL, gcry_xstrdup ("a"), 1*8); opa2 = gcry_mpi_set_opaque (NULL, gcry_xstrdup ("bbbbbbbbbbbbbbbb"), 16*8); opa2s = gcry_mpi_set_opaque (NULL, gcry_xstrdup ("b"), 1*8); /* Single limb test with cmp_ui */ if (gcry_mpi_cmp_ui (zero, 0)) fail ("mpi_cmp_ui failed at line %d", __LINE__); if (!(gcry_mpi_cmp_ui (zero, 1) < 0)) fail ("mpi_cmp_ui failed at line %d", __LINE__); if (!(gcry_mpi_cmp_ui (zero, (-1)) < 0)) fail ("mpi_cmp_ui failed at line %d", __LINE__); if (gcry_mpi_cmp_ui (two, 2)) fail ("mpi_cmp_ui failed at line %d", __LINE__); if (!(gcry_mpi_cmp_ui (two, 3) < 0)) fail ("mpi_cmp_ui failed at line %d", __LINE__); if (!(gcry_mpi_cmp_ui (two, 1) > 0)) fail ("mpi_cmp_ui failed at line %d", __LINE__); /* Multi limb tests with cmp_ui. */ if (!(gcry_mpi_cmp_ui (all_ones, 0) > 0)) fail ("mpi_cmp_ui failed at line %d", __LINE__); if (!(gcry_mpi_cmp_ui (all_ones, (-1)) > 0)) fail ("mpi_cmp_ui failed at line %d", __LINE__); /* Single limb test with cmp */ if (gcry_mpi_cmp (zero, zero2)) fail ("mpi_cmp failed at line %d", __LINE__); if (!(gcry_mpi_cmp (zero, one) < 0)) fail ("mpi_cmp failed at line %d", __LINE__); if (!(gcry_mpi_cmp (one, zero) > 0)) fail ("mpi_cmp failed at line %d", __LINE__); gcry_mpi_neg (one, one); if (!(gcry_mpi_cmp (zero, one) > 0)) fail ("mpi_cmp failed at line %d", __LINE__); if (!(gcry_mpi_cmp (one, zero) < 0)) fail ("mpi_cmp failed at line %d", __LINE__); if (!(gcry_mpi_cmp (one, two) < 0)) fail ("mpi_cmp failed at line %d", __LINE__); gcry_mpi_neg (one, one); if (!(gcry_mpi_cmp (one, two) < 0)) fail ("mpi_cmp failed at line %d", __LINE__); if (!(gcry_mpi_cmp (two, one) > 0)) fail ("mpi_cmp failed at line %d", __LINE__); if (!(gcry_mpi_cmp (one, all_ones) < 0)) fail ("mpi_cmp failed at line %d", __LINE__); /* Tests with opaque values. */ if (!(gcry_mpi_cmp (opa1, one) < 0)) fail ("mpi_cmp failed at line %d", __LINE__); if (!(gcry_mpi_cmp (one, opa1) > 0)) fail ("mpi_cmp failed at line %d", __LINE__); if (!(gcry_mpi_cmp (opa0, opa02) == 0)) fail ("mpi_cmp failed at line %d", __LINE__); if (!(gcry_mpi_cmp (opa1s, opa1) < 0)) fail ("mpi_cmp failed at line %d", __LINE__); if (!(gcry_mpi_cmp (opa2, opa1s) > 0)) fail ("mpi_cmp failed at line %d", __LINE__); if (!(gcry_mpi_cmp (opa1, opa2) < 0)) fail ("mpi_cmp failed at line %d", __LINE__); if (!(gcry_mpi_cmp (opa2, opa1) > 0)) fail ("mpi_cmp failed at line %d", __LINE__); if (!(gcry_mpi_cmp (opa1, opa1) == 0)) fail ("mpi_cmp failed at line %d", __LINE__); gcry_mpi_release(opa2s); gcry_mpi_release(opa2); gcry_mpi_release(opa1s); gcry_mpi_release(opa1); gcry_mpi_release(opa02); gcry_mpi_release(opa0); gcry_mpi_release(all_ones); gcry_mpi_release(two); gcry_mpi_release(one); gcry_mpi_release(zero2); gcry_mpi_release(zero); } static int test_add (void) { gcry_mpi_t one; gcry_mpi_t two; gcry_mpi_t ff; gcry_mpi_t result; gcry_mpi_t minusfive; char *pc; gcry_mpi_scan(&one, GCRYMPI_FMT_USG, ones, sizeof(ones), NULL); gcry_mpi_scan(&two, GCRYMPI_FMT_USG, twos, sizeof(twos), NULL); gcry_mpi_scan(&ff, GCRYMPI_FMT_USG, manyff, sizeof(manyff), NULL); result = gcry_mpi_new(0); gcry_mpi_add(result, one, two); gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); if (debug) gcry_log_debug ("Result of one plus two:\n%s\n", pc); if (strcmp (pc, "030303030303030303030303030303030303030303030303" "030303030303030303030303030303030303030303030303") != 0) fail ("mpi_add failed at line %d", __LINE__); gcry_free(pc); gcry_mpi_add(result, ff, one); gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); if (debug) gcry_log_debug ("Result of ff plus one:\n%s\n", pc); if (strcmp (pc, "010101010101010101010101010101010101010101010101" "01010101010101010101010101010101010101010101010100") != 0) fail ("mpi_add failed at line %d", __LINE__); gcry_free(pc); gcry_mpi_scan(&minusfive, GCRYMPI_FMT_HEX, "-5", 0, NULL); gcry_mpi_add_ui (result, minusfive, 2); gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); if (debug) gcry_log_debug ("Result of minus five plus two:\n%s\n", pc); if (strcmp (pc, "-03") != 0) fail ("mpi_add_ui failed at line %d", __LINE__); gcry_free(pc); gcry_mpi_add_ui (result, result, 3); gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); if (debug) gcry_log_debug ("Result of minus three plus three:\n%s\n", pc); if (strcmp (pc, "00") != 0) fail ("mpi_add_ui failed at line %d", __LINE__); gcry_free(pc); gcry_mpi_release(one); gcry_mpi_release(two); gcry_mpi_release(ff); gcry_mpi_release(result); gcry_mpi_release(minusfive); return 1; } static int test_sub (void) { gcry_mpi_t zero; gcry_mpi_t one; gcry_mpi_t two; gcry_mpi_t five; gcry_mpi_t result; gcry_mpi_t minusfive; char *pc; gcry_mpi_scan(&one, GCRYMPI_FMT_USG, ones, sizeof(ones), NULL); gcry_mpi_scan(&two, GCRYMPI_FMT_USG, twos, sizeof(twos), NULL); result = gcry_mpi_new(0); gcry_mpi_sub(result, two, one); gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); if (debug) gcry_log_debug ("Result of two minus one:\n%s\n", pc); if (strcmp (pc, "010101010101010101010101010101010101010101010101" "010101010101010101010101010101010101010101010101") != 0) fail ("mpi_sub failed at line %d", __LINE__); gcry_free(pc); zero = gcry_mpi_new(0); five = gcry_mpi_new(0); minusfive = gcry_mpi_new(0); gcry_mpi_set_ui (zero, 0); gcry_mpi_set_ui (one, 1); gcry_mpi_set_ui (two, 2); gcry_mpi_set_ui (five, 5); gcry_mpi_sub (minusfive, zero, five); gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, minusfive); if (debug) gcry_log_debug ("Result of zero minus five:\n%s\n", pc); if (strcmp (pc, "-05") != 0) fail ("mpi_sub failed at line %d", __LINE__); gcry_free(pc); gcry_mpi_sub_ui (result, five, 2); gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); if (debug) gcry_log_debug ("Result of five minus two:\n%s\n", pc); if (strcmp (pc, "03") != 0) fail ("mpi_sub_ui failed at line %d", __LINE__); gcry_free(pc); gcry_mpi_sub_ui (result, one, 10); gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); if (debug) gcry_log_debug ("Result of one minus ten:\n%s\n", pc); if (strcmp (pc, "-09") != 0) fail ("mpi_sub_ui failed at line %d", __LINE__); gcry_free(pc); gcry_mpi_sub_ui (result, minusfive, 2); gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); if (debug) gcry_log_debug ("Result of minus five minus two:\n%s\n", pc); if (strcmp (pc, "-07") != 0) fail ("mpi_sub_ui failed at line %d", __LINE__); gcry_free(pc); gcry_mpi_release(one); gcry_mpi_release(two); gcry_mpi_release(result); gcry_mpi_release(zero); gcry_mpi_release(five); gcry_mpi_release(minusfive); return 1; } static int test_mul (void) { gcry_mpi_t two; gcry_mpi_t three; gcry_mpi_t result; gcry_mpi_t minusfive; char *pc; gcry_mpi_scan(&two, GCRYMPI_FMT_USG, twos, sizeof(twos), NULL); gcry_mpi_scan(&three, GCRYMPI_FMT_USG, threes, sizeof(threes), NULL); result = gcry_mpi_new(0); gcry_mpi_mul(result, two, three); gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); if (debug) gcry_log_debug ("Result of two mul three:\n%s\n", pc); if (strcmp (pc, "060C12181E242A30363C42484E545A60666C72787E848A90" "969CA2A8AEB4BAC0C6CCD2D8DEE4EAF0F6FD03090F151B21" "1B150F0902FCF6F0EAE4DED8D2CCC6C0BAB4AEA8A29C9690" "8A847E78726C66605A544E48423C36302A241E18120C06") != 0) fail ("mpi_mul failed at line %d", __LINE__); gcry_free(pc); gcry_mpi_scan(&minusfive, GCRYMPI_FMT_HEX, "-5", 0, NULL); gcry_mpi_mul_ui (result, minusfive, 3); gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); if (debug) gcry_log_debug ("Result of minus five mul three:\n%s\n", pc); if (strcmp (pc, "-0F") != 0) fail ("mpi_mul_ui failed at line %d", __LINE__); gcry_free(pc); gcry_mpi_mul_ui (result, result, 0); gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); if (debug) gcry_log_debug ("Result of minus fifteen mul zero:\n%s\n", pc); if (strcmp (pc, "00") != 0) fail ("mpi_mul_ui failed at line %d", __LINE__); gcry_free(pc); gcry_mpi_release(two); gcry_mpi_release(three); gcry_mpi_release(result); gcry_mpi_release(minusfive); return 1; } /* What we test here is that we don't overwrite our args and that using the same mpi for several args works. */ static int test_powm (void) { int b_int = 17; int e_int = 3; int m_int = 19; gcry_mpi_t base = gcry_mpi_set_ui (NULL, b_int); gcry_mpi_t exp = gcry_mpi_set_ui (NULL, e_int); gcry_mpi_t mod = gcry_mpi_set_ui (NULL, m_int); gcry_mpi_t res = gcry_mpi_new (0); gcry_mpi_powm (res, base, exp, mod); if (gcry_mpi_cmp_ui (base, b_int)) die ("test_powm failed for base at %d\n", __LINE__); if (gcry_mpi_cmp_ui (exp, e_int)) die ("test_powm_ui failed for exp at %d\n", __LINE__); if (gcry_mpi_cmp_ui (mod, m_int)) die ("test_powm failed for mod at %d\n", __LINE__); /* Check using base for the result. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_set_ui (exp, e_int); gcry_mpi_set_ui(mod, m_int); gcry_mpi_powm (base, base, exp, mod); if (gcry_mpi_cmp (res, base)) die ("test_powm failed at %d\n", __LINE__); if (gcry_mpi_cmp_ui (exp, e_int)) die ("test_powm_ui failed for exp at %d\n", __LINE__); if (gcry_mpi_cmp_ui (mod, m_int)) die ("test_powm failed for mod at %d\n", __LINE__); /* Check using exp for the result. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_set_ui (exp, e_int); gcry_mpi_set_ui(mod, m_int); gcry_mpi_powm (exp, base, exp, mod); if (gcry_mpi_cmp (res, exp)) die ("test_powm failed at %d\n", __LINE__); if (gcry_mpi_cmp_ui (base, b_int)) die ("test_powm failed for base at %d\n", __LINE__); if (gcry_mpi_cmp_ui (mod, m_int)) die ("test_powm failed for mod at %d\n", __LINE__); /* Check using mod for the result. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_set_ui (exp, e_int); gcry_mpi_set_ui(mod, m_int); gcry_mpi_powm (mod, base, exp, mod); if (gcry_mpi_cmp (res, mod)) die ("test_powm failed at %d\n", __LINE__); if (gcry_mpi_cmp_ui (base, b_int)) die ("test_powm failed for base at %d\n", __LINE__); if (gcry_mpi_cmp_ui (exp, e_int)) die ("test_powm_ui failed for exp at %d\n", __LINE__); /* Now check base ^ base mod mod. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_set_ui(mod, m_int); gcry_mpi_powm (res, base, base, mod); if (gcry_mpi_cmp_ui (base, b_int)) die ("test_powm failed for base at %d\n", __LINE__); if (gcry_mpi_cmp_ui (mod, m_int)) die ("test_powm failed for mod at %d\n", __LINE__); /* Check base ^ base mod mod with base as result. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_set_ui(mod, m_int); gcry_mpi_powm (base, base, base, mod); if (gcry_mpi_cmp (res, base)) die ("test_powm failed at %d\n", __LINE__); if (gcry_mpi_cmp_ui (mod, m_int)) die ("test_powm failed for mod at %d\n", __LINE__); /* Check base ^ base mod mod with mod as result. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_set_ui(mod, m_int); gcry_mpi_powm (mod, base, base, mod); if (gcry_mpi_cmp (res, mod)) die ("test_powm failed at %d\n", __LINE__); if (gcry_mpi_cmp_ui (base, b_int)) die ("test_powm failed for base at %d\n", __LINE__); /* Now check base ^ base mod base. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_powm (res, base, base, base); if (gcry_mpi_cmp_ui (base, b_int)) die ("test_powm failed for base at %d\n", __LINE__); /* Check base ^ base mod base with base as result. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_powm (base, base, base, base); if (gcry_mpi_cmp (res, base)) die ("test_powm failed at %d\n", __LINE__); /* Check for a case: base is negative and expo is even. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_neg (base, base); gcry_mpi_set_ui (exp, e_int * 2); gcry_mpi_set_ui(mod, m_int); gcry_mpi_powm (res, base, exp, mod); /* Result should be positive and it's 7 = (-17)^6 mod 19. */ if (gcry_mpi_is_neg (res) || gcry_mpi_cmp_ui (res, 7)) { if (verbose) { fprintf (stderr, "is_neg: %d\n", gcry_mpi_is_neg (res)); fprintf (stderr, "mpi: "); gcry_mpi_dump (res); putc ('\n', stderr); } die ("test_powm failed for negative base at %d\n", __LINE__); } gcry_mpi_release (base); gcry_mpi_release (exp); gcry_mpi_release (mod); gcry_mpi_release (res); /* Fixme: We should add the rest of the cases of course. */ return 1; } +/* What we test here is that using the same mpi for divider and result + works. */ +static int +test_addm_subm_mulm (void) +{ + int i; + + for (i = 0; i < 3; i++) + { + unsigned int expect; + const char *func; + gcry_mpi_t A; + gcry_mpi_t B; + gcry_mpi_t C; + + A = gcry_mpi_set_ui (NULL, 2); + B = gcry_mpi_set_ui (NULL, 4); + C = gcry_mpi_set_ui (NULL, 7); + + if (i == 0) + { + func = "mpi_addm"; + expect = 6; + gcry_mpi_addm(C, A, B, C); + } + else if (i == 1) + { + func = "mpi_subm"; + expect = 5; + gcry_mpi_subm(C, A, B, C); + } + else if (i == 2) + { + func = "mpi_mulm"; + expect = 1; + gcry_mpi_mulm(C, A, B, C); + } + + if (gcry_mpi_is_neg (C) || gcry_mpi_cmp_ui (C, expect)) + { + die ("test_addm_subm_mulm failed for %s at %d\n", func, __LINE__); + } + + gcry_mpi_release(A); + gcry_mpi_release(B); + gcry_mpi_release(C); + } + + return 1; +} + + int main (int argc, char* argv[]) { if (argc > 1 && !strcmp (argv[1], "--verbose")) verbose = 1; else if (argc > 1 && !strcmp (argv[1], "--debug")) verbose = debug = 1; if (!gcry_check_version (GCRYPT_VERSION)) { fputs ("version mismatch\n", stderr); exit (1); } xgcry_control ((GCRYCTL_DISABLE_SECMEM)); test_const_and_immutable (); test_opaque (); test_maxsize (); test_cmp (); test_add (); test_sub (); test_mul (); test_powm (); + test_addm_subm_mulm (); return !!error_count; }