1
/* mpicoder.c - Coder for the external representation of MPIs
2
* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
4
* This file is part of Libgcrypt.
6
* Libgcrypt is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU Lesser General Public License as
8
* published by the Free Software Foundation; either version 2.1 of
9
* the License, or (at your option) any later version.
11
* Libgcrypt is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU Lesser General Public License for more details.
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
27
#include "kernel-interface.h"
29
#define MAX_EXTERN_MPI_BITS 16384
34
mpi_read_from_buffer(byte *buffer, unsigned *ret_nread, int secure)
37
unsigned int nbits, nbytes, nlimbs, nread=0;
43
nbits = buffer[0] << 8 | buffer[1];
44
if( nbits > MAX_EXTERN_MPI_BITS ) {
45
log_error("mpi too large (%u bits)\n", nbits);
49
log_error("an mpi of size 0 is not allowed\n");
55
nbytes = (nbits+7) / 8;
56
nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
57
val = secure? mpi_alloc_secure( nlimbs )
58
: mpi_alloc( nlimbs );
59
i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
60
i %= BYTES_PER_MPI_LIMB;
61
j= val->nlimbs = nlimbs;
65
for(; i < BYTES_PER_MPI_LIMB; i++ ) {
66
if( ++nread > *ret_nread )
67
log_bug("mpi larger than buffer");
82
* Make an mpi from a hex character string.
85
mpi_fromstr(MPI val, const char *str)
87
int sign=0, prepend_zero=0, i, j, c, c1, c2;
88
unsigned nbits, nbytes, nlimbs;
96
/* skip optional hex prefix */
97
if ( *str == '0' && str[1] == 'x' ) {
101
nbits = strlen(str)*4;
104
nbytes = (nbits+7) / 8;
105
nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
106
if( val->alloced < nlimbs )
107
mpi_resize(val, nlimbs );
108
i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
109
i %= BYTES_PER_MPI_LIMB;
110
j= val->nlimbs = nlimbs;
112
for( ; j > 0; j-- ) {
114
for(; i < BYTES_PER_MPI_LIMB; i++ ) {
124
if( c1 >= '0' && c1 <= '9' )
126
else if( c1 >= 'a' && c1 <= 'f' )
128
else if( c1 >= 'A' && c1 <= 'F' )
135
if( c2 >= '0' && c2 <= '9' )
137
else if( c2 >= 'a' && c2 <= 'f' )
139
else if( c2 >= 'A' && c2 <= 'F' )
157
* print an MPI to the given stream and return the number of characters
159
* FIXME: Replace this by the more generic gcry_mpi_print()
163
mpi_print( FILE *fp, MPI a, int mode )
168
return fprintf(fp, "[MPI_NULL]");
171
n1 = mpi_get_nbits(a);
172
n += fprintf(fp, "[%u bits]", n1);
177
#if BYTES_PER_MPI_LIMB == 2
179
#elif BYTES_PER_MPI_LIMB == 4
181
#elif BYTES_PER_MPI_LIMB == 8
184
#error please define the format here
186
for(i=a->nlimbs; i > 0 ; i-- ) {
187
n += fprintf(fp, i!=a->nlimbs? "%0" X "lX":"%lX", (ulong)a->d[i-1]);
199
#warning We should move this function to elsewhere
202
_gcry_log_mpidump( const char *text, MPI a )
204
FILE *fp = stderr; /* used to be log_stream() */
206
/* FIXME: Replace this function by a g10_log_xxx one */
207
fprintf(fp,"%s: ",text);
208
mpi_print(fp, a, 1 );
215
* Return an m_alloced buffer with the MPI (msb first).
216
* NBYTES receives the length of this buffer. Caller must free the
217
* return string (This function does return a 0 byte buffer with NBYTES
218
* set to zero if the value of A is zero. If sign is not NULL, it will
219
* be set to the sign of the A.
222
do_get_buffer( MPI a, unsigned *nbytes, int *sign, int force_secure )
231
*nbytes = a->nlimbs * BYTES_PER_MPI_LIMB;
232
n = *nbytes? *nbytes:1; /* allocate at least one byte */
233
p = buffer = force_secure || mpi_is_secure(a) ? gcry_xmalloc_secure(n)
236
for(i=a->nlimbs-1; i >= 0; i-- ) {
238
#if BYTES_PER_MPI_LIMB == 4
243
#elif BYTES_PER_MPI_LIMB == 8
253
#error please implement for this limb size.
257
/* this is sub-optimal but we need to do the shift oepration because
258
* the caller has to free the returned buffer */
259
for(p=buffer; !*p && *nbytes; p++, --*nbytes )
262
memmove(buffer,p, *nbytes);
268
_gcry_mpi_get_buffer( MPI a, unsigned *nbytes, int *sign )
270
return do_get_buffer( a, nbytes, sign, 0 );
274
_gcry_mpi_get_secure_buffer( MPI a, unsigned *nbytes, int *sign )
276
return do_get_buffer( a, nbytes, sign, 1 );
280
* Use BUFFER to update MPI.
283
_gcry_mpi_set_buffer( MPI a, const byte *buffer, unsigned nbytes, int sign )
290
nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
291
RESIZE_IF_NEEDED(a, nlimbs);
294
for(i=0, p = buffer+nbytes-1; p >= buffer+BYTES_PER_MPI_LIMB; ) {
295
#if BYTES_PER_MPI_LIMB == 4
298
alimb |= *p-- << 16 ;
299
alimb |= *p-- << 24 ;
300
#elif BYTES_PER_MPI_LIMB == 8
301
alimb = (mpi_limb_t)*p-- ;
302
alimb |= (mpi_limb_t)*p-- << 8 ;
303
alimb |= (mpi_limb_t)*p-- << 16 ;
304
alimb |= (mpi_limb_t)*p-- << 24 ;
305
alimb |= (mpi_limb_t)*p-- << 32 ;
306
alimb |= (mpi_limb_t)*p-- << 40 ;
307
alimb |= (mpi_limb_t)*p-- << 48 ;
308
alimb |= (mpi_limb_t)*p-- << 56 ;
310
#error please implement for this limb size.
315
#if BYTES_PER_MPI_LIMB == 4
317
if( p >= buffer ) alimb |= *p-- << 8 ;
318
if( p >= buffer ) alimb |= *p-- << 16 ;
319
if( p >= buffer ) alimb |= *p-- << 24 ;
320
#elif BYTES_PER_MPI_LIMB == 8
321
alimb = (mpi_limb_t)*p-- ;
322
if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 8 ;
323
if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 16 ;
324
if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 24 ;
325
if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 32 ;
326
if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 40 ;
327
if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 48 ;
328
if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 56 ;
330
#error please implement for this limb size.
335
// assert( i == nlimbs );
341
gcry_mpi_scan( struct gcry_mpi **ret_mpi, enum gcry_mpi_format format,
342
const char *buffer, size_t *nbytes )
344
struct gcry_mpi *a = NULL;
348
len = nbytes? *nbytes : (format == GCRYMPI_FMT_SSH? 0 : strlen(buffer));
351
/* TODO: add a way to allocate the MPI in secure memory
352
* Hmmm: maybe it is better to retrieve this information from
353
* the provided buffer. */
355
#warning secure memory is not used here.
358
if( format == GCRYMPI_FMT_STD ) {
359
const byte *s = buffer;
361
a = mpi_alloc( (len+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB );
362
if( len ) { /* not zero */
365
/* FIXME: we have to convert from 2compl to magnitude format */
367
return GCRYERR_INTERNAL;
370
_gcry_mpi_set_buffer( a, s, len, 0 );
381
else if( format == GCRYMPI_FMT_USG ) {
382
a = mpi_alloc( (len+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB );
383
if( len ) /* not zero */
384
_gcry_mpi_set_buffer( a, buffer, len, 0 );
394
else if( format == GCRYMPI_FMT_PGP ) {
395
a = mpi_read_from_buffer( (char*)buffer, &len, 0 );
404
return a? 0 : GCRYERR_INV_OBJ;
406
else if( format == GCRYMPI_FMT_SSH ) {
407
const byte *s = buffer;
411
return GCRYERR_TOO_SHORT;
412
n = s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3];
417
return GCRYERR_TOO_LARGE; /* or should it be too_short */
419
a = mpi_alloc( (n+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB );
420
if( n ) { /* not zero */
423
/* FIXME: we have to convert from 2compl to magnitude format */
425
return GCRYERR_INTERNAL;
428
_gcry_mpi_set_buffer( a, s, n, 0 );
441
else if( format == GCRYMPI_FMT_HEX ) {
443
return GCRYERR_INV_ARG; /* can only handle C strings for now */
445
if( mpi_fromstr( a, buffer ) )
446
return GCRYERR_INV_OBJ;
456
return GCRYERR_INV_ARG;
460
* Write A using FORMAT into buffer which has a length of *NBYTES.
461
* Returns the number of bytes actually written in nbytes.
462
* Buffer maybe NULL to query the required length of the buffer
465
gcry_mpi_print( enum gcry_mpi_format format, char *buffer, size_t *nbytes,
468
unsigned int nbits = mpi_get_nbits(a);
472
return GCRYERR_INV_ARG;
476
if( format == GCRYMPI_FMT_STD ) {
482
return GCRYERR_INTERNAL; /* can't handle it yet */
484
tmp = _gcry_mpi_get_buffer( a, &n, NULL );
485
if( n && (*tmp & 0x80) ) {
490
if( n > len && buffer ) {
492
return GCRYERR_TOO_SHORT; /* the provided buffer is too short */
499
memcpy( s, tmp, n-extra );
505
else if( format == GCRYMPI_FMT_USG ) {
506
unsigned int n = (nbits + 7)/8;
508
/* we ignore the sign for this format */
509
/* FIXME: for performance reasons we should put this into
510
* mpi_aprint becuase we can then use the buffer directly */
511
if( n > len && buffer )
512
return GCRYERR_TOO_SHORT; /* the provided buffer is too short */
515
tmp = _gcry_mpi_get_buffer( a, &n, NULL );
516
memcpy( buffer, tmp, n );
523
else if( format == GCRYMPI_FMT_PGP ) {
524
unsigned int n = (nbits + 7)/8;
527
return GCRYERR_INV_ARG; /* pgp format can only handle unsigned */
529
if( n+2 > len && buffer )
530
return GCRYERR_TOO_SHORT; /* the provided buffer is too short */
537
tmp = _gcry_mpi_get_buffer( a, &n, NULL );
538
memcpy( s+2, tmp, n );
544
else if( format == GCRYMPI_FMT_SSH ) {
550
return GCRYERR_INTERNAL; /* can't handle it yet */
552
tmp = _gcry_mpi_get_buffer( a, &n, NULL );
553
if( n && (*tmp & 0x80) ) {
558
if( n+4 > len && buffer ) {
560
return GCRYERR_TOO_SHORT; /* the provided buffer is too short */
571
memcpy( s, tmp, n-extra );
577
else if( format == GCRYMPI_FMT_HEX ) {
583
tmp = _gcry_mpi_get_buffer( a, &n, NULL );
584
if( !n || (*tmp & 0x80) )
587
if( 2*n + extra + !!a->sign + 1 > len && buffer ) {
589
return GCRYERR_TOO_SHORT; /* the provided buffer is too short */
600
for(i=0; i < n; i++ ) {
601
unsigned int c = tmp[i];
602
*s++ = (c >> 4) < 10? '0'+(c>>4) : 'A'+(c>>4)-10 ;
604
*s++ = c < 10? '0'+c : 'A'+c-10 ;
607
*nbytes = (char*)s - buffer;
610
*nbytes = 2*n + extra + !!a->sign + 1;
617
return GCRYERR_INV_ARG;
621
* Like gcry_mpi_print but this function allocates the buffer itself.
622
* The caller has to supply the address of a pointer. nbytes may be
626
gcry_mpi_aprint( enum gcry_mpi_format format, void **buffer, size_t *nbytes,
633
rc = gcry_mpi_print( format, NULL, &n, a );
636
*buffer = mpi_is_secure(a) ? gcry_xmalloc_secure( n ) : gcry_xmalloc( n );
637
rc = gcry_mpi_print( format, *buffer, &n, a );