diff options
author | Werner Koch <wk@gnupg.org> | 1997-11-18 15:06:00 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 1997-11-18 15:06:00 +0100 |
commit | 5393dd53c5e06f0458949217317601b2eaed8350 (patch) | |
tree | c4b8d021851c32a611165c5fc215ad88604b5a94 /mpi/mpicoder.c | |
parent | New repository initialized by cvs2svn. (diff) | |
download | gnupg2-5393dd53c5e06f0458949217317601b2eaed8350.tar.xz gnupg2-5393dd53c5e06f0458949217317601b2eaed8350.zip |
initially checkin
Diffstat (limited to 'mpi/mpicoder.c')
-rw-r--r-- | mpi/mpicoder.c | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/mpi/mpicoder.c b/mpi/mpicoder.c new file mode 100644 index 000000000..23454c0f9 --- /dev/null +++ b/mpi/mpicoder.c @@ -0,0 +1,392 @@ +/* mpicoder.c - Coder for the external representation of MPIs + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 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. + * + * G10 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include "mpi.h" +#include "iobuf.h" +#include "memory.h" +#include "util.h" + +#ifdef M_DEBUG + #undef mpi_decode + #undef mpi_decode_buffer +#endif + +#define MAX_EXTERN_MPI_BITS 16384 + +/**************** + * write an mpi to out. + */ +int +mpi_encode( IOBUF out, MPI a ) +{ + u16 dummy; + return mpi_encode_csum( out, a, &dummy ); +} + +int +mpi_encode_csum( IOBUF out, MPI a, u16 *csum ) +{ + int i; + byte c; + unsigned nbits = a->nlimbs * BITS_PER_MPI_LIMB; + mpi_limb_t limb; + +#if BYTES_PER_MPI_LIMB != 4 + #error Make this function work with other LIMB sizes +#endif + if( nbits > MAX_EXTERN_MPI_BITS ) + log_bug("mpi_encode: mpi too large (%u bits)\n", nbits); + iobuf_put(out, (c=nbits >>8) ); *csum += c; + iobuf_put(out, (c=nbits) ); *csum += c; + for(i=a->nlimbs-1; i >= 0; i-- ) { + limb = a->d[i]; + iobuf_put(out, (c=limb >> 24) ); *csum += c; + iobuf_put(out, (c=limb >> 16) ); *csum += c; + iobuf_put(out, (c=limb >> 8) ); *csum += c; + iobuf_put(out, (c=limb ) ); *csum += c; + } + return 0; +} + +/**************** + * encode the MPI into a newly allocated buffer, the buffer is + * so constructed, that it can be used for mpi_write. The caller + * must free the returned buffer. The buffer is allocated in the same + * type of memory space as A is. + */ +byte * +mpi_encode_buffer( MPI a ) +{ + abort(); + return NULL; +} + +/**************** + * write an mpi to out. This is a special function to handle + * encrypted values. It simply writes the buffer a to OUT. + * A is a special buffer, starting with 2 bytes giving it's length + * (in big endian order) and 2 bytes giving it's length in bits (also + * big endian) + */ +int +mpi_write( IOBUF out, byte *a) +{ + u16 dummy; + return mpi_write_csum( out, a, &dummy ); +} + +int +mpi_write_csum( IOBUF out, byte *a, u16 *csum) +{ + int rc; + unsigned n; + + n = *a++ << 8; + n |= *a++; + rc = iobuf_write(out, a, n ); + for( ; n; n--, a++ ) + *csum += *a; + return rc; +} + +/**************** + * Decode an external representation and return an MPI + * The external format is a 16 bit unsigned value stored in network byte order, + * giving the number of bits for the following integer. The integer is stored + * with MSB first (left padded with zeroes to align on a byte boundary). + */ +MPI +#ifdef M_DEBUG +mpi_debug_decode(IOBUF inp, unsigned *ret_nread, const char *info) +#else +mpi_decode(IOBUF inp, unsigned *ret_nread) +#endif +{ + int c, i, j; + unsigned nbits, nbytes, nlimbs, nread=0; + mpi_limb_t a; + MPI val = MPI_NULL; + + if( (c = iobuf_get(inp)) == -1 ) + goto leave; + nbits = c << 8; + if( (c = iobuf_get(inp)) == -1 ) + goto leave; + nbits |= c; + if( nbits > MAX_EXTERN_MPI_BITS ) { + log_error("mpi too large (%u bits)\n", nbits); + goto leave; + } + nread = 2; + + nbytes = (nbits+7) / 8; + nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB; + #ifdef M_DEBUG + val = mpi_debug_alloc( nlimbs, info ); + #else + val = mpi_alloc( nlimbs ); + #endif + 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++ ) { + a <<= 8; + a |= iobuf_get(inp) & 0xff; nread++; + } + i = 0; + val->d[j-1] = a; + } + + leave: + if( nread > *ret_nread ) + log_error("Ooops: mpi crosses packet border"); + else + *ret_nread = nread; + return val; +} + + +/**************** + * Decode an MPI from the buffer, the buffer starts with two bytes giving + * the length of the data to follow, the original data follows. + * The MPI is alloced from secure MPI space + */ +MPI +#ifdef M_DEBUG +mpi_debug_decode_buffer(byte *buffer, const char *info ) +#else +mpi_decode_buffer(byte *buffer ) +#endif +{ + int i, j; + u16 buflen; + unsigned nbits, nbytes, nlimbs; + mpi_limb_t a; + byte *p = buffer; + MPI val; + + if( !buffer ) + log_bug("mpi_decode_buffer: no buffer\n"); + buflen = *p++ << 8; + buflen |= *p++; + nbits = *p++ << 8; + nbits |= *p++; + nbytes = (nbits+7) / 8; + if( nbytes+2 != buflen ) + log_bug("mpi_decode_buffer: length conflict\n"); + nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB; + #ifdef M_DEBUG + val = mpi_debug_alloc_secure( nlimbs, info ); + #else + val = mpi_alloc_secure( nlimbs ); + #endif + 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++ ) { + a <<= 8; + a |= *p++; + } + i = 0; + val->d[j-1] = a; + } + return val; +} + + +/**************** + * Read a MPI from the external medium and return it in a newly allocated + * buffer (This buffer is allocated in the secure memory space, because + * we properly need this to decipher this string). + * Return: the allocated string and in RET_NREAD the number of bytes + * read (including the 2 length bytes), the returned buffer will + * be prefixed with two bytes describing the length of the following + * data. + */ +byte * +mpi_read(IOBUF inp, unsigned *ret_nread) +{ + int c; + u16 buflen; + unsigned nbits, nbytes, nread; + byte *p, *buf; + + if( (c = iobuf_get(inp)) == -1 ) + return NULL; + nbits = c << 8; + if( (c = iobuf_get(inp)) == -1 ) + return NULL; + nbits |= c; + if( nbits > MAX_EXTERN_MPI_BITS ) { + log_error("mpi too large (%u bits)\n", nbits); + return NULL; + } + nread = 2; + + nbytes = (nbits+7) / 8; + buflen = nbytes + 2; + p = buf = m_alloc_secure( buflen+2 ); + *p++ = buflen >> 8; + *p++ = buflen & 0xff; + *p++ = nbits >> 8; + *p++ = nbits & 0xff; + for( ; nbytes ; nbytes--, nread++ ) + *p++ = iobuf_get(inp) & 0xff; + + if( nread > *ret_nread ) + log_error("Ooops: mpi crosses packet border"); + else + *ret_nread = nread; + return buf; +} + + +/**************** + * Make a mpi from a character string. + */ +int +mpi_fromstr(MPI val, const char *str) +{ + int hexmode=0, sign=0, prepend_zero=0, i, j, c, c1, c2; + unsigned nbits, nbytes, nlimbs; + mpi_limb_t a; + + if( *str == '-' ) { + sign = 1; + str++; + } + if( *str == '0' && str[1] == 'x' ) + hexmode = 1; + else + return 1; /* other bases are not yet supported */ + str += 2; + + nbits = strlen(str)*4; + 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++; + assert(c1); + c2 = *str++; + assert(c2); + 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; + } + 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; + } + a <<= 8; + a |= c; + } + i = 0; + val->d[j-1] = a; + } + + return 0; +} + + +/**************** + * print an MPI to the give stream and return the number of characters + * printed. + */ +int +mpi_print( FILE *fp, MPI a, int mode ) +{ + int i, n=0; + + if( a == MPI_NULL ) + return fprintf(fp, "[MPI_NULL]"); + if( !mode ) + n += fprintf(fp, "[%d bits]", a->nlimbs * BITS_PER_MPI_LIMB ); + else { + if( a->sign ) + putc('-', fp); + for(i=a->nlimbs; i > 0 ; i-- ) { + n += fprintf(fp, i!=a->nlimbs? "%0" STR2(BYTES_PER_MPI_LIMB2) + "lX":"%lX", (unsigned long)a->d[i-1] ); + } + if( !a->nlimbs ) + putc('0', fp ); + } + return n; +} + + +/**************** + * Special function to get the low 8 bytes from a mpi, + * this can be used as a keyid, KEYID is an 2 element array. + * Does return the low 4 bytes. + */ +u32 +mpi_get_keyid( MPI a, u32 *keyid ) +{ +#if BYTES_PER_MPI_LIMB != 4 + #error Make this function work with other LIMB sizes +#endif + if( keyid ) { + keyid[0] = a->nlimbs >= 2? a->d[1] : 0; + keyid[1] = a->nlimbs >= 1? a->d[0] : 0; + } + return a->nlimbs >= 1? a->d[0] : 0; +} + + |