162306a36Sopenharmony_ci/* mpicoder.c - Coder for the external representation of MPIs 262306a36Sopenharmony_ci * Copyright (C) 1998, 1999 Free Software Foundation, Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This file is part of GnuPG. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * GnuPG is free software; you can redistribute it and/or modify 762306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by 862306a36Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 962306a36Sopenharmony_ci * (at your option) any later version. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * GnuPG is distributed in the hope that it will be useful, 1262306a36Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 1362306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1462306a36Sopenharmony_ci * GNU General Public License for more details. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License 1762306a36Sopenharmony_ci * along with this program; if not, write to the Free Software 1862306a36Sopenharmony_ci * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/bitops.h> 2262306a36Sopenharmony_ci#include <linux/count_zeros.h> 2362306a36Sopenharmony_ci#include <linux/byteorder/generic.h> 2462306a36Sopenharmony_ci#include <linux/scatterlist.h> 2562306a36Sopenharmony_ci#include <linux/string.h> 2662306a36Sopenharmony_ci#include "mpi-internal.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define MAX_EXTERN_SCAN_BYTES (16*1024*1024) 2962306a36Sopenharmony_ci#define MAX_EXTERN_MPI_BITS 16384 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/** 3262306a36Sopenharmony_ci * mpi_read_raw_data - Read a raw byte stream as a positive integer 3362306a36Sopenharmony_ci * @xbuffer: The data to read 3462306a36Sopenharmony_ci * @nbytes: The amount of data to read 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ciMPI mpi_read_raw_data(const void *xbuffer, size_t nbytes) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci const uint8_t *buffer = xbuffer; 3962306a36Sopenharmony_ci int i, j; 4062306a36Sopenharmony_ci unsigned nbits, nlimbs; 4162306a36Sopenharmony_ci mpi_limb_t a; 4262306a36Sopenharmony_ci MPI val = NULL; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci while (nbytes > 0 && buffer[0] == 0) { 4562306a36Sopenharmony_ci buffer++; 4662306a36Sopenharmony_ci nbytes--; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci nbits = nbytes * 8; 5062306a36Sopenharmony_ci if (nbits > MAX_EXTERN_MPI_BITS) { 5162306a36Sopenharmony_ci pr_info("MPI: mpi too large (%u bits)\n", nbits); 5262306a36Sopenharmony_ci return NULL; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci if (nbytes > 0) 5562306a36Sopenharmony_ci nbits -= count_leading_zeros(buffer[0]) - (BITS_PER_LONG - 8); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB); 5862306a36Sopenharmony_ci val = mpi_alloc(nlimbs); 5962306a36Sopenharmony_ci if (!val) 6062306a36Sopenharmony_ci return NULL; 6162306a36Sopenharmony_ci val->nbits = nbits; 6262306a36Sopenharmony_ci val->sign = 0; 6362306a36Sopenharmony_ci val->nlimbs = nlimbs; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (nbytes > 0) { 6662306a36Sopenharmony_ci i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; 6762306a36Sopenharmony_ci i %= BYTES_PER_MPI_LIMB; 6862306a36Sopenharmony_ci for (j = nlimbs; j > 0; j--) { 6962306a36Sopenharmony_ci a = 0; 7062306a36Sopenharmony_ci for (; i < BYTES_PER_MPI_LIMB; i++) { 7162306a36Sopenharmony_ci a <<= 8; 7262306a36Sopenharmony_ci a |= *buffer++; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci i = 0; 7562306a36Sopenharmony_ci val->d[j - 1] = a; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci return val; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_read_raw_data); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ciMPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci const uint8_t *buffer = xbuffer; 8562306a36Sopenharmony_ci unsigned int nbits, nbytes; 8662306a36Sopenharmony_ci MPI val; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (*ret_nread < 2) 8962306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 9062306a36Sopenharmony_ci nbits = buffer[0] << 8 | buffer[1]; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (nbits > MAX_EXTERN_MPI_BITS) { 9362306a36Sopenharmony_ci pr_info("MPI: mpi too large (%u bits)\n", nbits); 9462306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci nbytes = DIV_ROUND_UP(nbits, 8); 9862306a36Sopenharmony_ci if (nbytes + 2 > *ret_nread) { 9962306a36Sopenharmony_ci pr_info("MPI: mpi larger than buffer nbytes=%u ret_nread=%u\n", 10062306a36Sopenharmony_ci nbytes, *ret_nread); 10162306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci val = mpi_read_raw_data(buffer + 2, nbytes); 10562306a36Sopenharmony_ci if (!val) 10662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci *ret_nread = nbytes + 2; 10962306a36Sopenharmony_ci return val; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_read_from_buffer); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/**************** 11462306a36Sopenharmony_ci * Fill the mpi VAL from the hex string in STR. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ciint mpi_fromstr(MPI val, const char *str) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci int sign = 0; 11962306a36Sopenharmony_ci int prepend_zero = 0; 12062306a36Sopenharmony_ci int i, j, c, c1, c2; 12162306a36Sopenharmony_ci unsigned int nbits, nbytes, nlimbs; 12262306a36Sopenharmony_ci mpi_limb_t a; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (*str == '-') { 12562306a36Sopenharmony_ci sign = 1; 12662306a36Sopenharmony_ci str++; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* Skip optional hex prefix. */ 13062306a36Sopenharmony_ci if (*str == '0' && str[1] == 'x') 13162306a36Sopenharmony_ci str += 2; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci nbits = strlen(str); 13462306a36Sopenharmony_ci if (nbits > MAX_EXTERN_SCAN_BYTES) { 13562306a36Sopenharmony_ci mpi_clear(val); 13662306a36Sopenharmony_ci return -EINVAL; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci nbits *= 4; 13962306a36Sopenharmony_ci if ((nbits % 8)) 14062306a36Sopenharmony_ci prepend_zero = 1; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci nbytes = (nbits+7) / 8; 14362306a36Sopenharmony_ci nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (val->alloced < nlimbs) 14662306a36Sopenharmony_ci mpi_resize(val, nlimbs); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci i = BYTES_PER_MPI_LIMB - (nbytes % BYTES_PER_MPI_LIMB); 14962306a36Sopenharmony_ci i %= BYTES_PER_MPI_LIMB; 15062306a36Sopenharmony_ci j = val->nlimbs = nlimbs; 15162306a36Sopenharmony_ci val->sign = sign; 15262306a36Sopenharmony_ci for (; j > 0; j--) { 15362306a36Sopenharmony_ci a = 0; 15462306a36Sopenharmony_ci for (; i < BYTES_PER_MPI_LIMB; i++) { 15562306a36Sopenharmony_ci if (prepend_zero) { 15662306a36Sopenharmony_ci c1 = '0'; 15762306a36Sopenharmony_ci prepend_zero = 0; 15862306a36Sopenharmony_ci } else 15962306a36Sopenharmony_ci c1 = *str++; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (!c1) { 16262306a36Sopenharmony_ci mpi_clear(val); 16362306a36Sopenharmony_ci return -EINVAL; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci c2 = *str++; 16662306a36Sopenharmony_ci if (!c2) { 16762306a36Sopenharmony_ci mpi_clear(val); 16862306a36Sopenharmony_ci return -EINVAL; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci if (c1 >= '0' && c1 <= '9') 17162306a36Sopenharmony_ci c = c1 - '0'; 17262306a36Sopenharmony_ci else if (c1 >= 'a' && c1 <= 'f') 17362306a36Sopenharmony_ci c = c1 - 'a' + 10; 17462306a36Sopenharmony_ci else if (c1 >= 'A' && c1 <= 'F') 17562306a36Sopenharmony_ci c = c1 - 'A' + 10; 17662306a36Sopenharmony_ci else { 17762306a36Sopenharmony_ci mpi_clear(val); 17862306a36Sopenharmony_ci return -EINVAL; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci c <<= 4; 18162306a36Sopenharmony_ci if (c2 >= '0' && c2 <= '9') 18262306a36Sopenharmony_ci c |= c2 - '0'; 18362306a36Sopenharmony_ci else if (c2 >= 'a' && c2 <= 'f') 18462306a36Sopenharmony_ci c |= c2 - 'a' + 10; 18562306a36Sopenharmony_ci else if (c2 >= 'A' && c2 <= 'F') 18662306a36Sopenharmony_ci c |= c2 - 'A' + 10; 18762306a36Sopenharmony_ci else { 18862306a36Sopenharmony_ci mpi_clear(val); 18962306a36Sopenharmony_ci return -EINVAL; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci a <<= 8; 19262306a36Sopenharmony_ci a |= c; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci i = 0; 19562306a36Sopenharmony_ci val->d[j-1] = a; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci return 0; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_fromstr); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ciMPI mpi_scanval(const char *string) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci MPI a; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci a = mpi_alloc(0); 20762306a36Sopenharmony_ci if (!a) 20862306a36Sopenharmony_ci return NULL; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (mpi_fromstr(a, string)) { 21162306a36Sopenharmony_ci mpi_free(a); 21262306a36Sopenharmony_ci return NULL; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci mpi_normalize(a); 21562306a36Sopenharmony_ci return a; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_scanval); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic int count_lzeros(MPI a) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci mpi_limb_t alimb; 22262306a36Sopenharmony_ci int i, lzeros = 0; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci for (i = a->nlimbs - 1; i >= 0; i--) { 22562306a36Sopenharmony_ci alimb = a->d[i]; 22662306a36Sopenharmony_ci if (alimb == 0) { 22762306a36Sopenharmony_ci lzeros += sizeof(mpi_limb_t); 22862306a36Sopenharmony_ci } else { 22962306a36Sopenharmony_ci lzeros += count_leading_zeros(alimb) / 8; 23062306a36Sopenharmony_ci break; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci return lzeros; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci/** 23762306a36Sopenharmony_ci * mpi_read_buffer() - read MPI to a buffer provided by user (msb first) 23862306a36Sopenharmony_ci * 23962306a36Sopenharmony_ci * @a: a multi precision integer 24062306a36Sopenharmony_ci * @buf: buffer to which the output will be written to. Needs to be at 24162306a36Sopenharmony_ci * least mpi_get_size(a) long. 24262306a36Sopenharmony_ci * @buf_len: size of the buf. 24362306a36Sopenharmony_ci * @nbytes: receives the actual length of the data written on success and 24462306a36Sopenharmony_ci * the data to-be-written on -EOVERFLOW in case buf_len was too 24562306a36Sopenharmony_ci * small. 24662306a36Sopenharmony_ci * @sign: if not NULL, it will be set to the sign of a. 24762306a36Sopenharmony_ci * 24862306a36Sopenharmony_ci * Return: 0 on success or error code in case of error 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ciint mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes, 25162306a36Sopenharmony_ci int *sign) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci uint8_t *p; 25462306a36Sopenharmony_ci#if BYTES_PER_MPI_LIMB == 4 25562306a36Sopenharmony_ci __be32 alimb; 25662306a36Sopenharmony_ci#elif BYTES_PER_MPI_LIMB == 8 25762306a36Sopenharmony_ci __be64 alimb; 25862306a36Sopenharmony_ci#else 25962306a36Sopenharmony_ci#error please implement for this limb size. 26062306a36Sopenharmony_ci#endif 26162306a36Sopenharmony_ci unsigned int n = mpi_get_size(a); 26262306a36Sopenharmony_ci int i, lzeros; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (!buf || !nbytes) 26562306a36Sopenharmony_ci return -EINVAL; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (sign) 26862306a36Sopenharmony_ci *sign = a->sign; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci lzeros = count_lzeros(a); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (buf_len < n - lzeros) { 27362306a36Sopenharmony_ci *nbytes = n - lzeros; 27462306a36Sopenharmony_ci return -EOVERFLOW; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci p = buf; 27862306a36Sopenharmony_ci *nbytes = n - lzeros; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci for (i = a->nlimbs - 1 - lzeros / BYTES_PER_MPI_LIMB, 28162306a36Sopenharmony_ci lzeros %= BYTES_PER_MPI_LIMB; 28262306a36Sopenharmony_ci i >= 0; i--) { 28362306a36Sopenharmony_ci#if BYTES_PER_MPI_LIMB == 4 28462306a36Sopenharmony_ci alimb = cpu_to_be32(a->d[i]); 28562306a36Sopenharmony_ci#elif BYTES_PER_MPI_LIMB == 8 28662306a36Sopenharmony_ci alimb = cpu_to_be64(a->d[i]); 28762306a36Sopenharmony_ci#else 28862306a36Sopenharmony_ci#error please implement for this limb size. 28962306a36Sopenharmony_ci#endif 29062306a36Sopenharmony_ci memcpy(p, (u8 *)&alimb + lzeros, BYTES_PER_MPI_LIMB - lzeros); 29162306a36Sopenharmony_ci p += BYTES_PER_MPI_LIMB - lzeros; 29262306a36Sopenharmony_ci lzeros = 0; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci return 0; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_read_buffer); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci/* 29962306a36Sopenharmony_ci * mpi_get_buffer() - Returns an allocated buffer with the MPI (msb first). 30062306a36Sopenharmony_ci * Caller must free the return string. 30162306a36Sopenharmony_ci * This function does return a 0 byte buffer with nbytes set to zero if the 30262306a36Sopenharmony_ci * value of A is zero. 30362306a36Sopenharmony_ci * 30462306a36Sopenharmony_ci * @a: a multi precision integer. 30562306a36Sopenharmony_ci * @nbytes: receives the length of this buffer. 30662306a36Sopenharmony_ci * @sign: if not NULL, it will be set to the sign of the a. 30762306a36Sopenharmony_ci * 30862306a36Sopenharmony_ci * Return: Pointer to MPI buffer or NULL on error 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_civoid *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci uint8_t *buf; 31362306a36Sopenharmony_ci unsigned int n; 31462306a36Sopenharmony_ci int ret; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (!nbytes) 31762306a36Sopenharmony_ci return NULL; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci n = mpi_get_size(a); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (!n) 32262306a36Sopenharmony_ci n++; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci buf = kmalloc(n, GFP_KERNEL); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (!buf) 32762306a36Sopenharmony_ci return NULL; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci ret = mpi_read_buffer(a, buf, n, nbytes, sign); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (ret) { 33262306a36Sopenharmony_ci kfree(buf); 33362306a36Sopenharmony_ci return NULL; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci return buf; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_get_buffer); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci/** 34062306a36Sopenharmony_ci * mpi_write_to_sgl() - Funnction exports MPI to an sgl (msb first) 34162306a36Sopenharmony_ci * 34262306a36Sopenharmony_ci * This function works in the same way as the mpi_read_buffer, but it 34362306a36Sopenharmony_ci * takes an sgl instead of u8 * buf. 34462306a36Sopenharmony_ci * 34562306a36Sopenharmony_ci * @a: a multi precision integer 34662306a36Sopenharmony_ci * @sgl: scatterlist to write to. Needs to be at least 34762306a36Sopenharmony_ci * mpi_get_size(a) long. 34862306a36Sopenharmony_ci * @nbytes: the number of bytes to write. Leading bytes will be 34962306a36Sopenharmony_ci * filled with zero. 35062306a36Sopenharmony_ci * @sign: if not NULL, it will be set to the sign of a. 35162306a36Sopenharmony_ci * 35262306a36Sopenharmony_ci * Return: 0 on success or error code in case of error 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_ciint mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned nbytes, 35562306a36Sopenharmony_ci int *sign) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci u8 *p, *p2; 35862306a36Sopenharmony_ci#if BYTES_PER_MPI_LIMB == 4 35962306a36Sopenharmony_ci __be32 alimb; 36062306a36Sopenharmony_ci#elif BYTES_PER_MPI_LIMB == 8 36162306a36Sopenharmony_ci __be64 alimb; 36262306a36Sopenharmony_ci#else 36362306a36Sopenharmony_ci#error please implement for this limb size. 36462306a36Sopenharmony_ci#endif 36562306a36Sopenharmony_ci unsigned int n = mpi_get_size(a); 36662306a36Sopenharmony_ci struct sg_mapping_iter miter; 36762306a36Sopenharmony_ci int i, x, buf_len; 36862306a36Sopenharmony_ci int nents; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (sign) 37162306a36Sopenharmony_ci *sign = a->sign; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (nbytes < n) 37462306a36Sopenharmony_ci return -EOVERFLOW; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci nents = sg_nents_for_len(sgl, nbytes); 37762306a36Sopenharmony_ci if (nents < 0) 37862306a36Sopenharmony_ci return -EINVAL; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci sg_miter_start(&miter, sgl, nents, SG_MITER_ATOMIC | SG_MITER_TO_SG); 38162306a36Sopenharmony_ci sg_miter_next(&miter); 38262306a36Sopenharmony_ci buf_len = miter.length; 38362306a36Sopenharmony_ci p2 = miter.addr; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci while (nbytes > n) { 38662306a36Sopenharmony_ci i = min_t(unsigned, nbytes - n, buf_len); 38762306a36Sopenharmony_ci memset(p2, 0, i); 38862306a36Sopenharmony_ci p2 += i; 38962306a36Sopenharmony_ci nbytes -= i; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci buf_len -= i; 39262306a36Sopenharmony_ci if (!buf_len) { 39362306a36Sopenharmony_ci sg_miter_next(&miter); 39462306a36Sopenharmony_ci buf_len = miter.length; 39562306a36Sopenharmony_ci p2 = miter.addr; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci for (i = a->nlimbs - 1; i >= 0; i--) { 40062306a36Sopenharmony_ci#if BYTES_PER_MPI_LIMB == 4 40162306a36Sopenharmony_ci alimb = a->d[i] ? cpu_to_be32(a->d[i]) : 0; 40262306a36Sopenharmony_ci#elif BYTES_PER_MPI_LIMB == 8 40362306a36Sopenharmony_ci alimb = a->d[i] ? cpu_to_be64(a->d[i]) : 0; 40462306a36Sopenharmony_ci#else 40562306a36Sopenharmony_ci#error please implement for this limb size. 40662306a36Sopenharmony_ci#endif 40762306a36Sopenharmony_ci p = (u8 *)&alimb; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci for (x = 0; x < sizeof(alimb); x++) { 41062306a36Sopenharmony_ci *p2++ = *p++; 41162306a36Sopenharmony_ci if (!--buf_len) { 41262306a36Sopenharmony_ci sg_miter_next(&miter); 41362306a36Sopenharmony_ci buf_len = miter.length; 41462306a36Sopenharmony_ci p2 = miter.addr; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci sg_miter_stop(&miter); 42062306a36Sopenharmony_ci return 0; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_write_to_sgl); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci/* 42562306a36Sopenharmony_ci * mpi_read_raw_from_sgl() - Function allocates an MPI and populates it with 42662306a36Sopenharmony_ci * data from the sgl 42762306a36Sopenharmony_ci * 42862306a36Sopenharmony_ci * This function works in the same way as the mpi_read_raw_data, but it 42962306a36Sopenharmony_ci * takes an sgl instead of void * buffer. i.e. it allocates 43062306a36Sopenharmony_ci * a new MPI and reads the content of the sgl to the MPI. 43162306a36Sopenharmony_ci * 43262306a36Sopenharmony_ci * @sgl: scatterlist to read from 43362306a36Sopenharmony_ci * @nbytes: number of bytes to read 43462306a36Sopenharmony_ci * 43562306a36Sopenharmony_ci * Return: Pointer to a new MPI or NULL on error 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_ciMPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int nbytes) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct sg_mapping_iter miter; 44062306a36Sopenharmony_ci unsigned int nbits, nlimbs; 44162306a36Sopenharmony_ci int x, j, z, lzeros, ents; 44262306a36Sopenharmony_ci unsigned int len; 44362306a36Sopenharmony_ci const u8 *buff; 44462306a36Sopenharmony_ci mpi_limb_t a; 44562306a36Sopenharmony_ci MPI val = NULL; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci ents = sg_nents_for_len(sgl, nbytes); 44862306a36Sopenharmony_ci if (ents < 0) 44962306a36Sopenharmony_ci return NULL; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci sg_miter_start(&miter, sgl, ents, SG_MITER_ATOMIC | SG_MITER_FROM_SG); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci lzeros = 0; 45462306a36Sopenharmony_ci len = 0; 45562306a36Sopenharmony_ci while (nbytes > 0) { 45662306a36Sopenharmony_ci while (len && !*buff) { 45762306a36Sopenharmony_ci lzeros++; 45862306a36Sopenharmony_ci len--; 45962306a36Sopenharmony_ci buff++; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (len && *buff) 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci sg_miter_next(&miter); 46662306a36Sopenharmony_ci buff = miter.addr; 46762306a36Sopenharmony_ci len = miter.length; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci nbytes -= lzeros; 47062306a36Sopenharmony_ci lzeros = 0; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci miter.consumed = lzeros; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci nbytes -= lzeros; 47662306a36Sopenharmony_ci nbits = nbytes * 8; 47762306a36Sopenharmony_ci if (nbits > MAX_EXTERN_MPI_BITS) { 47862306a36Sopenharmony_ci sg_miter_stop(&miter); 47962306a36Sopenharmony_ci pr_info("MPI: mpi too large (%u bits)\n", nbits); 48062306a36Sopenharmony_ci return NULL; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (nbytes > 0) 48462306a36Sopenharmony_ci nbits -= count_leading_zeros(*buff) - (BITS_PER_LONG - 8); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci sg_miter_stop(&miter); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB); 48962306a36Sopenharmony_ci val = mpi_alloc(nlimbs); 49062306a36Sopenharmony_ci if (!val) 49162306a36Sopenharmony_ci return NULL; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci val->nbits = nbits; 49462306a36Sopenharmony_ci val->sign = 0; 49562306a36Sopenharmony_ci val->nlimbs = nlimbs; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (nbytes == 0) 49862306a36Sopenharmony_ci return val; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci j = nlimbs - 1; 50162306a36Sopenharmony_ci a = 0; 50262306a36Sopenharmony_ci z = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; 50362306a36Sopenharmony_ci z %= BYTES_PER_MPI_LIMB; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci while (sg_miter_next(&miter)) { 50662306a36Sopenharmony_ci buff = miter.addr; 50762306a36Sopenharmony_ci len = min_t(unsigned, miter.length, nbytes); 50862306a36Sopenharmony_ci nbytes -= len; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci for (x = 0; x < len; x++) { 51162306a36Sopenharmony_ci a <<= 8; 51262306a36Sopenharmony_ci a |= *buff++; 51362306a36Sopenharmony_ci if (((z + x + 1) % BYTES_PER_MPI_LIMB) == 0) { 51462306a36Sopenharmony_ci val->d[j--] = a; 51562306a36Sopenharmony_ci a = 0; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci z += x; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return val; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_read_raw_from_sgl); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci/* Perform a two's complement operation on buffer P of size N bytes. */ 52662306a36Sopenharmony_cistatic void twocompl(unsigned char *p, unsigned int n) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci int i; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci for (i = n-1; i >= 0 && !p[i]; i--) 53162306a36Sopenharmony_ci ; 53262306a36Sopenharmony_ci if (i >= 0) { 53362306a36Sopenharmony_ci if ((p[i] & 0x01)) 53462306a36Sopenharmony_ci p[i] = (((p[i] ^ 0xfe) | 0x01) & 0xff); 53562306a36Sopenharmony_ci else if ((p[i] & 0x02)) 53662306a36Sopenharmony_ci p[i] = (((p[i] ^ 0xfc) | 0x02) & 0xfe); 53762306a36Sopenharmony_ci else if ((p[i] & 0x04)) 53862306a36Sopenharmony_ci p[i] = (((p[i] ^ 0xf8) | 0x04) & 0xfc); 53962306a36Sopenharmony_ci else if ((p[i] & 0x08)) 54062306a36Sopenharmony_ci p[i] = (((p[i] ^ 0xf0) | 0x08) & 0xf8); 54162306a36Sopenharmony_ci else if ((p[i] & 0x10)) 54262306a36Sopenharmony_ci p[i] = (((p[i] ^ 0xe0) | 0x10) & 0xf0); 54362306a36Sopenharmony_ci else if ((p[i] & 0x20)) 54462306a36Sopenharmony_ci p[i] = (((p[i] ^ 0xc0) | 0x20) & 0xe0); 54562306a36Sopenharmony_ci else if ((p[i] & 0x40)) 54662306a36Sopenharmony_ci p[i] = (((p[i] ^ 0x80) | 0x40) & 0xc0); 54762306a36Sopenharmony_ci else 54862306a36Sopenharmony_ci p[i] = 0x80; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci for (i--; i >= 0; i--) 55162306a36Sopenharmony_ci p[i] ^= 0xff; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ciint mpi_print(enum gcry_mpi_format format, unsigned char *buffer, 55662306a36Sopenharmony_ci size_t buflen, size_t *nwritten, MPI a) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci unsigned int nbits = mpi_get_nbits(a); 55962306a36Sopenharmony_ci size_t len; 56062306a36Sopenharmony_ci size_t dummy_nwritten; 56162306a36Sopenharmony_ci int negative; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (!nwritten) 56462306a36Sopenharmony_ci nwritten = &dummy_nwritten; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* Libgcrypt does no always care to set clear the sign if the value 56762306a36Sopenharmony_ci * is 0. For printing this is a bit of a surprise, in particular 56862306a36Sopenharmony_ci * because if some of the formats don't support negative numbers but 56962306a36Sopenharmony_ci * should be able to print a zero. Thus we need this extra test 57062306a36Sopenharmony_ci * for a negative number. 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_ci if (a->sign && mpi_cmp_ui(a, 0)) 57362306a36Sopenharmony_ci negative = 1; 57462306a36Sopenharmony_ci else 57562306a36Sopenharmony_ci negative = 0; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci len = buflen; 57862306a36Sopenharmony_ci *nwritten = 0; 57962306a36Sopenharmony_ci if (format == GCRYMPI_FMT_STD) { 58062306a36Sopenharmony_ci unsigned char *tmp; 58162306a36Sopenharmony_ci int extra = 0; 58262306a36Sopenharmony_ci unsigned int n; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci tmp = mpi_get_buffer(a, &n, NULL); 58562306a36Sopenharmony_ci if (!tmp) 58662306a36Sopenharmony_ci return -EINVAL; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (negative) { 58962306a36Sopenharmony_ci twocompl(tmp, n); 59062306a36Sopenharmony_ci if (!(*tmp & 0x80)) { 59162306a36Sopenharmony_ci /* Need to extend the sign. */ 59262306a36Sopenharmony_ci n++; 59362306a36Sopenharmony_ci extra = 2; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci } else if (n && (*tmp & 0x80)) { 59662306a36Sopenharmony_ci /* Positive but the high bit of the returned buffer is set. 59762306a36Sopenharmony_ci * Thus we need to print an extra leading 0x00 so that the 59862306a36Sopenharmony_ci * output is interpreted as a positive number. 59962306a36Sopenharmony_ci */ 60062306a36Sopenharmony_ci n++; 60162306a36Sopenharmony_ci extra = 1; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (buffer && n > len) { 60562306a36Sopenharmony_ci /* The provided buffer is too short. */ 60662306a36Sopenharmony_ci kfree(tmp); 60762306a36Sopenharmony_ci return -E2BIG; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci if (buffer) { 61062306a36Sopenharmony_ci unsigned char *s = buffer; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci if (extra == 1) 61362306a36Sopenharmony_ci *s++ = 0; 61462306a36Sopenharmony_ci else if (extra) 61562306a36Sopenharmony_ci *s++ = 0xff; 61662306a36Sopenharmony_ci memcpy(s, tmp, n-!!extra); 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci kfree(tmp); 61962306a36Sopenharmony_ci *nwritten = n; 62062306a36Sopenharmony_ci return 0; 62162306a36Sopenharmony_ci } else if (format == GCRYMPI_FMT_USG) { 62262306a36Sopenharmony_ci unsigned int n = (nbits + 7)/8; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* Note: We ignore the sign for this format. */ 62562306a36Sopenharmony_ci /* FIXME: for performance reasons we should put this into 62662306a36Sopenharmony_ci * mpi_aprint because we can then use the buffer directly. 62762306a36Sopenharmony_ci */ 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (buffer && n > len) 63062306a36Sopenharmony_ci return -E2BIG; 63162306a36Sopenharmony_ci if (buffer) { 63262306a36Sopenharmony_ci unsigned char *tmp; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci tmp = mpi_get_buffer(a, &n, NULL); 63562306a36Sopenharmony_ci if (!tmp) 63662306a36Sopenharmony_ci return -EINVAL; 63762306a36Sopenharmony_ci memcpy(buffer, tmp, n); 63862306a36Sopenharmony_ci kfree(tmp); 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci *nwritten = n; 64162306a36Sopenharmony_ci return 0; 64262306a36Sopenharmony_ci } else if (format == GCRYMPI_FMT_PGP) { 64362306a36Sopenharmony_ci unsigned int n = (nbits + 7)/8; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci /* The PGP format can only handle unsigned integers. */ 64662306a36Sopenharmony_ci if (negative) 64762306a36Sopenharmony_ci return -EINVAL; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (buffer && n+2 > len) 65062306a36Sopenharmony_ci return -E2BIG; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (buffer) { 65362306a36Sopenharmony_ci unsigned char *tmp; 65462306a36Sopenharmony_ci unsigned char *s = buffer; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci s[0] = nbits >> 8; 65762306a36Sopenharmony_ci s[1] = nbits; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci tmp = mpi_get_buffer(a, &n, NULL); 66062306a36Sopenharmony_ci if (!tmp) 66162306a36Sopenharmony_ci return -EINVAL; 66262306a36Sopenharmony_ci memcpy(s+2, tmp, n); 66362306a36Sopenharmony_ci kfree(tmp); 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci *nwritten = n+2; 66662306a36Sopenharmony_ci return 0; 66762306a36Sopenharmony_ci } else if (format == GCRYMPI_FMT_SSH) { 66862306a36Sopenharmony_ci unsigned char *tmp; 66962306a36Sopenharmony_ci int extra = 0; 67062306a36Sopenharmony_ci unsigned int n; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci tmp = mpi_get_buffer(a, &n, NULL); 67362306a36Sopenharmony_ci if (!tmp) 67462306a36Sopenharmony_ci return -EINVAL; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (negative) { 67762306a36Sopenharmony_ci twocompl(tmp, n); 67862306a36Sopenharmony_ci if (!(*tmp & 0x80)) { 67962306a36Sopenharmony_ci /* Need to extend the sign. */ 68062306a36Sopenharmony_ci n++; 68162306a36Sopenharmony_ci extra = 2; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci } else if (n && (*tmp & 0x80)) { 68462306a36Sopenharmony_ci n++; 68562306a36Sopenharmony_ci extra = 1; 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci if (buffer && n+4 > len) { 68962306a36Sopenharmony_ci kfree(tmp); 69062306a36Sopenharmony_ci return -E2BIG; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci if (buffer) { 69462306a36Sopenharmony_ci unsigned char *s = buffer; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci *s++ = n >> 24; 69762306a36Sopenharmony_ci *s++ = n >> 16; 69862306a36Sopenharmony_ci *s++ = n >> 8; 69962306a36Sopenharmony_ci *s++ = n; 70062306a36Sopenharmony_ci if (extra == 1) 70162306a36Sopenharmony_ci *s++ = 0; 70262306a36Sopenharmony_ci else if (extra) 70362306a36Sopenharmony_ci *s++ = 0xff; 70462306a36Sopenharmony_ci memcpy(s, tmp, n-!!extra); 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci kfree(tmp); 70762306a36Sopenharmony_ci *nwritten = 4+n; 70862306a36Sopenharmony_ci return 0; 70962306a36Sopenharmony_ci } else if (format == GCRYMPI_FMT_HEX) { 71062306a36Sopenharmony_ci unsigned char *tmp; 71162306a36Sopenharmony_ci int i; 71262306a36Sopenharmony_ci int extra = 0; 71362306a36Sopenharmony_ci unsigned int n = 0; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci tmp = mpi_get_buffer(a, &n, NULL); 71662306a36Sopenharmony_ci if (!tmp) 71762306a36Sopenharmony_ci return -EINVAL; 71862306a36Sopenharmony_ci if (!n || (*tmp & 0x80)) 71962306a36Sopenharmony_ci extra = 2; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci if (buffer && 2*n + extra + negative + 1 > len) { 72262306a36Sopenharmony_ci kfree(tmp); 72362306a36Sopenharmony_ci return -E2BIG; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci if (buffer) { 72662306a36Sopenharmony_ci unsigned char *s = buffer; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (negative) 72962306a36Sopenharmony_ci *s++ = '-'; 73062306a36Sopenharmony_ci if (extra) { 73162306a36Sopenharmony_ci *s++ = '0'; 73262306a36Sopenharmony_ci *s++ = '0'; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci for (i = 0; i < n; i++) { 73662306a36Sopenharmony_ci unsigned int c = tmp[i]; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci *s++ = (c >> 4) < 10 ? '0'+(c>>4) : 'A'+(c>>4)-10; 73962306a36Sopenharmony_ci c &= 15; 74062306a36Sopenharmony_ci *s++ = c < 10 ? '0'+c : 'A'+c-10; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci *s++ = 0; 74362306a36Sopenharmony_ci *nwritten = s - buffer; 74462306a36Sopenharmony_ci } else { 74562306a36Sopenharmony_ci *nwritten = 2*n + extra + negative + 1; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci kfree(tmp); 74862306a36Sopenharmony_ci return 0; 74962306a36Sopenharmony_ci } else 75062306a36Sopenharmony_ci return -EINVAL; 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_print); 753