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