at v3.6 5.3 kB view raw
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 * Return an allocated buffer with the MPI (msb first). 78 * NBYTES receives the length of this buffer. Caller must free the 79 * return string (This function does return a 0 byte buffer with NBYTES 80 * set to zero if the value of A is zero. If sign is not NULL, it will 81 * be set to the sign of the A. 82 */ 83void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign) 84{ 85 uint8_t *p, *buffer; 86 mpi_limb_t alimb; 87 int i; 88 unsigned int n; 89 90 if (sign) 91 *sign = a->sign; 92 *nbytes = n = a->nlimbs * BYTES_PER_MPI_LIMB; 93 if (!n) 94 n++; /* avoid zero length allocation */ 95 p = buffer = kmalloc(n, GFP_KERNEL); 96 if (!p) 97 return NULL; 98 99 for (i = a->nlimbs - 1; i >= 0; i--) { 100 alimb = a->d[i]; 101#if BYTES_PER_MPI_LIMB == 4 102 *p++ = alimb >> 24; 103 *p++ = alimb >> 16; 104 *p++ = alimb >> 8; 105 *p++ = alimb; 106#elif BYTES_PER_MPI_LIMB == 8 107 *p++ = alimb >> 56; 108 *p++ = alimb >> 48; 109 *p++ = alimb >> 40; 110 *p++ = alimb >> 32; 111 *p++ = alimb >> 24; 112 *p++ = alimb >> 16; 113 *p++ = alimb >> 8; 114 *p++ = alimb; 115#else 116#error please implement for this limb size. 117#endif 118 } 119 120 /* this is sub-optimal but we need to do the shift operation 121 * because the caller has to free the returned buffer */ 122 for (p = buffer; !*p && *nbytes; p++, --*nbytes) 123 ; 124 if (p != buffer) 125 memmove(buffer, p, *nbytes); 126 127 return buffer; 128} 129EXPORT_SYMBOL_GPL(mpi_get_buffer); 130 131/**************** 132 * Use BUFFER to update MPI. 133 */ 134int mpi_set_buffer(MPI a, const void *xbuffer, unsigned nbytes, int sign) 135{ 136 const uint8_t *buffer = xbuffer, *p; 137 mpi_limb_t alimb; 138 int nlimbs; 139 int i; 140 141 nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB; 142 if (RESIZE_IF_NEEDED(a, nlimbs) < 0) 143 return -ENOMEM; 144 a->sign = sign; 145 146 for (i = 0, p = buffer + nbytes - 1; p >= buffer + BYTES_PER_MPI_LIMB;) { 147#if BYTES_PER_MPI_LIMB == 4 148 alimb = (mpi_limb_t) *p--; 149 alimb |= (mpi_limb_t) *p-- << 8; 150 alimb |= (mpi_limb_t) *p-- << 16; 151 alimb |= (mpi_limb_t) *p-- << 24; 152#elif BYTES_PER_MPI_LIMB == 8 153 alimb = (mpi_limb_t) *p--; 154 alimb |= (mpi_limb_t) *p-- << 8; 155 alimb |= (mpi_limb_t) *p-- << 16; 156 alimb |= (mpi_limb_t) *p-- << 24; 157 alimb |= (mpi_limb_t) *p-- << 32; 158 alimb |= (mpi_limb_t) *p-- << 40; 159 alimb |= (mpi_limb_t) *p-- << 48; 160 alimb |= (mpi_limb_t) *p-- << 56; 161#else 162#error please implement for this limb size. 163#endif 164 a->d[i++] = alimb; 165 } 166 if (p >= buffer) { 167#if BYTES_PER_MPI_LIMB == 4 168 alimb = *p--; 169 if (p >= buffer) 170 alimb |= (mpi_limb_t) *p-- << 8; 171 if (p >= buffer) 172 alimb |= (mpi_limb_t) *p-- << 16; 173 if (p >= buffer) 174 alimb |= (mpi_limb_t) *p-- << 24; 175#elif BYTES_PER_MPI_LIMB == 8 176 alimb = (mpi_limb_t) *p--; 177 if (p >= buffer) 178 alimb |= (mpi_limb_t) *p-- << 8; 179 if (p >= buffer) 180 alimb |= (mpi_limb_t) *p-- << 16; 181 if (p >= buffer) 182 alimb |= (mpi_limb_t) *p-- << 24; 183 if (p >= buffer) 184 alimb |= (mpi_limb_t) *p-- << 32; 185 if (p >= buffer) 186 alimb |= (mpi_limb_t) *p-- << 40; 187 if (p >= buffer) 188 alimb |= (mpi_limb_t) *p-- << 48; 189 if (p >= buffer) 190 alimb |= (mpi_limb_t) *p-- << 56; 191#else 192#error please implement for this limb size. 193#endif 194 a->d[i++] = alimb; 195 } 196 a->nlimbs = i; 197 198 if (i != nlimbs) { 199 pr_emerg("MPI: mpi_set_buffer: Assertion failed (%d != %d)", i, 200 nlimbs); 201 BUG(); 202 } 203 return 0; 204} 205EXPORT_SYMBOL_GPL(mpi_set_buffer);