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 <linux/bitops.h> 22#include <asm-generic/bitops/count_zeros.h> 23#include "mpi-internal.h" 24 25#define MAX_EXTERN_MPI_BITS 16384 26 27/** 28 * mpi_read_raw_data - Read a raw byte stream as a positive integer 29 * @xbuffer: The data to read 30 * @nbytes: The amount of data to read 31 */ 32MPI mpi_read_raw_data(const void *xbuffer, size_t nbytes) 33{ 34 const uint8_t *buffer = xbuffer; 35 int i, j; 36 unsigned nbits, nlimbs; 37 mpi_limb_t a; 38 MPI val = NULL; 39 40 while (nbytes > 0 && buffer[0] == 0) { 41 buffer++; 42 nbytes--; 43 } 44 45 nbits = nbytes * 8; 46 if (nbits > MAX_EXTERN_MPI_BITS) { 47 pr_info("MPI: mpi too large (%u bits)\n", nbits); 48 return NULL; 49 } 50 if (nbytes > 0) 51 nbits -= count_leading_zeros(buffer[0]); 52 else 53 nbits = 0; 54 55 nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB); 56 val = mpi_alloc(nlimbs); 57 if (!val) 58 return NULL; 59 val->nbits = nbits; 60 val->sign = 0; 61 val->nlimbs = nlimbs; 62 63 if (nbytes > 0) { 64 i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; 65 i %= BYTES_PER_MPI_LIMB; 66 for (j = nlimbs; j > 0; j--) { 67 a = 0; 68 for (; i < BYTES_PER_MPI_LIMB; i++) { 69 a <<= 8; 70 a |= *buffer++; 71 } 72 i = 0; 73 val->d[j - 1] = a; 74 } 75 } 76 return val; 77} 78EXPORT_SYMBOL_GPL(mpi_read_raw_data); 79 80MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread) 81{ 82 const uint8_t *buffer = xbuffer; 83 int i, j; 84 unsigned nbits, nbytes, nlimbs, nread = 0; 85 mpi_limb_t a; 86 MPI val = NULL; 87 88 if (*ret_nread < 2) 89 goto leave; 90 nbits = buffer[0] << 8 | buffer[1]; 91 92 if (nbits > MAX_EXTERN_MPI_BITS) { 93 pr_info("MPI: mpi too large (%u bits)\n", nbits); 94 goto leave; 95 } 96 buffer += 2; 97 nread = 2; 98 99 nbytes = DIV_ROUND_UP(nbits, 8); 100 nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB); 101 val = mpi_alloc(nlimbs); 102 if (!val) 103 return NULL; 104 i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; 105 i %= BYTES_PER_MPI_LIMB; 106 val->nbits = nbits; 107 j = val->nlimbs = nlimbs; 108 val->sign = 0; 109 for (; j > 0; j--) { 110 a = 0; 111 for (; i < BYTES_PER_MPI_LIMB; i++) { 112 if (++nread > *ret_nread) { 113 printk 114 ("MPI: mpi larger than buffer nread=%d ret_nread=%d\n", 115 nread, *ret_nread); 116 goto leave; 117 } 118 a <<= 8; 119 a |= *buffer++; 120 } 121 i = 0; 122 val->d[j - 1] = a; 123 } 124 125leave: 126 *ret_nread = nread; 127 return val; 128} 129EXPORT_SYMBOL_GPL(mpi_read_from_buffer); 130 131/**************** 132 * Return an allocated buffer with the MPI (msb first). 133 * NBYTES receives the length of this buffer. Caller must free the 134 * return string (This function does return a 0 byte buffer with NBYTES 135 * set to zero if the value of A is zero. If sign is not NULL, it will 136 * be set to the sign of the A. 137 */ 138void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign) 139{ 140 uint8_t *p, *buffer; 141 mpi_limb_t alimb; 142 int i; 143 unsigned int n; 144 145 if (sign) 146 *sign = a->sign; 147 *nbytes = n = a->nlimbs * BYTES_PER_MPI_LIMB; 148 if (!n) 149 n++; /* avoid zero length allocation */ 150 p = buffer = kmalloc(n, GFP_KERNEL); 151 if (!p) 152 return NULL; 153 154 for (i = a->nlimbs - 1; i >= 0; i--) { 155 alimb = a->d[i]; 156#if BYTES_PER_MPI_LIMB == 4 157 *p++ = alimb >> 24; 158 *p++ = alimb >> 16; 159 *p++ = alimb >> 8; 160 *p++ = alimb; 161#elif BYTES_PER_MPI_LIMB == 8 162 *p++ = alimb >> 56; 163 *p++ = alimb >> 48; 164 *p++ = alimb >> 40; 165 *p++ = alimb >> 32; 166 *p++ = alimb >> 24; 167 *p++ = alimb >> 16; 168 *p++ = alimb >> 8; 169 *p++ = alimb; 170#else 171#error please implement for this limb size. 172#endif 173 } 174 175 /* this is sub-optimal but we need to do the shift operation 176 * because the caller has to free the returned buffer */ 177 for (p = buffer; !*p && *nbytes; p++, --*nbytes) 178 ; 179 if (p != buffer) 180 memmove(buffer, p, *nbytes); 181 182 return buffer; 183} 184EXPORT_SYMBOL_GPL(mpi_get_buffer); 185 186/**************** 187 * Use BUFFER to update MPI. 188 */ 189int mpi_set_buffer(MPI a, const void *xbuffer, unsigned nbytes, int sign) 190{ 191 const uint8_t *buffer = xbuffer, *p; 192 mpi_limb_t alimb; 193 int nlimbs; 194 int i; 195 196 nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB); 197 if (RESIZE_IF_NEEDED(a, nlimbs) < 0) 198 return -ENOMEM; 199 a->sign = sign; 200 201 for (i = 0, p = buffer + nbytes - 1; p >= buffer + BYTES_PER_MPI_LIMB;) { 202#if BYTES_PER_MPI_LIMB == 4 203 alimb = (mpi_limb_t) *p--; 204 alimb |= (mpi_limb_t) *p-- << 8; 205 alimb |= (mpi_limb_t) *p-- << 16; 206 alimb |= (mpi_limb_t) *p-- << 24; 207#elif BYTES_PER_MPI_LIMB == 8 208 alimb = (mpi_limb_t) *p--; 209 alimb |= (mpi_limb_t) *p-- << 8; 210 alimb |= (mpi_limb_t) *p-- << 16; 211 alimb |= (mpi_limb_t) *p-- << 24; 212 alimb |= (mpi_limb_t) *p-- << 32; 213 alimb |= (mpi_limb_t) *p-- << 40; 214 alimb |= (mpi_limb_t) *p-- << 48; 215 alimb |= (mpi_limb_t) *p-- << 56; 216#else 217#error please implement for this limb size. 218#endif 219 a->d[i++] = alimb; 220 } 221 if (p >= buffer) { 222#if BYTES_PER_MPI_LIMB == 4 223 alimb = *p--; 224 if (p >= buffer) 225 alimb |= (mpi_limb_t) *p-- << 8; 226 if (p >= buffer) 227 alimb |= (mpi_limb_t) *p-- << 16; 228 if (p >= buffer) 229 alimb |= (mpi_limb_t) *p-- << 24; 230#elif BYTES_PER_MPI_LIMB == 8 231 alimb = (mpi_limb_t) *p--; 232 if (p >= buffer) 233 alimb |= (mpi_limb_t) *p-- << 8; 234 if (p >= buffer) 235 alimb |= (mpi_limb_t) *p-- << 16; 236 if (p >= buffer) 237 alimb |= (mpi_limb_t) *p-- << 24; 238 if (p >= buffer) 239 alimb |= (mpi_limb_t) *p-- << 32; 240 if (p >= buffer) 241 alimb |= (mpi_limb_t) *p-- << 40; 242 if (p >= buffer) 243 alimb |= (mpi_limb_t) *p-- << 48; 244 if (p >= buffer) 245 alimb |= (mpi_limb_t) *p-- << 56; 246#else 247#error please implement for this limb size. 248#endif 249 a->d[i++] = alimb; 250 } 251 a->nlimbs = i; 252 253 if (i != nlimbs) { 254 pr_emerg("MPI: mpi_set_buffer: Assertion failed (%d != %d)", i, 255 nlimbs); 256 BUG(); 257 } 258 return 0; 259} 260EXPORT_SYMBOL_GPL(mpi_set_buffer); 261