at v4.2-rc2 7.2 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 <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 * mpi_read_buffer() - read MPI to a bufer provided by user (msb first) 133 * 134 * @a: a multi precision integer 135 * @buf: bufer to which the output will be written to. Needs to be at 136 * leaset mpi_get_size(a) long. 137 * @buf_len: size of the buf. 138 * @nbytes: receives the actual length of the data written. 139 * @sign: if not NULL, it will be set to the sign of a. 140 * 141 * Return: 0 on success or error code in case of error 142 */ 143int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes, 144 int *sign) 145{ 146 uint8_t *p; 147 mpi_limb_t alimb; 148 unsigned int n = mpi_get_size(a); 149 int i; 150 151 if (buf_len < n || !buf) 152 return -EINVAL; 153 154 if (sign) 155 *sign = a->sign; 156 157 if (nbytes) 158 *nbytes = n; 159 160 p = buf; 161 162 for (i = a->nlimbs - 1; i >= 0; i--) { 163 alimb = a->d[i]; 164#if BYTES_PER_MPI_LIMB == 4 165 *p++ = alimb >> 24; 166 *p++ = alimb >> 16; 167 *p++ = alimb >> 8; 168 *p++ = alimb; 169#elif BYTES_PER_MPI_LIMB == 8 170 *p++ = alimb >> 56; 171 *p++ = alimb >> 48; 172 *p++ = alimb >> 40; 173 *p++ = alimb >> 32; 174 *p++ = alimb >> 24; 175 *p++ = alimb >> 16; 176 *p++ = alimb >> 8; 177 *p++ = alimb; 178#else 179#error please implement for this limb size. 180#endif 181 } 182 return 0; 183} 184EXPORT_SYMBOL_GPL(mpi_read_buffer); 185 186/* 187 * mpi_get_buffer() - Returns an allocated buffer with the MPI (msb first). 188 * Caller must free the return string. 189 * This function does return a 0 byte buffer with nbytes set to zero if the 190 * value of A is zero. 191 * 192 * @a: a multi precision integer. 193 * @nbytes: receives the length of this buffer. 194 * @sign: if not NULL, it will be set to the sign of the a. 195 * 196 * Return: Pointer to MPI buffer or NULL on error 197 */ 198void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign) 199{ 200 uint8_t *buf, *p; 201 unsigned int n; 202 int ret; 203 204 if (!nbytes) 205 return NULL; 206 207 n = mpi_get_size(a); 208 209 if (!n) 210 n++; 211 212 buf = kmalloc(n, GFP_KERNEL); 213 214 if (!buf) 215 return NULL; 216 217 ret = mpi_read_buffer(a, buf, n, nbytes, sign); 218 219 if (ret) { 220 kfree(buf); 221 return NULL; 222 } 223 224 /* this is sub-optimal but we need to do the shift operation 225 * because the caller has to free the returned buffer */ 226 for (p = buf; !*p && *nbytes; p++, --*nbytes) 227 ; 228 if (p != buf) 229 memmove(buf, p, *nbytes); 230 231 return buf; 232} 233EXPORT_SYMBOL_GPL(mpi_get_buffer); 234 235/**************** 236 * Use BUFFER to update MPI. 237 */ 238int mpi_set_buffer(MPI a, const void *xbuffer, unsigned nbytes, int sign) 239{ 240 const uint8_t *buffer = xbuffer, *p; 241 mpi_limb_t alimb; 242 int nlimbs; 243 int i; 244 245 nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB); 246 if (RESIZE_IF_NEEDED(a, nlimbs) < 0) 247 return -ENOMEM; 248 a->sign = sign; 249 250 for (i = 0, p = buffer + nbytes - 1; p >= buffer + BYTES_PER_MPI_LIMB;) { 251#if BYTES_PER_MPI_LIMB == 4 252 alimb = (mpi_limb_t) *p--; 253 alimb |= (mpi_limb_t) *p-- << 8; 254 alimb |= (mpi_limb_t) *p-- << 16; 255 alimb |= (mpi_limb_t) *p-- << 24; 256#elif BYTES_PER_MPI_LIMB == 8 257 alimb = (mpi_limb_t) *p--; 258 alimb |= (mpi_limb_t) *p-- << 8; 259 alimb |= (mpi_limb_t) *p-- << 16; 260 alimb |= (mpi_limb_t) *p-- << 24; 261 alimb |= (mpi_limb_t) *p-- << 32; 262 alimb |= (mpi_limb_t) *p-- << 40; 263 alimb |= (mpi_limb_t) *p-- << 48; 264 alimb |= (mpi_limb_t) *p-- << 56; 265#else 266#error please implement for this limb size. 267#endif 268 a->d[i++] = alimb; 269 } 270 if (p >= buffer) { 271#if BYTES_PER_MPI_LIMB == 4 272 alimb = *p--; 273 if (p >= buffer) 274 alimb |= (mpi_limb_t) *p-- << 8; 275 if (p >= buffer) 276 alimb |= (mpi_limb_t) *p-- << 16; 277 if (p >= buffer) 278 alimb |= (mpi_limb_t) *p-- << 24; 279#elif BYTES_PER_MPI_LIMB == 8 280 alimb = (mpi_limb_t) *p--; 281 if (p >= buffer) 282 alimb |= (mpi_limb_t) *p-- << 8; 283 if (p >= buffer) 284 alimb |= (mpi_limb_t) *p-- << 16; 285 if (p >= buffer) 286 alimb |= (mpi_limb_t) *p-- << 24; 287 if (p >= buffer) 288 alimb |= (mpi_limb_t) *p-- << 32; 289 if (p >= buffer) 290 alimb |= (mpi_limb_t) *p-- << 40; 291 if (p >= buffer) 292 alimb |= (mpi_limb_t) *p-- << 48; 293 if (p >= buffer) 294 alimb |= (mpi_limb_t) *p-- << 56; 295#else 296#error please implement for this limb size. 297#endif 298 a->d[i++] = alimb; 299 } 300 a->nlimbs = i; 301 302 if (i != nlimbs) { 303 pr_emerg("MPI: mpi_set_buffer: Assertion failed (%d != %d)", i, 304 nlimbs); 305 BUG(); 306 } 307 return 0; 308} 309EXPORT_SYMBOL_GPL(mpi_set_buffer);