2011-08-31 19:05:16 +08:00
|
|
|
/* mpicoder.c - Coder for the external representation of MPIs
|
|
|
|
* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
|
|
|
|
*
|
|
|
|
* This file is part of GnuPG.
|
|
|
|
*
|
|
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* GnuPG is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
*/
|
|
|
|
|
2012-09-25 00:11:27 +08:00
|
|
|
#include <linux/bitops.h>
|
2015-08-28 15:27:15 +08:00
|
|
|
#include <linux/count_zeros.h>
|
2016-03-22 20:12:39 +08:00
|
|
|
#include <linux/byteorder/generic.h>
|
2016-03-22 20:12:41 +08:00
|
|
|
#include <linux/string.h>
|
2011-08-31 19:05:16 +08:00
|
|
|
#include "mpi-internal.h"
|
|
|
|
|
|
|
|
#define MAX_EXTERN_MPI_BITS 16384
|
|
|
|
|
2012-09-25 00:11:27 +08:00
|
|
|
/**
|
|
|
|
* mpi_read_raw_data - Read a raw byte stream as a positive integer
|
|
|
|
* @xbuffer: The data to read
|
|
|
|
* @nbytes: The amount of data to read
|
|
|
|
*/
|
|
|
|
MPI mpi_read_raw_data(const void *xbuffer, size_t nbytes)
|
|
|
|
{
|
|
|
|
const uint8_t *buffer = xbuffer;
|
|
|
|
int i, j;
|
|
|
|
unsigned nbits, nlimbs;
|
|
|
|
mpi_limb_t a;
|
|
|
|
MPI val = NULL;
|
|
|
|
|
2013-06-13 05:04:40 +08:00
|
|
|
while (nbytes > 0 && buffer[0] == 0) {
|
2012-09-25 00:11:27 +08:00
|
|
|
buffer++;
|
|
|
|
nbytes--;
|
|
|
|
}
|
|
|
|
|
|
|
|
nbits = nbytes * 8;
|
|
|
|
if (nbits > MAX_EXTERN_MPI_BITS) {
|
|
|
|
pr_info("MPI: mpi too large (%u bits)\n", nbits);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (nbytes > 0)
|
|
|
|
nbits -= count_leading_zeros(buffer[0]);
|
|
|
|
else
|
|
|
|
nbits = 0;
|
|
|
|
|
2013-01-30 17:30:06 +08:00
|
|
|
nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB);
|
2012-09-25 00:11:27 +08:00
|
|
|
val = mpi_alloc(nlimbs);
|
|
|
|
if (!val)
|
|
|
|
return NULL;
|
|
|
|
val->nbits = nbits;
|
|
|
|
val->sign = 0;
|
|
|
|
val->nlimbs = nlimbs;
|
|
|
|
|
|
|
|
if (nbytes > 0) {
|
|
|
|
i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
|
|
|
|
i %= BYTES_PER_MPI_LIMB;
|
|
|
|
for (j = nlimbs; j > 0; j--) {
|
|
|
|
a = 0;
|
|
|
|
for (; i < BYTES_PER_MPI_LIMB; i++) {
|
|
|
|
a <<= 8;
|
|
|
|
a |= *buffer++;
|
|
|
|
}
|
|
|
|
i = 0;
|
|
|
|
val->d[j - 1] = a;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mpi_read_raw_data);
|
|
|
|
|
2011-08-31 19:05:16 +08:00
|
|
|
MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread)
|
|
|
|
{
|
|
|
|
const uint8_t *buffer = xbuffer;
|
|
|
|
int i, j;
|
|
|
|
unsigned nbits, nbytes, nlimbs, nread = 0;
|
|
|
|
mpi_limb_t a;
|
2012-01-27 01:13:16 +08:00
|
|
|
MPI val = NULL;
|
2011-08-31 19:05:16 +08:00
|
|
|
|
|
|
|
if (*ret_nread < 2)
|
|
|
|
goto leave;
|
|
|
|
nbits = buffer[0] << 8 | buffer[1];
|
|
|
|
|
|
|
|
if (nbits > MAX_EXTERN_MPI_BITS) {
|
|
|
|
pr_info("MPI: mpi too large (%u bits)\n", nbits);
|
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
buffer += 2;
|
|
|
|
nread = 2;
|
|
|
|
|
2013-01-30 17:30:06 +08:00
|
|
|
nbytes = DIV_ROUND_UP(nbits, 8);
|
|
|
|
nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB);
|
2011-08-31 19:05:16 +08:00
|
|
|
val = mpi_alloc(nlimbs);
|
|
|
|
if (!val)
|
2012-01-27 01:13:16 +08:00
|
|
|
return NULL;
|
2011-08-31 19:05:16 +08:00
|
|
|
i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
|
|
|
|
i %= BYTES_PER_MPI_LIMB;
|
|
|
|
val->nbits = nbits;
|
|
|
|
j = val->nlimbs = nlimbs;
|
|
|
|
val->sign = 0;
|
|
|
|
for (; j > 0; j--) {
|
|
|
|
a = 0;
|
|
|
|
for (; i < BYTES_PER_MPI_LIMB; i++) {
|
|
|
|
if (++nread > *ret_nread) {
|
|
|
|
printk
|
|
|
|
("MPI: mpi larger than buffer nread=%d ret_nread=%d\n",
|
|
|
|
nread, *ret_nread);
|
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
a <<= 8;
|
|
|
|
a |= *buffer++;
|
|
|
|
}
|
|
|
|
i = 0;
|
|
|
|
val->d[j - 1] = a;
|
|
|
|
}
|
|
|
|
|
|
|
|
leave:
|
|
|
|
*ret_nread = nread;
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mpi_read_from_buffer);
|
|
|
|
|
2016-02-17 21:46:59 +08:00
|
|
|
static int count_lzeros(MPI a)
|
|
|
|
{
|
|
|
|
mpi_limb_t alimb;
|
|
|
|
int i, lzeros = 0;
|
|
|
|
|
|
|
|
for (i = a->nlimbs - 1; i >= 0; i--) {
|
|
|
|
alimb = a->d[i];
|
|
|
|
if (alimb == 0) {
|
|
|
|
lzeros += sizeof(mpi_limb_t);
|
|
|
|
} else {
|
|
|
|
lzeros += count_leading_zeros(alimb) / 8;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lzeros;
|
|
|
|
}
|
|
|
|
|
2015-06-16 04:18:36 +08:00
|
|
|
/**
|
|
|
|
* mpi_read_buffer() - read MPI to a bufer provided by user (msb first)
|
|
|
|
*
|
|
|
|
* @a: a multi precision integer
|
|
|
|
* @buf: bufer to which the output will be written to. Needs to be at
|
|
|
|
* leaset mpi_get_size(a) long.
|
|
|
|
* @buf_len: size of the buf.
|
2015-11-13 19:01:32 +08:00
|
|
|
* @nbytes: receives the actual length of the data written on success and
|
|
|
|
* the data to-be-written on -EOVERFLOW in case buf_len was too
|
|
|
|
* small.
|
2015-06-16 04:18:36 +08:00
|
|
|
* @sign: if not NULL, it will be set to the sign of a.
|
|
|
|
*
|
|
|
|
* Return: 0 on success or error code in case of error
|
2011-08-31 19:05:16 +08:00
|
|
|
*/
|
2015-06-16 04:18:36 +08:00
|
|
|
int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes,
|
|
|
|
int *sign)
|
2011-08-31 19:05:16 +08:00
|
|
|
{
|
2015-06-16 04:18:36 +08:00
|
|
|
uint8_t *p;
|
2016-03-22 20:12:41 +08:00
|
|
|
#if BYTES_PER_MPI_LIMB == 4
|
|
|
|
__be32 alimb;
|
|
|
|
#elif BYTES_PER_MPI_LIMB == 8
|
|
|
|
__be64 alimb;
|
|
|
|
#else
|
|
|
|
#error please implement for this limb size.
|
|
|
|
#endif
|
2015-06-16 04:18:36 +08:00
|
|
|
unsigned int n = mpi_get_size(a);
|
2016-02-17 21:46:59 +08:00
|
|
|
int i, lzeros;
|
2015-06-16 04:18:36 +08:00
|
|
|
|
2015-11-13 19:01:32 +08:00
|
|
|
if (!buf || !nbytes)
|
2015-06-16 04:18:36 +08:00
|
|
|
return -EINVAL;
|
2011-08-31 19:05:16 +08:00
|
|
|
|
|
|
|
if (sign)
|
|
|
|
*sign = a->sign;
|
2015-06-16 04:18:36 +08:00
|
|
|
|
2016-02-17 21:46:59 +08:00
|
|
|
lzeros = count_lzeros(a);
|
2015-06-16 04:18:36 +08:00
|
|
|
|
2015-11-13 19:01:32 +08:00
|
|
|
if (buf_len < n - lzeros) {
|
|
|
|
*nbytes = n - lzeros;
|
|
|
|
return -EOVERFLOW;
|
|
|
|
}
|
|
|
|
|
2015-06-16 04:18:36 +08:00
|
|
|
p = buf;
|
2015-08-24 22:52:14 +08:00
|
|
|
*nbytes = n - lzeros;
|
2011-08-31 19:05:16 +08:00
|
|
|
|
2016-03-22 20:12:40 +08:00
|
|
|
for (i = a->nlimbs - 1 - lzeros / BYTES_PER_MPI_LIMB,
|
|
|
|
lzeros %= BYTES_PER_MPI_LIMB;
|
|
|
|
i >= 0; i--) {
|
2011-08-31 19:05:16 +08:00
|
|
|
#if BYTES_PER_MPI_LIMB == 4
|
2016-03-22 20:12:41 +08:00
|
|
|
alimb = cpu_to_be32(a->d[i]);
|
2011-08-31 19:05:16 +08:00
|
|
|
#elif BYTES_PER_MPI_LIMB == 8
|
2016-03-22 20:12:41 +08:00
|
|
|
alimb = cpu_to_be64(a->d[i]);
|
2011-08-31 19:05:16 +08:00
|
|
|
#else
|
|
|
|
#error please implement for this limb size.
|
|
|
|
#endif
|
2016-03-22 20:12:42 +08:00
|
|
|
memcpy(p, (u8 *)&alimb + lzeros, BYTES_PER_MPI_LIMB - lzeros);
|
|
|
|
p += BYTES_PER_MPI_LIMB - lzeros;
|
|
|
|
lzeros = 0;
|
2011-08-31 19:05:16 +08:00
|
|
|
}
|
2015-06-16 04:18:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mpi_read_buffer);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* mpi_get_buffer() - Returns an allocated buffer with the MPI (msb first).
|
|
|
|
* Caller must free the return string.
|
|
|
|
* This function does return a 0 byte buffer with nbytes set to zero if the
|
|
|
|
* value of A is zero.
|
|
|
|
*
|
|
|
|
* @a: a multi precision integer.
|
|
|
|
* @nbytes: receives the length of this buffer.
|
|
|
|
* @sign: if not NULL, it will be set to the sign of the a.
|
|
|
|
*
|
|
|
|
* Return: Pointer to MPI buffer or NULL on error
|
|
|
|
*/
|
|
|
|
void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign)
|
|
|
|
{
|
2015-08-24 22:52:14 +08:00
|
|
|
uint8_t *buf;
|
2015-06-16 04:18:36 +08:00
|
|
|
unsigned int n;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!nbytes)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
n = mpi_get_size(a);
|
|
|
|
|
|
|
|
if (!n)
|
|
|
|
n++;
|
|
|
|
|
|
|
|
buf = kmalloc(n, GFP_KERNEL);
|
|
|
|
|
|
|
|
if (!buf)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ret = mpi_read_buffer(a, buf, n, nbytes, sign);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
kfree(buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return buf;
|
2011-08-31 19:05:16 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mpi_get_buffer);
|
|
|
|
|
|
|
|
/****************
|
|
|
|
* Use BUFFER to update MPI.
|
|
|
|
*/
|
|
|
|
int mpi_set_buffer(MPI a, const void *xbuffer, unsigned nbytes, int sign)
|
|
|
|
{
|
|
|
|
const uint8_t *buffer = xbuffer, *p;
|
|
|
|
mpi_limb_t alimb;
|
|
|
|
int nlimbs;
|
|
|
|
int i;
|
|
|
|
|
2013-01-30 17:30:06 +08:00
|
|
|
nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB);
|
2011-08-31 19:05:16 +08:00
|
|
|
if (RESIZE_IF_NEEDED(a, nlimbs) < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
a->sign = sign;
|
|
|
|
|
|
|
|
for (i = 0, p = buffer + nbytes - 1; p >= buffer + BYTES_PER_MPI_LIMB;) {
|
|
|
|
#if BYTES_PER_MPI_LIMB == 4
|
|
|
|
alimb = (mpi_limb_t) *p--;
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 8;
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 16;
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 24;
|
|
|
|
#elif BYTES_PER_MPI_LIMB == 8
|
|
|
|
alimb = (mpi_limb_t) *p--;
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 8;
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 16;
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 24;
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 32;
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 40;
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 48;
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 56;
|
|
|
|
#else
|
|
|
|
#error please implement for this limb size.
|
|
|
|
#endif
|
|
|
|
a->d[i++] = alimb;
|
|
|
|
}
|
|
|
|
if (p >= buffer) {
|
|
|
|
#if BYTES_PER_MPI_LIMB == 4
|
|
|
|
alimb = *p--;
|
|
|
|
if (p >= buffer)
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 8;
|
|
|
|
if (p >= buffer)
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 16;
|
|
|
|
if (p >= buffer)
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 24;
|
|
|
|
#elif BYTES_PER_MPI_LIMB == 8
|
|
|
|
alimb = (mpi_limb_t) *p--;
|
|
|
|
if (p >= buffer)
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 8;
|
|
|
|
if (p >= buffer)
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 16;
|
|
|
|
if (p >= buffer)
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 24;
|
|
|
|
if (p >= buffer)
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 32;
|
|
|
|
if (p >= buffer)
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 40;
|
|
|
|
if (p >= buffer)
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 48;
|
|
|
|
if (p >= buffer)
|
|
|
|
alimb |= (mpi_limb_t) *p-- << 56;
|
|
|
|
#else
|
|
|
|
#error please implement for this limb size.
|
|
|
|
#endif
|
|
|
|
a->d[i++] = alimb;
|
|
|
|
}
|
|
|
|
a->nlimbs = i;
|
|
|
|
|
|
|
|
if (i != nlimbs) {
|
|
|
|
pr_emerg("MPI: mpi_set_buffer: Assertion failed (%d != %d)", i,
|
|
|
|
nlimbs);
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mpi_set_buffer);
|
2015-10-09 00:26:50 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* mpi_write_to_sgl() - Funnction exports MPI to an sgl (msb first)
|
|
|
|
*
|
|
|
|
* This function works in the same way as the mpi_read_buffer, but it
|
|
|
|
* takes an sgl instead of u8 * buf.
|
|
|
|
*
|
|
|
|
* @a: a multi precision integer
|
|
|
|
* @sgl: scatterlist to write to. Needs to be at least
|
|
|
|
* mpi_get_size(a) long.
|
|
|
|
* @nbytes: in/out param - it has the be set to the maximum number of
|
|
|
|
* bytes that can be written to sgl. This has to be at least
|
|
|
|
* the size of the integer a. On return it receives the actual
|
2015-11-13 19:01:32 +08:00
|
|
|
* length of the data written on success or the data that would
|
|
|
|
* be written if buffer was too small.
|
2015-10-09 00:26:50 +08:00
|
|
|
* @sign: if not NULL, it will be set to the sign of a.
|
|
|
|
*
|
|
|
|
* Return: 0 on success or error code in case of error
|
|
|
|
*/
|
|
|
|
int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes,
|
|
|
|
int *sign)
|
|
|
|
{
|
|
|
|
u8 *p, *p2;
|
2016-03-22 20:12:39 +08:00
|
|
|
#if BYTES_PER_MPI_LIMB == 4
|
|
|
|
__be32 alimb;
|
|
|
|
#elif BYTES_PER_MPI_LIMB == 8
|
|
|
|
__be64 alimb;
|
|
|
|
#else
|
|
|
|
#error please implement for this limb size.
|
|
|
|
#endif
|
2015-10-09 00:26:50 +08:00
|
|
|
unsigned int n = mpi_get_size(a);
|
2016-02-17 21:46:59 +08:00
|
|
|
int i, x, y = 0, lzeros, buf_len;
|
2015-10-09 00:26:50 +08:00
|
|
|
|
2015-11-13 19:01:32 +08:00
|
|
|
if (!nbytes)
|
2015-10-09 00:26:50 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (sign)
|
|
|
|
*sign = a->sign;
|
|
|
|
|
2016-02-17 21:46:59 +08:00
|
|
|
lzeros = count_lzeros(a);
|
2015-10-09 00:26:50 +08:00
|
|
|
|
2015-11-13 19:01:32 +08:00
|
|
|
if (*nbytes < n - lzeros) {
|
|
|
|
*nbytes = n - lzeros;
|
|
|
|
return -EOVERFLOW;
|
|
|
|
}
|
|
|
|
|
2015-10-09 00:26:50 +08:00
|
|
|
*nbytes = n - lzeros;
|
|
|
|
buf_len = sgl->length;
|
|
|
|
p2 = sg_virt(sgl);
|
|
|
|
|
2016-03-22 20:12:35 +08:00
|
|
|
for (i = a->nlimbs - 1 - lzeros / BYTES_PER_MPI_LIMB,
|
|
|
|
lzeros %= BYTES_PER_MPI_LIMB;
|
|
|
|
i >= 0; i--) {
|
2015-10-09 00:26:50 +08:00
|
|
|
#if BYTES_PER_MPI_LIMB == 4
|
2016-03-22 20:12:39 +08:00
|
|
|
alimb = cpu_to_be32(a->d[i]);
|
2015-10-09 00:26:50 +08:00
|
|
|
#elif BYTES_PER_MPI_LIMB == 8
|
2016-03-22 20:12:39 +08:00
|
|
|
alimb = cpu_to_be64(a->d[i]);
|
2015-10-09 00:26:50 +08:00
|
|
|
#else
|
|
|
|
#error please implement for this limb size.
|
|
|
|
#endif
|
2016-03-22 20:12:36 +08:00
|
|
|
if (lzeros) {
|
2016-03-22 20:12:35 +08:00
|
|
|
y = lzeros;
|
2016-03-22 20:12:36 +08:00
|
|
|
lzeros = 0;
|
2015-10-09 00:26:50 +08:00
|
|
|
}
|
|
|
|
|
2016-03-22 20:12:39 +08:00
|
|
|
p = (u8 *)&alimb + y;
|
2015-10-09 00:26:50 +08:00
|
|
|
|
|
|
|
for (x = 0; x < sizeof(alimb) - y; x++) {
|
|
|
|
if (!buf_len) {
|
|
|
|
sgl = sg_next(sgl);
|
|
|
|
if (!sgl)
|
|
|
|
return -EINVAL;
|
|
|
|
buf_len = sgl->length;
|
|
|
|
p2 = sg_virt(sgl);
|
|
|
|
}
|
|
|
|
*p2++ = *p++;
|
|
|
|
buf_len--;
|
|
|
|
}
|
|
|
|
y = 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mpi_write_to_sgl);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* mpi_read_raw_from_sgl() - Function allocates an MPI and populates it with
|
|
|
|
* data from the sgl
|
|
|
|
*
|
|
|
|
* This function works in the same way as the mpi_read_raw_data, but it
|
|
|
|
* takes an sgl instead of void * buffer. i.e. it allocates
|
|
|
|
* a new MPI and reads the content of the sgl to the MPI.
|
|
|
|
*
|
|
|
|
* @sgl: scatterlist to read from
|
2016-03-22 20:12:43 +08:00
|
|
|
* @nbytes: number of bytes to read
|
2015-10-09 00:26:50 +08:00
|
|
|
*
|
|
|
|
* Return: Pointer to a new MPI or NULL on error
|
|
|
|
*/
|
2016-03-22 20:12:43 +08:00
|
|
|
MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int nbytes)
|
2015-10-09 00:26:50 +08:00
|
|
|
{
|
|
|
|
struct scatterlist *sg;
|
|
|
|
int x, i, j, z, lzeros, ents;
|
2016-03-22 20:12:43 +08:00
|
|
|
unsigned int nbits, nlimbs;
|
2015-10-09 00:26:50 +08:00
|
|
|
mpi_limb_t a;
|
|
|
|
MPI val = NULL;
|
|
|
|
|
|
|
|
lzeros = 0;
|
|
|
|
ents = sg_nents(sgl);
|
|
|
|
|
|
|
|
for_each_sg(sgl, sg, ents, i) {
|
|
|
|
const u8 *buff = sg_virt(sg);
|
|
|
|
int len = sg->length;
|
|
|
|
|
2015-10-18 18:45:18 +08:00
|
|
|
while (len && !*buff) {
|
2015-10-09 00:26:50 +08:00
|
|
|
lzeros++;
|
2015-10-18 18:45:18 +08:00
|
|
|
len--;
|
|
|
|
buff++;
|
|
|
|
}
|
2015-10-09 00:26:50 +08:00
|
|
|
|
|
|
|
if (len && *buff)
|
|
|
|
break;
|
|
|
|
|
|
|
|
ents--;
|
lib/mpi: mpi_read_raw_from_sgl(): don't include leading zero SGEs in nbytes
At the very beginning of mpi_read_raw_from_sgl(), the leading zeros of
the input scatterlist are counted:
lzeros = 0;
for_each_sg(sgl, sg, ents, i) {
...
if (/* sg contains nonzero bytes */)
break;
/* sg contains nothing but zeros here */
ents--;
lzeros = 0;
}
Later on, the total number of trailing nonzero bytes is calculated by
subtracting the number of leading zero bytes from the total number of input
bytes:
nbytes -= lzeros;
However, since lzeros gets reset to zero for each completely zero leading
sg in the loop above, it doesn't include those.
Besides wasting resources by allocating a too large output buffer,
this mistake propagates into the calculation of x, the number of
leading zeros within the most significant output limb:
x = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
What's more, the low order bytes of the output, equal in number to the
extra bytes in nbytes, are left uninitialized.
Fix this by adjusting nbytes for each completely zero leading scatterlist
entry.
Fixes: 2d4d1eea540b ("lib/mpi: Add mpi sgl helpers")
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2016-03-22 20:12:44 +08:00
|
|
|
nbytes -= lzeros;
|
2015-10-09 00:26:50 +08:00
|
|
|
lzeros = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
sgl = sg;
|
lib/mpi: mpi_read_raw_from_sgl(): don't include leading zero SGEs in nbytes
At the very beginning of mpi_read_raw_from_sgl(), the leading zeros of
the input scatterlist are counted:
lzeros = 0;
for_each_sg(sgl, sg, ents, i) {
...
if (/* sg contains nonzero bytes */)
break;
/* sg contains nothing but zeros here */
ents--;
lzeros = 0;
}
Later on, the total number of trailing nonzero bytes is calculated by
subtracting the number of leading zero bytes from the total number of input
bytes:
nbytes -= lzeros;
However, since lzeros gets reset to zero for each completely zero leading
sg in the loop above, it doesn't include those.
Besides wasting resources by allocating a too large output buffer,
this mistake propagates into the calculation of x, the number of
leading zeros within the most significant output limb:
x = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
What's more, the low order bytes of the output, equal in number to the
extra bytes in nbytes, are left uninitialized.
Fix this by adjusting nbytes for each completely zero leading scatterlist
entry.
Fixes: 2d4d1eea540b ("lib/mpi: Add mpi sgl helpers")
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2016-03-22 20:12:44 +08:00
|
|
|
nbytes -= lzeros;
|
2015-10-09 00:26:50 +08:00
|
|
|
nbits = nbytes * 8;
|
|
|
|
if (nbits > MAX_EXTERN_MPI_BITS) {
|
|
|
|
pr_info("MPI: mpi too large (%u bits)\n", nbits);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nbytes > 0)
|
2016-03-22 20:17:27 +08:00
|
|
|
nbits -= count_leading_zeros(*(u8 *)(sg_virt(sgl) + lzeros)) -
|
|
|
|
(BITS_PER_LONG - 8);
|
2015-10-09 00:26:50 +08:00
|
|
|
|
|
|
|
nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB);
|
|
|
|
val = mpi_alloc(nlimbs);
|
|
|
|
if (!val)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
val->nbits = nbits;
|
|
|
|
val->sign = 0;
|
|
|
|
val->nlimbs = nlimbs;
|
|
|
|
|
|
|
|
if (nbytes == 0)
|
|
|
|
return val;
|
|
|
|
|
|
|
|
j = nlimbs - 1;
|
|
|
|
a = 0;
|
|
|
|
z = 0;
|
|
|
|
x = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
|
|
|
|
x %= BYTES_PER_MPI_LIMB;
|
|
|
|
|
|
|
|
for_each_sg(sgl, sg, ents, i) {
|
|
|
|
const u8 *buffer = sg_virt(sg) + lzeros;
|
|
|
|
int len = sg->length - lzeros;
|
|
|
|
int buf_shift = x;
|
|
|
|
|
|
|
|
if (sg_is_last(sg) && (len % BYTES_PER_MPI_LIMB))
|
|
|
|
len += BYTES_PER_MPI_LIMB - (len % BYTES_PER_MPI_LIMB);
|
|
|
|
|
|
|
|
for (; x < len + buf_shift; x++) {
|
|
|
|
a <<= 8;
|
|
|
|
a |= *buffer++;
|
|
|
|
if (((z + x + 1) % BYTES_PER_MPI_LIMB) == 0) {
|
|
|
|
val->d[j--] = a;
|
|
|
|
a = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
z += x;
|
|
|
|
x = 0;
|
|
|
|
lzeros = 0;
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mpi_read_raw_from_sgl);
|