linux/lib/mpi/mpicoder.c
<<
>>
Prefs
   1/* mpicoder.c  -  Coder for the external representation of MPIs
   2 * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
   3 *
   4 * This file is part of GnuPG.
   5 *
   6 * GnuPG is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * GnuPG 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 General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, write to the Free Software
  18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  19 */
  20
  21#include "mpi-internal.h"
  22
  23#define MAX_EXTERN_MPI_BITS 16384
  24
  25MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread)
  26{
  27        const uint8_t *buffer = xbuffer;
  28        int i, j;
  29        unsigned nbits, nbytes, nlimbs, nread = 0;
  30        mpi_limb_t a;
  31        MPI val = NULL;
  32
  33        if (*ret_nread < 2)
  34                goto leave;
  35        nbits = buffer[0] << 8 | buffer[1];
  36
  37        if (nbits > MAX_EXTERN_MPI_BITS) {
  38                pr_info("MPI: mpi too large (%u bits)\n", nbits);
  39                goto leave;
  40        }
  41        buffer += 2;
  42        nread = 2;
  43
  44        nbytes = (nbits + 7) / 8;
  45        nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
  46        val = mpi_alloc(nlimbs);
  47        if (!val)
  48                return NULL;
  49        i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
  50        i %= BYTES_PER_MPI_LIMB;
  51        val->nbits = nbits;
  52        j = val->nlimbs = nlimbs;
  53        val->sign = 0;
  54        for (; j > 0; j--) {
  55                a = 0;
  56                for (; i < BYTES_PER_MPI_LIMB; i++) {
  57                        if (++nread > *ret_nread) {
  58                                printk
  59                                    ("MPI: mpi larger than buffer nread=%d ret_nread=%d\n",
  60                                     nread, *ret_nread);
  61                                goto leave;
  62                        }
  63                        a <<= 8;
  64                        a |= *buffer++;
  65                }
  66                i = 0;
  67                val->d[j - 1] = a;
  68        }
  69
  70leave:
  71        *ret_nread = nread;
  72        return val;
  73}
  74EXPORT_SYMBOL_GPL(mpi_read_from_buffer);
  75
  76/****************
  77 * Make an mpi from a character string.
  78 */
  79int mpi_fromstr(MPI val, const char *str)
  80{
  81        int hexmode = 0, sign = 0, prepend_zero = 0, i, j, c, c1, c2;
  82        unsigned nbits, nbytes, nlimbs;
  83        mpi_limb_t a;
  84
  85        if (*str == '-') {
  86                sign = 1;
  87                str++;
  88        }
  89        if (*str == '0' && str[1] == 'x')
  90                hexmode = 1;
  91        else
  92                return -EINVAL; /* other bases are not yet supported */
  93        str += 2;
  94
  95        nbits = strlen(str) * 4;
  96        if (nbits % 8)
  97                prepend_zero = 1;
  98        nbytes = (nbits + 7) / 8;
  99        nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
 100        if (val->alloced < nlimbs)
 101                if (!mpi_resize(val, nlimbs))
 102                        return -ENOMEM;
 103        i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
 104        i %= BYTES_PER_MPI_LIMB;
 105        j = val->nlimbs = nlimbs;
 106        val->sign = sign;
 107        for (; j > 0; j--) {
 108                a = 0;
 109                for (; i < BYTES_PER_MPI_LIMB; i++) {
 110                        if (prepend_zero) {
 111                                c1 = '0';
 112                                prepend_zero = 0;
 113                        } else
 114                                c1 = *str++;
 115                        assert(c1);
 116                        c2 = *str++;
 117                        assert(c2);
 118                        if (c1 >= '0' && c1 <= '9')
 119                                c = c1 - '0';
 120                        else if (c1 >= 'a' && c1 <= 'f')
 121                                c = c1 - 'a' + 10;
 122                        else if (c1 >= 'A' && c1 <= 'F')
 123                                c = c1 - 'A' + 10;
 124                        else {
 125                                mpi_clear(val);
 126                                return 1;
 127                        }
 128                        c <<= 4;
 129                        if (c2 >= '0' && c2 <= '9')
 130                                c |= c2 - '0';
 131                        else if (c2 >= 'a' && c2 <= 'f')
 132                                c |= c2 - 'a' + 10;
 133                        else if (c2 >= 'A' && c2 <= 'F')
 134                                c |= c2 - 'A' + 10;
 135                        else {
 136                                mpi_clear(val);
 137                                return 1;
 138                        }
 139                        a <<= 8;
 140                        a |= c;
 141                }
 142                i = 0;
 143
 144                val->d[j - 1] = a;
 145        }
 146
 147        return 0;
 148}
 149EXPORT_SYMBOL_GPL(mpi_fromstr);
 150
 151/****************
 152 * Return an allocated buffer with the MPI (msb first).
 153 * NBYTES receives the length of this buffer. Caller must free the
 154 * return string (This function does return a 0 byte buffer with NBYTES
 155 * set to zero if the value of A is zero. If sign is not NULL, it will
 156 * be set to the sign of the A.
 157 */
 158void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign)
 159{
 160        uint8_t *p, *buffer;
 161        mpi_limb_t alimb;
 162        int i;
 163        unsigned int n;
 164
 165        if (sign)
 166                *sign = a->sign;
 167        *nbytes = n = a->nlimbs * BYTES_PER_MPI_LIMB;
 168        if (!n)
 169                n++;            /* avoid zero length allocation */
 170        p = buffer = kmalloc(n, GFP_KERNEL);
 171        if (!p)
 172                return NULL;
 173
 174        for (i = a->nlimbs - 1; i >= 0; i--) {
 175                alimb = a->d[i];
 176#if BYTES_PER_MPI_LIMB == 4
 177                *p++ = alimb >> 24;
 178                *p++ = alimb >> 16;
 179                *p++ = alimb >> 8;
 180                *p++ = alimb;
 181#elif BYTES_PER_MPI_LIMB == 8
 182                *p++ = alimb >> 56;
 183                *p++ = alimb >> 48;
 184                *p++ = alimb >> 40;
 185                *p++ = alimb >> 32;
 186                *p++ = alimb >> 24;
 187                *p++ = alimb >> 16;
 188                *p++ = alimb >> 8;
 189                *p++ = alimb;
 190#else
 191#error please implement for this limb size.
 192#endif
 193        }
 194
 195        /* this is sub-optimal but we need to do the shift operation
 196         * because the caller has to free the returned buffer */
 197        for (p = buffer; !*p && *nbytes; p++, --*nbytes)
 198                ;
 199        if (p != buffer)
 200                memmove(buffer, p, *nbytes);
 201
 202        return buffer;
 203}
 204EXPORT_SYMBOL_GPL(mpi_get_buffer);
 205
 206/****************
 207 * Use BUFFER to update MPI.
 208 */
 209int mpi_set_buffer(MPI a, const void *xbuffer, unsigned nbytes, int sign)
 210{
 211        const uint8_t *buffer = xbuffer, *p;
 212        mpi_limb_t alimb;
 213        int nlimbs;
 214        int i;
 215
 216        nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
 217        if (RESIZE_IF_NEEDED(a, nlimbs) < 0)
 218                return -ENOMEM;
 219        a->sign = sign;
 220
 221        for (i = 0, p = buffer + nbytes - 1; p >= buffer + BYTES_PER_MPI_LIMB;) {
 222#if BYTES_PER_MPI_LIMB == 4
 223                alimb = (mpi_limb_t) *p--;
 224                alimb |= (mpi_limb_t) *p-- << 8;
 225                alimb |= (mpi_limb_t) *p-- << 16;
 226                alimb |= (mpi_limb_t) *p-- << 24;
 227#elif BYTES_PER_MPI_LIMB == 8
 228                alimb = (mpi_limb_t) *p--;
 229                alimb |= (mpi_limb_t) *p-- << 8;
 230                alimb |= (mpi_limb_t) *p-- << 16;
 231                alimb |= (mpi_limb_t) *p-- << 24;
 232                alimb |= (mpi_limb_t) *p-- << 32;
 233                alimb |= (mpi_limb_t) *p-- << 40;
 234                alimb |= (mpi_limb_t) *p-- << 48;
 235                alimb |= (mpi_limb_t) *p-- << 56;
 236#else
 237#error please implement for this limb size.
 238#endif
 239                a->d[i++] = alimb;
 240        }
 241        if (p >= buffer) {
 242#if BYTES_PER_MPI_LIMB == 4
 243                alimb = *p--;
 244                if (p >= buffer)
 245                        alimb |= (mpi_limb_t) *p-- << 8;
 246                if (p >= buffer)
 247                        alimb |= (mpi_limb_t) *p-- << 16;
 248                if (p >= buffer)
 249                        alimb |= (mpi_limb_t) *p-- << 24;
 250#elif BYTES_PER_MPI_LIMB == 8
 251                alimb = (mpi_limb_t) *p--;
 252                if (p >= buffer)
 253                        alimb |= (mpi_limb_t) *p-- << 8;
 254                if (p >= buffer)
 255                        alimb |= (mpi_limb_t) *p-- << 16;
 256                if (p >= buffer)
 257                        alimb |= (mpi_limb_t) *p-- << 24;
 258                if (p >= buffer)
 259                        alimb |= (mpi_limb_t) *p-- << 32;
 260                if (p >= buffer)
 261                        alimb |= (mpi_limb_t) *p-- << 40;
 262                if (p >= buffer)
 263                        alimb |= (mpi_limb_t) *p-- << 48;
 264                if (p >= buffer)
 265                        alimb |= (mpi_limb_t) *p-- << 56;
 266#else
 267#error please implement for this limb size.
 268#endif
 269                a->d[i++] = alimb;
 270        }
 271        a->nlimbs = i;
 272
 273        if (i != nlimbs) {
 274                pr_emerg("MPI: mpi_set_buffer: Assertion failed (%d != %d)", i,
 275                       nlimbs);
 276                BUG();
 277        }
 278        return 0;
 279}
 280EXPORT_SYMBOL_GPL(mpi_set_buffer);
 281