summaryrefslogtreecommitdiff
path: root/libgcrypt-1.4.6/mpi/mpicoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgcrypt-1.4.6/mpi/mpicoder.c')
-rw-r--r--libgcrypt-1.4.6/mpi/mpicoder.c1503
1 files changed, 751 insertions, 752 deletions
diff --git a/libgcrypt-1.4.6/mpi/mpicoder.c b/libgcrypt-1.4.6/mpi/mpicoder.c
index 8f0c76f..b2d542c 100644
--- a/libgcrypt-1.4.6/mpi/mpicoder.c
+++ b/libgcrypt-1.4.6/mpi/mpicoder.c
@@ -1,752 +1,751 @@
-/* mpicoder.c - Coder for the external representation of MPIs
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
- * 2008 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <config.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "mpi-internal.h"
-#include "g10lib.h"
-
-#define MAX_EXTERN_MPI_BITS 16384
-
-/* Helper used to scan PGP style MPIs. Returns NULL on failure. */
-static gcry_mpi_t
-mpi_read_from_buffer (const unsigned char *buffer, unsigned *ret_nread,
- int secure)
-{
- int i, j;
- unsigned int nbits, nbytes, nlimbs, nread=0;
- mpi_limb_t a;
- gcry_mpi_t val = MPI_NULL;
-
- if ( *ret_nread < 2 )
- goto leave;
- nbits = buffer[0] << 8 | buffer[1];
- if ( nbits > MAX_EXTERN_MPI_BITS )
- {
-/* log_debug ("mpi too large (%u bits)\n", nbits); */
- goto leave;
- }
- else if( !nbits )
- {
-/* log_debug ("an mpi of size 0 is not allowed\n"); */
- goto leave;
- }
- buffer += 2;
- nread = 2;
-
- nbytes = (nbits+7) / 8;
- nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
- val = secure? mpi_alloc_secure (nlimbs) : mpi_alloc (nlimbs);
- i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
- i %= BYTES_PER_MPI_LIMB;
- j= val->nlimbs = nlimbs;
- val->sign = 0;
- for ( ; j > 0; j-- )
- {
- a = 0;
- for (; i < BYTES_PER_MPI_LIMB; i++ )
- {
- if ( ++nread > *ret_nread )
- {
-/* log_debug ("mpi larger than buffer"); */
- mpi_free (val);
- val = NULL;
- goto leave;
- }
- a <<= 8;
- a |= *buffer++;
- }
- i = 0;
- val->d[j-1] = a;
- }
-
- leave:
- *ret_nread = nread;
- return val;
-}
-
-
-/****************
- * Fill the mpi VAL from the hex string in STR.
- */
-static int
-mpi_fromstr (gcry_mpi_t val, const char *str)
-{
- int sign = 0;
- int prepend_zero = 0;
- int i, j, c, c1, c2;
- unsigned int nbits, nbytes, nlimbs;
- mpi_limb_t a;
-
- if ( *str == '-' )
- {
- sign = 1;
- str++;
- }
-
- /* Skip optional hex prefix. */
- if ( *str == '0' && str[1] == 'x' )
- str += 2;
-
- nbits = 4 * strlen (str);
- if ((nbits % 8))
- prepend_zero = 1;
-
- nbytes = (nbits+7) / 8;
- nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
-
- if ( val->alloced < nlimbs )
- mpi_resize (val, nlimbs);
-
- i = BYTES_PER_MPI_LIMB - (nbytes % BYTES_PER_MPI_LIMB);
- i %= BYTES_PER_MPI_LIMB;
- j = val->nlimbs = nlimbs;
- val->sign = sign;
- for (; j > 0; j--)
- {
- a = 0;
- for (; i < BYTES_PER_MPI_LIMB; i++)
- {
- if (prepend_zero)
- {
- c1 = '0';
- prepend_zero = 0;
- }
- else
- c1 = *str++;
-
- if (!c1)
- {
- mpi_clear (val);
- return 1; /* Error. */
- }
- c2 = *str++;
- if (!c2)
- {
- mpi_clear (val);
- return 1; /* Error. */
- }
- if ( c1 >= '0' && c1 <= '9' )
- c = c1 - '0';
- else if ( c1 >= 'a' && c1 <= 'f' )
- c = c1 - 'a' + 10;
- else if ( c1 >= 'A' && c1 <= 'F' )
- c = c1 - 'A' + 10;
- else
- {
- mpi_clear (val);
- return 1; /* Error. */
- }
- c <<= 4;
- if ( c2 >= '0' && c2 <= '9' )
- c |= c2 - '0';
- else if( c2 >= 'a' && c2 <= 'f' )
- c |= c2 - 'a' + 10;
- else if( c2 >= 'A' && c2 <= 'F' )
- c |= c2 - 'A' + 10;
- else
- {
- mpi_clear(val);
- return 1; /* Error. */
- }
- a <<= 8;
- a |= c;
- }
- i = 0;
- val->d[j-1] = a;
- }
-
- return 0; /* Okay. */
-}
-
-
-/* Dump the value of A in a format suitable for debugging to
- Libgcrypt's logging stream. Note that one leading space but no
- trailing space or linefeed will be printed. It is okay to pass
- NULL for A. */
-void
-gcry_mpi_dump (const gcry_mpi_t a)
-{
- int i;
-
- log_printf (" ");
- if (!a)
- log_printf ("[MPI_NULL]");
- else
- {
- if (a->sign)
- log_printf ( "-");
-#if BYTES_PER_MPI_LIMB == 2
-# define X "4"
-#elif BYTES_PER_MPI_LIMB == 4
-# define X "8"
-#elif BYTES_PER_MPI_LIMB == 8
-# define X "16"
-#elif BYTES_PER_MPI_LIMB == 16
-# define X "32"
-#else
-# error please define the format here
-#endif
- for (i=a->nlimbs; i > 0 ; i-- )
- {
- log_printf (i != a->nlimbs? "%0" X "lX":"%lX", (ulong)a->d[i-1]);
- }
-#undef X
- if (!a->nlimbs)
- log_printf ("0");
- }
-}
-
-/* Convience function used internally. */
-void
-_gcry_log_mpidump (const char *text, gcry_mpi_t a)
-{
- log_printf ("%s:", text);
- gcry_mpi_dump (a);
- log_printf ("\n");
-}
-
-
-/* Return an allocated buffer with the MPI (msb first). NBYTES
- receives the length of this buffer. Caller must free the return
- string. This function returns an allocated buffer with NBYTES set
- to zero if the value of A is zero. If sign is not NULL, it will be
- set to the sign of the A. On error NULL is returned and ERRNO set
- appropriately. */
-static unsigned char *
-do_get_buffer (gcry_mpi_t a, unsigned int *nbytes, int *sign, int force_secure)
-{
- unsigned char *p, *buffer;
- mpi_limb_t alimb;
- int i;
- size_t n;
-
- if (sign)
- *sign = a->sign;
-
- *nbytes = a->nlimbs * BYTES_PER_MPI_LIMB;
- n = *nbytes? *nbytes:1; /* Allocate at least one byte. */
- p = buffer = (force_secure || mpi_is_secure(a))? gcry_malloc_secure (n)
- : gcry_malloc (n);
- if (!buffer)
- return NULL;
-
- for (i=a->nlimbs-1; i >= 0; i--)
- {
- alimb = a->d[i];
-#if BYTES_PER_MPI_LIMB == 4
- *p++ = alimb >> 24;
- *p++ = alimb >> 16;
- *p++ = alimb >> 8;
- *p++ = alimb ;
-#elif BYTES_PER_MPI_LIMB == 8
- *p++ = alimb >> 56;
- *p++ = alimb >> 48;
- *p++ = alimb >> 40;
- *p++ = alimb >> 32;
- *p++ = alimb >> 24;
- *p++ = alimb >> 16;
- *p++ = alimb >> 8;
- *p++ = alimb ;
-#else
-# error please implement for this limb size.
-#endif
- }
-
- /* This is sub-optimal but we need to do the shift operation because
- the caller has to free the returned buffer. */
- for (p=buffer; !*p && *nbytes; p++, --*nbytes)
- ;
- if (p != buffer)
- memmove (buffer,p, *nbytes);
- return buffer;
-}
-
-
-byte *
-_gcry_mpi_get_buffer (gcry_mpi_t a, unsigned int *nbytes, int *sign)
-{
- return do_get_buffer (a, nbytes, sign, 0);
-}
-
-byte *
-_gcry_mpi_get_secure_buffer (gcry_mpi_t a, unsigned *nbytes, int *sign)
-{
- return do_get_buffer (a, nbytes, sign, 1);
-}
-
-
-/*
- * Use the NBYTES at BUFFER_ARG to update A. Set the sign of a to
- * SIGN.
- */
-void
-_gcry_mpi_set_buffer (gcry_mpi_t a, const void *buffer_arg,
- unsigned int nbytes, int sign)
-{
- const unsigned char *buffer = (const unsigned char*)buffer_arg;
- const unsigned char *p;
- mpi_limb_t alimb;
- int nlimbs;
- int i;
-
- nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
- RESIZE_IF_NEEDED(a, nlimbs);
- a->sign = sign;
-
- for (i=0, p = buffer+nbytes-1; p >= buffer+BYTES_PER_MPI_LIMB; )
- {
-#if BYTES_PER_MPI_LIMB == 4
- alimb = *p-- ;
- alimb |= *p-- << 8 ;
- alimb |= *p-- << 16 ;
- alimb |= *p-- << 24 ;
-#elif BYTES_PER_MPI_LIMB == 8
- alimb = (mpi_limb_t)*p-- ;
- alimb |= (mpi_limb_t)*p-- << 8 ;
- alimb |= (mpi_limb_t)*p-- << 16 ;
- alimb |= (mpi_limb_t)*p-- << 24 ;
- alimb |= (mpi_limb_t)*p-- << 32 ;
- alimb |= (mpi_limb_t)*p-- << 40 ;
- alimb |= (mpi_limb_t)*p-- << 48 ;
- alimb |= (mpi_limb_t)*p-- << 56 ;
-#else
-# error please implement for this limb size.
-#endif
- a->d[i++] = alimb;
- }
- if ( p >= buffer )
- {
-#if BYTES_PER_MPI_LIMB == 4
- alimb = *p--;
- if (p >= buffer)
- alimb |= *p-- << 8;
- if (p >= buffer)
- alimb |= *p-- << 16;
- if (p >= buffer)
- alimb |= *p-- << 24;
-#elif BYTES_PER_MPI_LIMB == 8
- alimb = (mpi_limb_t)*p--;
- if (p >= buffer)
- alimb |= (mpi_limb_t)*p-- << 8;
- if (p >= buffer)
- alimb |= (mpi_limb_t)*p-- << 16;
- if (p >= buffer)
- alimb |= (mpi_limb_t)*p-- << 24;
- if (p >= buffer)
- alimb |= (mpi_limb_t)*p-- << 32;
- if (p >= buffer)
- alimb |= (mpi_limb_t)*p-- << 40;
- if (p >= buffer)
- alimb |= (mpi_limb_t)*p-- << 48;
- if (p >= buffer)
- alimb |= (mpi_limb_t)*p-- << 56;
-#else
-# error please implement for this limb size.
-#endif
- a->d[i++] = alimb;
- }
- a->nlimbs = i;
- gcry_assert (i == nlimbs);
-}
-
-
-/* Convert the external representation of an integer stored in BUFFER
- with a length of BUFLEN into a newly create MPI returned in
- RET_MPI. If NBYTES is not NULL, it will receive the number of
- bytes actually scanned after a successful operation. */
-gcry_error_t
-gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format,
- const void *buffer_arg, size_t buflen, size_t *nscanned)
-{
- const unsigned char *buffer = (const unsigned char*)buffer_arg;
- struct gcry_mpi *a = NULL;
- unsigned int len;
- int secure = (buffer && gcry_is_secure (buffer));
-
- if (format == GCRYMPI_FMT_SSH)
- len = 0;
- else
- len = buflen;
-
- if (format == GCRYMPI_FMT_STD)
- {
- const unsigned char *s = buffer;
-
- a = secure? mpi_alloc_secure ((len+BYTES_PER_MPI_LIMB-1)
- /BYTES_PER_MPI_LIMB)
- : mpi_alloc ((len+BYTES_PER_MPI_LIMB-1)/BYTES_PER_MPI_LIMB);
- if (len)
- {
- a->sign = !!(*s & 0x80);
- if (a->sign)
- {
- /* FIXME: we have to convert from 2compl to magnitude format */
- mpi_free (a);
- return gcry_error (GPG_ERR_INTERNAL);
- }
- else
- _gcry_mpi_set_buffer (a, s, len, 0);
- }
- if (ret_mpi)
- {
- mpi_normalize ( a );
- *ret_mpi = a;
- }
- else
- mpi_free(a);
- return 0;
- }
- else if (format == GCRYMPI_FMT_USG)
- {
- a = secure? mpi_alloc_secure ((len+BYTES_PER_MPI_LIMB-1)
- /BYTES_PER_MPI_LIMB)
- : mpi_alloc ((len+BYTES_PER_MPI_LIMB-1)/BYTES_PER_MPI_LIMB);
-
- if (len)
- _gcry_mpi_set_buffer (a, buffer, len, 0);
- if (ret_mpi)
- {
- mpi_normalize ( a );
- *ret_mpi = a;
- }
- else
- mpi_free(a);
- return 0;
- }
- else if (format == GCRYMPI_FMT_PGP)
- {
- a = mpi_read_from_buffer (buffer, &len, secure);
- if (nscanned)
- *nscanned = len;
- if (ret_mpi && a)
- {
- mpi_normalize (a);
- *ret_mpi = a;
- }
- else if (a)
- {
- mpi_free(a);
- a = NULL;
- }
- return a? 0 : gcry_error (GPG_ERR_INV_OBJ);
- }
- else if (format == GCRYMPI_FMT_SSH)
- {
- const unsigned char *s = buffer;
- size_t n;
-
- if (len && len < 4)
- return gcry_error (GPG_ERR_TOO_SHORT);
-
- n = (s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]);
- s += 4;
- if (len)
- len -= 4;
- if (len && n > len)
- return gcry_error (GPG_ERR_TOO_LARGE);
-
- a = secure? mpi_alloc_secure ((n+BYTES_PER_MPI_LIMB-1)
- /BYTES_PER_MPI_LIMB)
- : mpi_alloc ((n+BYTES_PER_MPI_LIMB-1)/BYTES_PER_MPI_LIMB);
- if (n)
- {
- a->sign = !!(*s & 0x80);
- if (a->sign)
- {
- /* FIXME: we have to convert from 2compl to magnitude format */
- mpi_free(a);
- return gcry_error (GPG_ERR_INTERNAL);
- }
- else
- _gcry_mpi_set_buffer( a, s, n, 0 );
- }
- if (nscanned)
- *nscanned = n+4;
- if (ret_mpi)
- {
- mpi_normalize ( a );
- *ret_mpi = a;
- }
- else
- mpi_free(a);
- return 0;
- }
- else if (format == GCRYMPI_FMT_HEX)
- {
- /* We can only handle C strings for now. */
- if (buflen)
- return gcry_error (GPG_ERR_INV_ARG);
-
- a = secure? mpi_alloc_secure (0) : mpi_alloc(0);
- if (mpi_fromstr (a, (const char *)buffer))
- {
- mpi_free (a);
- return gcry_error (GPG_ERR_INV_OBJ);
- }
- if (ret_mpi)
- {
- mpi_normalize ( a );
- *ret_mpi = a;
- }
- else
- mpi_free(a);
- return 0;
- }
- else
- return gcry_error (GPG_ERR_INV_ARG);
-}
-
-
-/* Convert the big integer A into the external representation
- described by FORMAT and store it in the provided BUFFER which has
- been allocated by the user with a size of BUFLEN bytes. NWRITTEN
- receives the actual length of the external representation unless it
- has been passed as NULL. BUFFER may be NULL to query the required
- length. */
-gcry_error_t
-gcry_mpi_print (enum gcry_mpi_format format,
- unsigned char *buffer, size_t buflen,
- size_t *nwritten, struct gcry_mpi *a)
-{
- unsigned int nbits = mpi_get_nbits (a);
- size_t len;
- size_t dummy_nwritten;
-
- if (!nwritten)
- nwritten = &dummy_nwritten;
-
- len = buflen;
- *nwritten = 0;
- if (format == GCRYMPI_FMT_STD)
- {
- unsigned char *tmp;
- int extra = 0;
- unsigned int n;
-
- if (a->sign)
- return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */
-
- tmp = _gcry_mpi_get_buffer (a, &n, NULL);
- if (!tmp)
- return gpg_error_from_syserror ();
- if (n && (*tmp & 0x80))
- {
- n++;
- extra=1;
- }
-
- if (buffer && n > len)
- {
- /* The provided buffer is too short. */
- gcry_free (tmp);
- return gcry_error (GPG_ERR_TOO_SHORT);
- }
- if (buffer)
- {
- unsigned char *s = buffer;
-
- if (extra)
- *s++ = 0;
- memcpy (s, tmp, n-extra);
- }
- gcry_free(tmp);
- *nwritten = n;
- return 0;
- }
- else if (format == GCRYMPI_FMT_USG)
- {
- unsigned int n = (nbits + 7)/8;
-
- /* Note: We ignore the sign for this format. */
- /* FIXME: for performance reasons we should put this into
- mpi_aprint because we can then use the buffer directly. */
- if (buffer && n > len)
- return gcry_error (GPG_ERR_TOO_SHORT);
- if (buffer)
- {
- unsigned char *tmp;
-
- tmp = _gcry_mpi_get_buffer (a, &n, NULL);
- if (!tmp)
- return gpg_error_from_syserror ();
- memcpy (buffer, tmp, n);
- gcry_free (tmp);
- }
- *nwritten = n;
- return 0;
- }
- else if (format == GCRYMPI_FMT_PGP)
- {
- unsigned int n = (nbits + 7)/8;
-
- /* The PGP format can only handle unsigned integers. */
- if( a->sign )
- return gcry_error (GPG_ERR_INV_ARG);
-
- if (buffer && n+2 > len)
- return gcry_error (GPG_ERR_TOO_SHORT);
-
- if (buffer)
- {
- unsigned char *tmp;
- unsigned char *s = buffer;
-
- s[0] = nbits >> 8;
- s[1] = nbits;
-
- tmp = _gcry_mpi_get_buffer (a, &n, NULL);
- if (!tmp)
- return gpg_error_from_syserror ();
- memcpy (s+2, tmp, n);
- gcry_free (tmp);
- }
- *nwritten = n+2;
- return 0;
- }
- else if (format == GCRYMPI_FMT_SSH)
- {
- unsigned char *tmp;
- int extra = 0;
- unsigned int n;
-
- if (a->sign)
- return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */
-
- tmp = _gcry_mpi_get_buffer (a, &n, NULL);
- if (!tmp)
- return gpg_error_from_syserror ();
- if (n && (*tmp & 0x80))
- {
- n++;
- extra=1;
- }
-
- if (buffer && n+4 > len)
- {
- gcry_free(tmp);
- return gcry_error (GPG_ERR_TOO_SHORT);
- }
-
- if (buffer)
- {
- unsigned char *s = buffer;
-
- *s++ = n >> 24;
- *s++ = n >> 16;
- *s++ = n >> 8;
- *s++ = n;
- if (extra)
- *s++ = 0;
-
- memcpy (s, tmp, n-extra);
- }
- gcry_free (tmp);
- *nwritten = 4+n;
- return 0;
- }
- else if (format == GCRYMPI_FMT_HEX)
- {
- unsigned char *tmp;
- int i;
- int extra = 0;
- unsigned int n = 0;
-
- tmp = _gcry_mpi_get_buffer (a, &n, NULL);
- if (!tmp)
- return gpg_error_from_syserror ();
- if (!n || (*tmp & 0x80))
- extra = 2;
-
- if (buffer && 2*n + extra + !!a->sign + 1 > len)
- {
- gcry_free(tmp);
- return gcry_error (GPG_ERR_TOO_SHORT);
- }
- if (buffer)
- {
- unsigned char *s = buffer;
-
- if (a->sign)
- *s++ = '-';
- if (extra)
- {
- *s++ = '0';
- *s++ = '0';
- }
-
- for (i=0; i < n; i++)
- {
- unsigned int c = tmp[i];
-
- *s++ = (c >> 4) < 10? '0'+(c>>4) : 'A'+(c>>4)-10 ;
- c &= 15;
- *s++ = c < 10? '0'+c : 'A'+c-10 ;
- }
- *s++ = 0;
- *nwritten = s - buffer;
- }
- else
- {
- *nwritten = 2*n + extra + !!a->sign + 1;
- }
- gcry_free (tmp);
- return 0;
- }
- else
- return gcry_error (GPG_ERR_INV_ARG);
-}
-
-
-/*
- * Like gcry_mpi_print but this function allocates the buffer itself.
- * The caller has to supply the address of a pointer. NWRITTEN may be
- * NULL.
- */
-gcry_error_t
-gcry_mpi_aprint (enum gcry_mpi_format format,
- unsigned char **buffer, size_t *nwritten,
- struct gcry_mpi *a)
-{
- size_t n;
- gcry_error_t rc;
-
- *buffer = NULL;
- rc = gcry_mpi_print (format, NULL, 0, &n, a);
- if (rc)
- return rc;
-
- *buffer = mpi_is_secure(a) ? gcry_malloc_secure (n) : gcry_malloc (n);
- if (!*buffer)
- return gpg_error_from_syserror ();
- rc = gcry_mpi_print( format, *buffer, n, &n, a );
- if (rc)
- {
- gcry_free(*buffer);
- *buffer = NULL;
- }
- else if (nwritten)
- *nwritten = n;
- return rc;
-}
-
+/* mpicoder.c - Coder for the external representation of MPIs
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
+ * 2008 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "mpi-internal.h"
+#include "g10lib.h"
+
+#define MAX_EXTERN_MPI_BITS 16384
+
+/* Helper used to scan PGP style MPIs. Returns NULL on failure. */
+static gcry_mpi_t
+mpi_read_from_buffer (const unsigned char *buffer, unsigned *ret_nread,
+ int secure)
+{
+ int i, j;
+ unsigned int nbits, nbytes, nlimbs, nread=0;
+ mpi_limb_t a;
+ gcry_mpi_t val = MPI_NULL;
+
+ if ( *ret_nread < 2 )
+ goto leave;
+ nbits = buffer[0] << 8 | buffer[1];
+ if ( nbits > MAX_EXTERN_MPI_BITS )
+ {
+/* log_debug ("mpi too large (%u bits)\n", nbits); */
+ goto leave;
+ }
+ buffer += 2;
+ nread = 2;
+
+ nbytes = (nbits+7) / 8;
+ nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
+ val = secure? mpi_alloc_secure (nlimbs) : mpi_alloc (nlimbs);
+ i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
+ i %= BYTES_PER_MPI_LIMB;
+ j= val->nlimbs = nlimbs;
+ val->sign = 0;
+ for ( ; j > 0; j-- )
+ {
+ a = 0;
+ for (; i < BYTES_PER_MPI_LIMB; i++ )
+ {
+ if ( ++nread > *ret_nread )
+ {
+/* log_debug ("mpi larger than buffer"); */
+ mpi_free (val);
+ val = NULL;
+ goto leave;
+ }
+ a <<= 8;
+ a |= *buffer++;
+ }
+ i = 0;
+ val->d[j-1] = a;
+ }
+
+ leave:
+ *ret_nread = nread;
+ return val;
+}
+
+
+/****************
+ * Fill the mpi VAL from the hex string in STR.
+ */
+static int
+mpi_fromstr (gcry_mpi_t val, const char *str)
+{
+ int sign = 0;
+ int prepend_zero = 0;
+ int i, j, c, c1, c2;
+ unsigned int nbits, nbytes, nlimbs;
+ mpi_limb_t a;
+
+ if ( *str == '-' )
+ {
+ sign = 1;
+ str++;
+ }
+
+ /* Skip optional hex prefix. */
+ if ( *str == '0' && str[1] == 'x' )
+ str += 2;
+
+ nbits = 4 * strlen (str);
+ if ((nbits % 8))
+ prepend_zero = 1;
+
+ nbytes = (nbits+7) / 8;
+ nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
+
+ if ( val->alloced < nlimbs )
+ mpi_resize (val, nlimbs);
+
+ i = BYTES_PER_MPI_LIMB - (nbytes % BYTES_PER_MPI_LIMB);
+ i %= BYTES_PER_MPI_LIMB;
+ j = val->nlimbs = nlimbs;
+ val->sign = sign;
+ for (; j > 0; j--)
+ {
+ a = 0;
+ for (; i < BYTES_PER_MPI_LIMB; i++)
+ {
+ if (prepend_zero)
+ {
+ c1 = '0';
+ prepend_zero = 0;
+ }
+ else
+ c1 = *str++;
+
+ if (!c1)
+ {
+ mpi_clear (val);
+ return 1; /* Error. */
+ }
+ c2 = *str++;
+ if (!c2)
+ {
+ mpi_clear (val);
+ return 1; /* Error. */
+ }
+ if ( c1 >= '0' && c1 <= '9' )
+ c = c1 - '0';
+ else if ( c1 >= 'a' && c1 <= 'f' )
+ c = c1 - 'a' + 10;
+ else if ( c1 >= 'A' && c1 <= 'F' )
+ c = c1 - 'A' + 10;
+ else
+ {
+ mpi_clear (val);
+ return 1; /* Error. */
+ }
+ c <<= 4;
+ if ( c2 >= '0' && c2 <= '9' )
+ c |= c2 - '0';
+ else if( c2 >= 'a' && c2 <= 'f' )
+ c |= c2 - 'a' + 10;
+ else if( c2 >= 'A' && c2 <= 'F' )
+ c |= c2 - 'A' + 10;
+ else
+ {
+ mpi_clear(val);
+ return 1; /* Error. */
+ }
+ a <<= 8;
+ a |= c;
+ }
+ i = 0;
+ val->d[j-1] = a;
+ }
+
+ return 0; /* Okay. */
+}
+
+
+/* Dump the value of A in a format suitable for debugging to
+ Libgcrypt's logging stream. Note that one leading space but no
+ trailing space or linefeed will be printed. It is okay to pass
+ NULL for A. */
+void
+gcry_mpi_dump (const gcry_mpi_t a)
+{
+ int i;
+
+ log_printf (" ");
+ if (!a)
+ log_printf ("[MPI_NULL]");
+ else
+ {
+ if (a->sign)
+ log_printf ( "-");
+#if BYTES_PER_MPI_LIMB == 2
+# define X "4"
+#elif BYTES_PER_MPI_LIMB == 4
+# define X "8"
+#elif BYTES_PER_MPI_LIMB == 8
+# define X "16"
+#elif BYTES_PER_MPI_LIMB == 16
+# define X "32"
+#else
+# error please define the format here
+#endif
+ for (i=a->nlimbs; i > 0 ; i-- )
+ {
+ log_printf (i != a->nlimbs? "%0" X "lX":"%lX", (ulong)a->d[i-1]);
+ }
+#undef X
+ if (!a->nlimbs)
+ log_printf ("0");
+ }
+}
+
+/* Convience function used internally. */
+void
+_gcry_log_mpidump (const char *text, gcry_mpi_t a)
+{
+ log_printf ("%s:", text);
+ gcry_mpi_dump (a);
+ log_printf ("\n");
+}
+
+
+/* Return an allocated buffer with the MPI (msb first). NBYTES
+ receives the length of this buffer. Caller must free the return
+ string. This function returns an allocated buffer with NBYTES set
+ to zero if the value of A is zero. If sign is not NULL, it will be
+ set to the sign of the A. On error NULL is returned and ERRNO set
+ appropriately. */
+static unsigned char *
+do_get_buffer (gcry_mpi_t a, unsigned int *nbytes, int *sign, int force_secure)
+{
+ unsigned char *p, *buffer;
+ mpi_limb_t alimb;
+ int i;
+ size_t n;
+
+ if (sign)
+ *sign = a->sign;
+
+ *nbytes = a->nlimbs * BYTES_PER_MPI_LIMB;
+ n = *nbytes? *nbytes:1; /* Allocate at least one byte. */
+ p = buffer = (force_secure || mpi_is_secure(a))? gcry_malloc_secure (n)
+ : gcry_malloc (n);
+ if (!buffer)
+ return NULL;
+
+ for (i=a->nlimbs-1; i >= 0; i--)
+ {
+ alimb = a->d[i];
+#if BYTES_PER_MPI_LIMB == 4
+ *p++ = alimb >> 24;
+ *p++ = alimb >> 16;
+ *p++ = alimb >> 8;
+ *p++ = alimb ;
+#elif BYTES_PER_MPI_LIMB == 8
+ *p++ = alimb >> 56;
+ *p++ = alimb >> 48;
+ *p++ = alimb >> 40;
+ *p++ = alimb >> 32;
+ *p++ = alimb >> 24;
+ *p++ = alimb >> 16;
+ *p++ = alimb >> 8;
+ *p++ = alimb ;
+#else
+# error please implement for this limb size.
+#endif
+ }
+
+ /* This is sub-optimal but we need to do the shift operation because
+ the caller has to free the returned buffer. */
+ for (p=buffer; !*p && *nbytes; p++, --*nbytes)
+ ;
+ if (p != buffer)
+ memmove (buffer,p, *nbytes);
+ return buffer;
+}
+
+
+byte *
+_gcry_mpi_get_buffer (gcry_mpi_t a, unsigned int *nbytes, int *sign)
+{
+ return do_get_buffer (a, nbytes, sign, 0);
+}
+
+byte *
+_gcry_mpi_get_secure_buffer (gcry_mpi_t a, unsigned *nbytes, int *sign)
+{
+ return do_get_buffer (a, nbytes, sign, 1);
+}
+
+
+/*
+ * Use the NBYTES at BUFFER_ARG to update A. Set the sign of a to
+ * SIGN.
+ */
+void
+_gcry_mpi_set_buffer (gcry_mpi_t a, const void *buffer_arg,
+ unsigned int nbytes, int sign)
+{
+ const unsigned char *buffer = (const unsigned char*)buffer_arg;
+ const unsigned char *p;
+ mpi_limb_t alimb;
+ int nlimbs;
+ int i;
+
+ nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
+ RESIZE_IF_NEEDED(a, nlimbs);
+ a->sign = sign;
+
+ for (i=0, p = buffer+nbytes-1; p >= buffer+BYTES_PER_MPI_LIMB; )
+ {
+#if BYTES_PER_MPI_LIMB == 4
+ alimb = *p-- ;
+ alimb |= *p-- << 8 ;
+ alimb |= *p-- << 16 ;
+ alimb |= *p-- << 24 ;
+#elif BYTES_PER_MPI_LIMB == 8
+ alimb = (mpi_limb_t)*p-- ;
+ alimb |= (mpi_limb_t)*p-- << 8 ;
+ alimb |= (mpi_limb_t)*p-- << 16 ;
+ alimb |= (mpi_limb_t)*p-- << 24 ;
+ alimb |= (mpi_limb_t)*p-- << 32 ;
+ alimb |= (mpi_limb_t)*p-- << 40 ;
+ alimb |= (mpi_limb_t)*p-- << 48 ;
+ alimb |= (mpi_limb_t)*p-- << 56 ;
+#else
+# error please implement for this limb size.
+#endif
+ a->d[i++] = alimb;
+ }
+ if ( p >= buffer )
+ {
+#if BYTES_PER_MPI_LIMB == 4
+ alimb = *p--;
+ if (p >= buffer)
+ alimb |= *p-- << 8;
+ if (p >= buffer)
+ alimb |= *p-- << 16;
+ if (p >= buffer)
+ alimb |= *p-- << 24;
+#elif BYTES_PER_MPI_LIMB == 8
+ alimb = (mpi_limb_t)*p--;
+ if (p >= buffer)
+ alimb |= (mpi_limb_t)*p-- << 8;
+ if (p >= buffer)
+ alimb |= (mpi_limb_t)*p-- << 16;
+ if (p >= buffer)
+ alimb |= (mpi_limb_t)*p-- << 24;
+ if (p >= buffer)
+ alimb |= (mpi_limb_t)*p-- << 32;
+ if (p >= buffer)
+ alimb |= (mpi_limb_t)*p-- << 40;
+ if (p >= buffer)
+ alimb |= (mpi_limb_t)*p-- << 48;
+ if (p >= buffer)
+ alimb |= (mpi_limb_t)*p-- << 56;
+#else
+# error please implement for this limb size.
+#endif
+ a->d[i++] = alimb;
+ }
+ a->nlimbs = i;
+ gcry_assert (i == nlimbs);
+}
+
+
+/* Convert the external representation of an integer stored in BUFFER
+ with a length of BUFLEN into a newly create MPI returned in
+ RET_MPI. If NBYTES is not NULL, it will receive the number of
+ bytes actually scanned after a successful operation. */
+gcry_error_t
+gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format,
+ const void *buffer_arg, size_t buflen, size_t *nscanned)
+{
+ const unsigned char *buffer = (const unsigned char*)buffer_arg;
+ struct gcry_mpi *a = NULL;
+ unsigned int len;
+ int secure = (buffer && gcry_is_secure (buffer));
+
+ if (format == GCRYMPI_FMT_SSH)
+ len = 0;
+ else
+ len = buflen;
+
+ if (format == GCRYMPI_FMT_STD)
+ {
+ const unsigned char *s = buffer;
+
+ a = secure? mpi_alloc_secure ((len+BYTES_PER_MPI_LIMB-1)
+ /BYTES_PER_MPI_LIMB)
+ : mpi_alloc ((len+BYTES_PER_MPI_LIMB-1)/BYTES_PER_MPI_LIMB);
+ if (len)
+ {
+ a->sign = !!(*s & 0x80);
+ if (a->sign)
+ {
+ /* FIXME: we have to convert from 2compl to magnitude format */
+ mpi_free (a);
+ return gcry_error (GPG_ERR_INTERNAL);
+ }
+ else
+ _gcry_mpi_set_buffer (a, s, len, 0);
+ }
+ if (ret_mpi)
+ {
+ mpi_normalize ( a );
+ *ret_mpi = a;
+ }
+ else
+ mpi_free(a);
+ return 0;
+ }
+ else if (format == GCRYMPI_FMT_USG)
+ {
+ a = secure? mpi_alloc_secure ((len+BYTES_PER_MPI_LIMB-1)
+ /BYTES_PER_MPI_LIMB)
+ : mpi_alloc ((len+BYTES_PER_MPI_LIMB-1)/BYTES_PER_MPI_LIMB);
+
+ if (len)
+ _gcry_mpi_set_buffer (a, buffer, len, 0);
+ if (ret_mpi)
+ {
+ mpi_normalize ( a );
+ *ret_mpi = a;
+ }
+ else
+ mpi_free(a);
+ return 0;
+ }
+ else if (format == GCRYMPI_FMT_PGP)
+ {
+ a = mpi_read_from_buffer (buffer, &len, secure);
+ if (nscanned)
+ *nscanned = len;
+ if (ret_mpi && a)
+ {
+ mpi_normalize (a);
+ *ret_mpi = a;
+ }
+ else if (a)
+ {
+ mpi_free(a);
+ a = NULL;
+ }
+ return a? 0 : gcry_error (GPG_ERR_INV_OBJ);
+ }
+ else if (format == GCRYMPI_FMT_SSH)
+ {
+ const unsigned char *s = buffer;
+ size_t n;
+
+ /* This test is not strictly necessary and an assert (!len)
+ would be sufficient. We keep this test in case we later
+ allow the BUFLEN argument to act as a sanitiy check. Same
+ below. */
+ if (len && len < 4)
+ return gcry_error (GPG_ERR_TOO_SHORT);
+
+ n = (s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]);
+ s += 4;
+ if (len)
+ len -= 4;
+ if (len && n > len)
+ return gcry_error (GPG_ERR_TOO_LARGE);
+
+ a = secure? mpi_alloc_secure ((n+BYTES_PER_MPI_LIMB-1)
+ /BYTES_PER_MPI_LIMB)
+ : mpi_alloc ((n+BYTES_PER_MPI_LIMB-1)/BYTES_PER_MPI_LIMB);
+ if (n)
+ {
+ a->sign = !!(*s & 0x80);
+ if (a->sign)
+ {
+ /* FIXME: we have to convert from 2compl to magnitude format */
+ mpi_free(a);
+ return gcry_error (GPG_ERR_INTERNAL);
+ }
+ else
+ _gcry_mpi_set_buffer( a, s, n, 0 );
+ }
+ if (nscanned)
+ *nscanned = n+4;
+ if (ret_mpi)
+ {
+ mpi_normalize ( a );
+ *ret_mpi = a;
+ }
+ else
+ mpi_free(a);
+ return 0;
+ }
+ else if (format == GCRYMPI_FMT_HEX)
+ {
+ /* We can only handle C strings for now. */
+ if (buflen)
+ return gcry_error (GPG_ERR_INV_ARG);
+
+ a = secure? mpi_alloc_secure (0) : mpi_alloc(0);
+ if (mpi_fromstr (a, (const char *)buffer))
+ {
+ mpi_free (a);
+ return gcry_error (GPG_ERR_INV_OBJ);
+ }
+ if (ret_mpi)
+ {
+ mpi_normalize ( a );
+ *ret_mpi = a;
+ }
+ else
+ mpi_free(a);
+ return 0;
+ }
+ else
+ return gcry_error (GPG_ERR_INV_ARG);
+}
+
+
+/* Convert the big integer A into the external representation
+ described by FORMAT and store it in the provided BUFFER which has
+ been allocated by the user with a size of BUFLEN bytes. NWRITTEN
+ receives the actual length of the external representation unless it
+ has been passed as NULL. BUFFER may be NULL to query the required
+ length. */
+gcry_error_t
+gcry_mpi_print (enum gcry_mpi_format format,
+ unsigned char *buffer, size_t buflen,
+ size_t *nwritten, struct gcry_mpi *a)
+{
+ unsigned int nbits = mpi_get_nbits (a);
+ size_t len;
+ size_t dummy_nwritten;
+
+ if (!nwritten)
+ nwritten = &dummy_nwritten;
+
+ len = buflen;
+ *nwritten = 0;
+ if (format == GCRYMPI_FMT_STD)
+ {
+ unsigned char *tmp;
+ int extra = 0;
+ unsigned int n;
+
+ if (a->sign)
+ return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */
+
+ tmp = _gcry_mpi_get_buffer (a, &n, NULL);
+ if (!tmp)
+ return gpg_error_from_syserror ();
+ if (n && (*tmp & 0x80))
+ {
+ n++;
+ extra=1;
+ }
+
+ if (buffer && n > len)
+ {
+ /* The provided buffer is too short. */
+ gcry_free (tmp);
+ return gcry_error (GPG_ERR_TOO_SHORT);
+ }
+ if (buffer)
+ {
+ unsigned char *s = buffer;
+
+ if (extra)
+ *s++ = 0;
+ memcpy (s, tmp, n-extra);
+ }
+ gcry_free(tmp);
+ *nwritten = n;
+ return 0;
+ }
+ else if (format == GCRYMPI_FMT_USG)
+ {
+ unsigned int n = (nbits + 7)/8;
+
+ /* Note: We ignore the sign for this format. */
+ /* FIXME: for performance reasons we should put this into
+ mpi_aprint because we can then use the buffer directly. */
+ if (buffer && n > len)
+ return gcry_error (GPG_ERR_TOO_SHORT);
+ if (buffer)
+ {
+ unsigned char *tmp;
+
+ tmp = _gcry_mpi_get_buffer (a, &n, NULL);
+ if (!tmp)
+ return gpg_error_from_syserror ();
+ memcpy (buffer, tmp, n);
+ gcry_free (tmp);
+ }
+ *nwritten = n;
+ return 0;
+ }
+ else if (format == GCRYMPI_FMT_PGP)
+ {
+ unsigned int n = (nbits + 7)/8;
+
+ /* The PGP format can only handle unsigned integers. */
+ if( a->sign )
+ return gcry_error (GPG_ERR_INV_ARG);
+
+ if (buffer && n+2 > len)
+ return gcry_error (GPG_ERR_TOO_SHORT);
+
+ if (buffer)
+ {
+ unsigned char *tmp;
+ unsigned char *s = buffer;
+
+ s[0] = nbits >> 8;
+ s[1] = nbits;
+
+ tmp = _gcry_mpi_get_buffer (a, &n, NULL);
+ if (!tmp)
+ return gpg_error_from_syserror ();
+ memcpy (s+2, tmp, n);
+ gcry_free (tmp);
+ }
+ *nwritten = n+2;
+ return 0;
+ }
+ else if (format == GCRYMPI_FMT_SSH)
+ {
+ unsigned char *tmp;
+ int extra = 0;
+ unsigned int n;
+
+ if (a->sign)
+ return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */
+
+ tmp = _gcry_mpi_get_buffer (a, &n, NULL);
+ if (!tmp)
+ return gpg_error_from_syserror ();
+ if (n && (*tmp & 0x80))
+ {
+ n++;
+ extra=1;
+ }
+
+ if (buffer && n+4 > len)
+ {
+ gcry_free(tmp);
+ return gcry_error (GPG_ERR_TOO_SHORT);
+ }
+
+ if (buffer)
+ {
+ unsigned char *s = buffer;
+
+ *s++ = n >> 24;
+ *s++ = n >> 16;
+ *s++ = n >> 8;
+ *s++ = n;
+ if (extra)
+ *s++ = 0;
+
+ memcpy (s, tmp, n-extra);
+ }
+ gcry_free (tmp);
+ *nwritten = 4+n;
+ return 0;
+ }
+ else if (format == GCRYMPI_FMT_HEX)
+ {
+ unsigned char *tmp;
+ int i;
+ int extra = 0;
+ unsigned int n = 0;
+
+ tmp = _gcry_mpi_get_buffer (a, &n, NULL);
+ if (!tmp)
+ return gpg_error_from_syserror ();
+ if (!n || (*tmp & 0x80))
+ extra = 2;
+
+ if (buffer && 2*n + extra + !!a->sign + 1 > len)
+ {
+ gcry_free(tmp);
+ return gcry_error (GPG_ERR_TOO_SHORT);
+ }
+ if (buffer)
+ {
+ unsigned char *s = buffer;
+
+ if (a->sign)
+ *s++ = '-';
+ if (extra)
+ {
+ *s++ = '0';
+ *s++ = '0';
+ }
+
+ for (i=0; i < n; i++)
+ {
+ unsigned int c = tmp[i];
+
+ *s++ = (c >> 4) < 10? '0'+(c>>4) : 'A'+(c>>4)-10 ;
+ c &= 15;
+ *s++ = c < 10? '0'+c : 'A'+c-10 ;
+ }
+ *s++ = 0;
+ *nwritten = s - buffer;
+ }
+ else
+ {
+ *nwritten = 2*n + extra + !!a->sign + 1;
+ }
+ gcry_free (tmp);
+ return 0;
+ }
+ else
+ return gcry_error (GPG_ERR_INV_ARG);
+}
+
+
+/*
+ * Like gcry_mpi_print but this function allocates the buffer itself.
+ * The caller has to supply the address of a pointer. NWRITTEN may be
+ * NULL.
+ */
+gcry_error_t
+gcry_mpi_aprint (enum gcry_mpi_format format,
+ unsigned char **buffer, size_t *nwritten,
+ struct gcry_mpi *a)
+{
+ size_t n;
+ gcry_error_t rc;
+
+ *buffer = NULL;
+ rc = gcry_mpi_print (format, NULL, 0, &n, a);
+ if (rc)
+ return rc;
+
+ *buffer = mpi_is_secure(a) ? gcry_malloc_secure (n) : gcry_malloc (n);
+ if (!*buffer)
+ return gpg_error_from_syserror ();
+ rc = gcry_mpi_print( format, *buffer, n, &n, a );
+ if (rc)
+ {
+ gcry_free(*buffer);
+ *buffer = NULL;
+ }
+ else if (nwritten)
+ *nwritten = n;
+ return rc;
+}
+