18c2ecf20Sopenharmony_ci/* mpicoder.c - Coder for the external representation of MPIs 28c2ecf20Sopenharmony_ci * Copyright (C) 1998, 1999 Free Software Foundation, Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is part of GnuPG. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * GnuPG is free software; you can redistribute it and/or modify 78c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 88c2ecf20Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 98c2ecf20Sopenharmony_ci * (at your option) any later version. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * GnuPG is distributed in the hope that it will be useful, 128c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 138c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 148c2ecf20Sopenharmony_ci * GNU General Public License for more details. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License 178c2ecf20Sopenharmony_ci * along with this program; if not, write to the Free Software 188c2ecf20Sopenharmony_ci * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/bitops.h> 228c2ecf20Sopenharmony_ci#include <linux/count_zeros.h> 238c2ecf20Sopenharmony_ci#include <linux/byteorder/generic.h> 248c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 258c2ecf20Sopenharmony_ci#include <linux/string.h> 268c2ecf20Sopenharmony_ci#include "mpi-internal.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define MAX_EXTERN_SCAN_BYTES (16*1024*1024) 298c2ecf20Sopenharmony_ci#define MAX_EXTERN_MPI_BITS 16384 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/** 328c2ecf20Sopenharmony_ci * mpi_read_raw_data - Read a raw byte stream as a positive integer 338c2ecf20Sopenharmony_ci * @xbuffer: The data to read 348c2ecf20Sopenharmony_ci * @nbytes: The amount of data to read 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ciMPI mpi_read_raw_data(const void *xbuffer, size_t nbytes) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci const uint8_t *buffer = xbuffer; 398c2ecf20Sopenharmony_ci int i, j; 408c2ecf20Sopenharmony_ci unsigned nbits, nlimbs; 418c2ecf20Sopenharmony_ci mpi_limb_t a; 428c2ecf20Sopenharmony_ci MPI val = NULL; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci while (nbytes > 0 && buffer[0] == 0) { 458c2ecf20Sopenharmony_ci buffer++; 468c2ecf20Sopenharmony_ci nbytes--; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci nbits = nbytes * 8; 508c2ecf20Sopenharmony_ci if (nbits > MAX_EXTERN_MPI_BITS) { 518c2ecf20Sopenharmony_ci pr_info("MPI: mpi too large (%u bits)\n", nbits); 528c2ecf20Sopenharmony_ci return NULL; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci if (nbytes > 0) 558c2ecf20Sopenharmony_ci nbits -= count_leading_zeros(buffer[0]) - (BITS_PER_LONG - 8); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB); 588c2ecf20Sopenharmony_ci val = mpi_alloc(nlimbs); 598c2ecf20Sopenharmony_ci if (!val) 608c2ecf20Sopenharmony_ci return NULL; 618c2ecf20Sopenharmony_ci val->nbits = nbits; 628c2ecf20Sopenharmony_ci val->sign = 0; 638c2ecf20Sopenharmony_ci val->nlimbs = nlimbs; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (nbytes > 0) { 668c2ecf20Sopenharmony_ci i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; 678c2ecf20Sopenharmony_ci i %= BYTES_PER_MPI_LIMB; 688c2ecf20Sopenharmony_ci for (j = nlimbs; j > 0; j--) { 698c2ecf20Sopenharmony_ci a = 0; 708c2ecf20Sopenharmony_ci for (; i < BYTES_PER_MPI_LIMB; i++) { 718c2ecf20Sopenharmony_ci a <<= 8; 728c2ecf20Sopenharmony_ci a |= *buffer++; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci i = 0; 758c2ecf20Sopenharmony_ci val->d[j - 1] = a; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci return val; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_read_raw_data); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ciMPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci const uint8_t *buffer = xbuffer; 858c2ecf20Sopenharmony_ci unsigned int nbits, nbytes; 868c2ecf20Sopenharmony_ci MPI val; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (*ret_nread < 2) 898c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 908c2ecf20Sopenharmony_ci nbits = buffer[0] << 8 | buffer[1]; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (nbits > MAX_EXTERN_MPI_BITS) { 938c2ecf20Sopenharmony_ci pr_info("MPI: mpi too large (%u bits)\n", nbits); 948c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci nbytes = DIV_ROUND_UP(nbits, 8); 988c2ecf20Sopenharmony_ci if (nbytes + 2 > *ret_nread) { 998c2ecf20Sopenharmony_ci pr_info("MPI: mpi larger than buffer nbytes=%u ret_nread=%u\n", 1008c2ecf20Sopenharmony_ci nbytes, *ret_nread); 1018c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci val = mpi_read_raw_data(buffer + 2, nbytes); 1058c2ecf20Sopenharmony_ci if (!val) 1068c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci *ret_nread = nbytes + 2; 1098c2ecf20Sopenharmony_ci return val; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_read_from_buffer); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/**************** 1148c2ecf20Sopenharmony_ci * Fill the mpi VAL from the hex string in STR. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ciint mpi_fromstr(MPI val, const char *str) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci int sign = 0; 1198c2ecf20Sopenharmony_ci int prepend_zero = 0; 1208c2ecf20Sopenharmony_ci int i, j, c, c1, c2; 1218c2ecf20Sopenharmony_ci unsigned int nbits, nbytes, nlimbs; 1228c2ecf20Sopenharmony_ci mpi_limb_t a; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (*str == '-') { 1258c2ecf20Sopenharmony_ci sign = 1; 1268c2ecf20Sopenharmony_ci str++; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* Skip optional hex prefix. */ 1308c2ecf20Sopenharmony_ci if (*str == '0' && str[1] == 'x') 1318c2ecf20Sopenharmony_ci str += 2; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci nbits = strlen(str); 1348c2ecf20Sopenharmony_ci if (nbits > MAX_EXTERN_SCAN_BYTES) { 1358c2ecf20Sopenharmony_ci mpi_clear(val); 1368c2ecf20Sopenharmony_ci return -EINVAL; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci nbits *= 4; 1398c2ecf20Sopenharmony_ci if ((nbits % 8)) 1408c2ecf20Sopenharmony_ci prepend_zero = 1; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci nbytes = (nbits+7) / 8; 1438c2ecf20Sopenharmony_ci nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (val->alloced < nlimbs) 1468c2ecf20Sopenharmony_ci mpi_resize(val, nlimbs); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci i = BYTES_PER_MPI_LIMB - (nbytes % BYTES_PER_MPI_LIMB); 1498c2ecf20Sopenharmony_ci i %= BYTES_PER_MPI_LIMB; 1508c2ecf20Sopenharmony_ci j = val->nlimbs = nlimbs; 1518c2ecf20Sopenharmony_ci val->sign = sign; 1528c2ecf20Sopenharmony_ci for (; j > 0; j--) { 1538c2ecf20Sopenharmony_ci a = 0; 1548c2ecf20Sopenharmony_ci for (; i < BYTES_PER_MPI_LIMB; i++) { 1558c2ecf20Sopenharmony_ci if (prepend_zero) { 1568c2ecf20Sopenharmony_ci c1 = '0'; 1578c2ecf20Sopenharmony_ci prepend_zero = 0; 1588c2ecf20Sopenharmony_ci } else 1598c2ecf20Sopenharmony_ci c1 = *str++; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (!c1) { 1628c2ecf20Sopenharmony_ci mpi_clear(val); 1638c2ecf20Sopenharmony_ci return -EINVAL; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci c2 = *str++; 1668c2ecf20Sopenharmony_ci if (!c2) { 1678c2ecf20Sopenharmony_ci mpi_clear(val); 1688c2ecf20Sopenharmony_ci return -EINVAL; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci if (c1 >= '0' && c1 <= '9') 1718c2ecf20Sopenharmony_ci c = c1 - '0'; 1728c2ecf20Sopenharmony_ci else if (c1 >= 'a' && c1 <= 'f') 1738c2ecf20Sopenharmony_ci c = c1 - 'a' + 10; 1748c2ecf20Sopenharmony_ci else if (c1 >= 'A' && c1 <= 'F') 1758c2ecf20Sopenharmony_ci c = c1 - 'A' + 10; 1768c2ecf20Sopenharmony_ci else { 1778c2ecf20Sopenharmony_ci mpi_clear(val); 1788c2ecf20Sopenharmony_ci return -EINVAL; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci c <<= 4; 1818c2ecf20Sopenharmony_ci if (c2 >= '0' && c2 <= '9') 1828c2ecf20Sopenharmony_ci c |= c2 - '0'; 1838c2ecf20Sopenharmony_ci else if (c2 >= 'a' && c2 <= 'f') 1848c2ecf20Sopenharmony_ci c |= c2 - 'a' + 10; 1858c2ecf20Sopenharmony_ci else if (c2 >= 'A' && c2 <= 'F') 1868c2ecf20Sopenharmony_ci c |= c2 - 'A' + 10; 1878c2ecf20Sopenharmony_ci else { 1888c2ecf20Sopenharmony_ci mpi_clear(val); 1898c2ecf20Sopenharmony_ci return -EINVAL; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci a <<= 8; 1928c2ecf20Sopenharmony_ci a |= c; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci i = 0; 1958c2ecf20Sopenharmony_ci val->d[j-1] = a; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return 0; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_fromstr); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ciMPI mpi_scanval(const char *string) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci MPI a; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci a = mpi_alloc(0); 2078c2ecf20Sopenharmony_ci if (!a) 2088c2ecf20Sopenharmony_ci return NULL; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (mpi_fromstr(a, string)) { 2118c2ecf20Sopenharmony_ci mpi_free(a); 2128c2ecf20Sopenharmony_ci return NULL; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci mpi_normalize(a); 2158c2ecf20Sopenharmony_ci return a; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_scanval); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic int count_lzeros(MPI a) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci mpi_limb_t alimb; 2228c2ecf20Sopenharmony_ci int i, lzeros = 0; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci for (i = a->nlimbs - 1; i >= 0; i--) { 2258c2ecf20Sopenharmony_ci alimb = a->d[i]; 2268c2ecf20Sopenharmony_ci if (alimb == 0) { 2278c2ecf20Sopenharmony_ci lzeros += sizeof(mpi_limb_t); 2288c2ecf20Sopenharmony_ci } else { 2298c2ecf20Sopenharmony_ci lzeros += count_leading_zeros(alimb) / 8; 2308c2ecf20Sopenharmony_ci break; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci return lzeros; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci/** 2378c2ecf20Sopenharmony_ci * mpi_read_buffer() - read MPI to a bufer provided by user (msb first) 2388c2ecf20Sopenharmony_ci * 2398c2ecf20Sopenharmony_ci * @a: a multi precision integer 2408c2ecf20Sopenharmony_ci * @buf: bufer to which the output will be written to. Needs to be at 2418c2ecf20Sopenharmony_ci * leaset mpi_get_size(a) long. 2428c2ecf20Sopenharmony_ci * @buf_len: size of the buf. 2438c2ecf20Sopenharmony_ci * @nbytes: receives the actual length of the data written on success and 2448c2ecf20Sopenharmony_ci * the data to-be-written on -EOVERFLOW in case buf_len was too 2458c2ecf20Sopenharmony_ci * small. 2468c2ecf20Sopenharmony_ci * @sign: if not NULL, it will be set to the sign of a. 2478c2ecf20Sopenharmony_ci * 2488c2ecf20Sopenharmony_ci * Return: 0 on success or error code in case of error 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_ciint mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes, 2518c2ecf20Sopenharmony_ci int *sign) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci uint8_t *p; 2548c2ecf20Sopenharmony_ci#if BYTES_PER_MPI_LIMB == 4 2558c2ecf20Sopenharmony_ci __be32 alimb; 2568c2ecf20Sopenharmony_ci#elif BYTES_PER_MPI_LIMB == 8 2578c2ecf20Sopenharmony_ci __be64 alimb; 2588c2ecf20Sopenharmony_ci#else 2598c2ecf20Sopenharmony_ci#error please implement for this limb size. 2608c2ecf20Sopenharmony_ci#endif 2618c2ecf20Sopenharmony_ci unsigned int n = mpi_get_size(a); 2628c2ecf20Sopenharmony_ci int i, lzeros; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (!buf || !nbytes) 2658c2ecf20Sopenharmony_ci return -EINVAL; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (sign) 2688c2ecf20Sopenharmony_ci *sign = a->sign; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci lzeros = count_lzeros(a); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (buf_len < n - lzeros) { 2738c2ecf20Sopenharmony_ci *nbytes = n - lzeros; 2748c2ecf20Sopenharmony_ci return -EOVERFLOW; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci p = buf; 2788c2ecf20Sopenharmony_ci *nbytes = n - lzeros; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci for (i = a->nlimbs - 1 - lzeros / BYTES_PER_MPI_LIMB, 2818c2ecf20Sopenharmony_ci lzeros %= BYTES_PER_MPI_LIMB; 2828c2ecf20Sopenharmony_ci i >= 0; i--) { 2838c2ecf20Sopenharmony_ci#if BYTES_PER_MPI_LIMB == 4 2848c2ecf20Sopenharmony_ci alimb = cpu_to_be32(a->d[i]); 2858c2ecf20Sopenharmony_ci#elif BYTES_PER_MPI_LIMB == 8 2868c2ecf20Sopenharmony_ci alimb = cpu_to_be64(a->d[i]); 2878c2ecf20Sopenharmony_ci#else 2888c2ecf20Sopenharmony_ci#error please implement for this limb size. 2898c2ecf20Sopenharmony_ci#endif 2908c2ecf20Sopenharmony_ci memcpy(p, (u8 *)&alimb + lzeros, BYTES_PER_MPI_LIMB - lzeros); 2918c2ecf20Sopenharmony_ci p += BYTES_PER_MPI_LIMB - lzeros; 2928c2ecf20Sopenharmony_ci lzeros = 0; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci return 0; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_read_buffer); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/* 2998c2ecf20Sopenharmony_ci * mpi_get_buffer() - Returns an allocated buffer with the MPI (msb first). 3008c2ecf20Sopenharmony_ci * Caller must free the return string. 3018c2ecf20Sopenharmony_ci * This function does return a 0 byte buffer with nbytes set to zero if the 3028c2ecf20Sopenharmony_ci * value of A is zero. 3038c2ecf20Sopenharmony_ci * 3048c2ecf20Sopenharmony_ci * @a: a multi precision integer. 3058c2ecf20Sopenharmony_ci * @nbytes: receives the length of this buffer. 3068c2ecf20Sopenharmony_ci * @sign: if not NULL, it will be set to the sign of the a. 3078c2ecf20Sopenharmony_ci * 3088c2ecf20Sopenharmony_ci * Return: Pointer to MPI buffer or NULL on error 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_civoid *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci uint8_t *buf; 3138c2ecf20Sopenharmony_ci unsigned int n; 3148c2ecf20Sopenharmony_ci int ret; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (!nbytes) 3178c2ecf20Sopenharmony_ci return NULL; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci n = mpi_get_size(a); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (!n) 3228c2ecf20Sopenharmony_ci n++; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci buf = kmalloc(n, GFP_KERNEL); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (!buf) 3278c2ecf20Sopenharmony_ci return NULL; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci ret = mpi_read_buffer(a, buf, n, nbytes, sign); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (ret) { 3328c2ecf20Sopenharmony_ci kfree(buf); 3338c2ecf20Sopenharmony_ci return NULL; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci return buf; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_get_buffer); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci/** 3408c2ecf20Sopenharmony_ci * mpi_write_to_sgl() - Funnction exports MPI to an sgl (msb first) 3418c2ecf20Sopenharmony_ci * 3428c2ecf20Sopenharmony_ci * This function works in the same way as the mpi_read_buffer, but it 3438c2ecf20Sopenharmony_ci * takes an sgl instead of u8 * buf. 3448c2ecf20Sopenharmony_ci * 3458c2ecf20Sopenharmony_ci * @a: a multi precision integer 3468c2ecf20Sopenharmony_ci * @sgl: scatterlist to write to. Needs to be at least 3478c2ecf20Sopenharmony_ci * mpi_get_size(a) long. 3488c2ecf20Sopenharmony_ci * @nbytes: the number of bytes to write. Leading bytes will be 3498c2ecf20Sopenharmony_ci * filled with zero. 3508c2ecf20Sopenharmony_ci * @sign: if not NULL, it will be set to the sign of a. 3518c2ecf20Sopenharmony_ci * 3528c2ecf20Sopenharmony_ci * Return: 0 on success or error code in case of error 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_ciint mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned nbytes, 3558c2ecf20Sopenharmony_ci int *sign) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci u8 *p, *p2; 3588c2ecf20Sopenharmony_ci#if BYTES_PER_MPI_LIMB == 4 3598c2ecf20Sopenharmony_ci __be32 alimb; 3608c2ecf20Sopenharmony_ci#elif BYTES_PER_MPI_LIMB == 8 3618c2ecf20Sopenharmony_ci __be64 alimb; 3628c2ecf20Sopenharmony_ci#else 3638c2ecf20Sopenharmony_ci#error please implement for this limb size. 3648c2ecf20Sopenharmony_ci#endif 3658c2ecf20Sopenharmony_ci unsigned int n = mpi_get_size(a); 3668c2ecf20Sopenharmony_ci struct sg_mapping_iter miter; 3678c2ecf20Sopenharmony_ci int i, x, buf_len; 3688c2ecf20Sopenharmony_ci int nents; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (sign) 3718c2ecf20Sopenharmony_ci *sign = a->sign; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (nbytes < n) 3748c2ecf20Sopenharmony_ci return -EOVERFLOW; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci nents = sg_nents_for_len(sgl, nbytes); 3778c2ecf20Sopenharmony_ci if (nents < 0) 3788c2ecf20Sopenharmony_ci return -EINVAL; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci sg_miter_start(&miter, sgl, nents, SG_MITER_ATOMIC | SG_MITER_TO_SG); 3818c2ecf20Sopenharmony_ci sg_miter_next(&miter); 3828c2ecf20Sopenharmony_ci buf_len = miter.length; 3838c2ecf20Sopenharmony_ci p2 = miter.addr; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci while (nbytes > n) { 3868c2ecf20Sopenharmony_ci i = min_t(unsigned, nbytes - n, buf_len); 3878c2ecf20Sopenharmony_ci memset(p2, 0, i); 3888c2ecf20Sopenharmony_ci p2 += i; 3898c2ecf20Sopenharmony_ci nbytes -= i; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci buf_len -= i; 3928c2ecf20Sopenharmony_ci if (!buf_len) { 3938c2ecf20Sopenharmony_ci sg_miter_next(&miter); 3948c2ecf20Sopenharmony_ci buf_len = miter.length; 3958c2ecf20Sopenharmony_ci p2 = miter.addr; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci for (i = a->nlimbs - 1; i >= 0; i--) { 4008c2ecf20Sopenharmony_ci#if BYTES_PER_MPI_LIMB == 4 4018c2ecf20Sopenharmony_ci alimb = a->d[i] ? cpu_to_be32(a->d[i]) : 0; 4028c2ecf20Sopenharmony_ci#elif BYTES_PER_MPI_LIMB == 8 4038c2ecf20Sopenharmony_ci alimb = a->d[i] ? cpu_to_be64(a->d[i]) : 0; 4048c2ecf20Sopenharmony_ci#else 4058c2ecf20Sopenharmony_ci#error please implement for this limb size. 4068c2ecf20Sopenharmony_ci#endif 4078c2ecf20Sopenharmony_ci p = (u8 *)&alimb; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci for (x = 0; x < sizeof(alimb); x++) { 4108c2ecf20Sopenharmony_ci *p2++ = *p++; 4118c2ecf20Sopenharmony_ci if (!--buf_len) { 4128c2ecf20Sopenharmony_ci sg_miter_next(&miter); 4138c2ecf20Sopenharmony_ci buf_len = miter.length; 4148c2ecf20Sopenharmony_ci p2 = miter.addr; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci sg_miter_stop(&miter); 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_write_to_sgl); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci/* 4258c2ecf20Sopenharmony_ci * mpi_read_raw_from_sgl() - Function allocates an MPI and populates it with 4268c2ecf20Sopenharmony_ci * data from the sgl 4278c2ecf20Sopenharmony_ci * 4288c2ecf20Sopenharmony_ci * This function works in the same way as the mpi_read_raw_data, but it 4298c2ecf20Sopenharmony_ci * takes an sgl instead of void * buffer. i.e. it allocates 4308c2ecf20Sopenharmony_ci * a new MPI and reads the content of the sgl to the MPI. 4318c2ecf20Sopenharmony_ci * 4328c2ecf20Sopenharmony_ci * @sgl: scatterlist to read from 4338c2ecf20Sopenharmony_ci * @nbytes: number of bytes to read 4348c2ecf20Sopenharmony_ci * 4358c2ecf20Sopenharmony_ci * Return: Pointer to a new MPI or NULL on error 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_ciMPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int nbytes) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct sg_mapping_iter miter; 4408c2ecf20Sopenharmony_ci unsigned int nbits, nlimbs; 4418c2ecf20Sopenharmony_ci int x, j, z, lzeros, ents; 4428c2ecf20Sopenharmony_ci unsigned int len; 4438c2ecf20Sopenharmony_ci const u8 *buff; 4448c2ecf20Sopenharmony_ci mpi_limb_t a; 4458c2ecf20Sopenharmony_ci MPI val = NULL; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci ents = sg_nents_for_len(sgl, nbytes); 4488c2ecf20Sopenharmony_ci if (ents < 0) 4498c2ecf20Sopenharmony_ci return NULL; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci sg_miter_start(&miter, sgl, ents, SG_MITER_ATOMIC | SG_MITER_FROM_SG); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci lzeros = 0; 4548c2ecf20Sopenharmony_ci len = 0; 4558c2ecf20Sopenharmony_ci while (nbytes > 0) { 4568c2ecf20Sopenharmony_ci while (len && !*buff) { 4578c2ecf20Sopenharmony_ci lzeros++; 4588c2ecf20Sopenharmony_ci len--; 4598c2ecf20Sopenharmony_ci buff++; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (len && *buff) 4638c2ecf20Sopenharmony_ci break; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci sg_miter_next(&miter); 4668c2ecf20Sopenharmony_ci buff = miter.addr; 4678c2ecf20Sopenharmony_ci len = miter.length; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci nbytes -= lzeros; 4708c2ecf20Sopenharmony_ci lzeros = 0; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci miter.consumed = lzeros; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci nbytes -= lzeros; 4768c2ecf20Sopenharmony_ci nbits = nbytes * 8; 4778c2ecf20Sopenharmony_ci if (nbits > MAX_EXTERN_MPI_BITS) { 4788c2ecf20Sopenharmony_ci sg_miter_stop(&miter); 4798c2ecf20Sopenharmony_ci pr_info("MPI: mpi too large (%u bits)\n", nbits); 4808c2ecf20Sopenharmony_ci return NULL; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (nbytes > 0) 4848c2ecf20Sopenharmony_ci nbits -= count_leading_zeros(*buff) - (BITS_PER_LONG - 8); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci sg_miter_stop(&miter); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB); 4898c2ecf20Sopenharmony_ci val = mpi_alloc(nlimbs); 4908c2ecf20Sopenharmony_ci if (!val) 4918c2ecf20Sopenharmony_ci return NULL; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci val->nbits = nbits; 4948c2ecf20Sopenharmony_ci val->sign = 0; 4958c2ecf20Sopenharmony_ci val->nlimbs = nlimbs; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (nbytes == 0) 4988c2ecf20Sopenharmony_ci return val; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci j = nlimbs - 1; 5018c2ecf20Sopenharmony_ci a = 0; 5028c2ecf20Sopenharmony_ci z = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; 5038c2ecf20Sopenharmony_ci z %= BYTES_PER_MPI_LIMB; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci while (sg_miter_next(&miter)) { 5068c2ecf20Sopenharmony_ci buff = miter.addr; 5078c2ecf20Sopenharmony_ci len = min_t(unsigned, miter.length, nbytes); 5088c2ecf20Sopenharmony_ci nbytes -= len; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci for (x = 0; x < len; x++) { 5118c2ecf20Sopenharmony_ci a <<= 8; 5128c2ecf20Sopenharmony_ci a |= *buff++; 5138c2ecf20Sopenharmony_ci if (((z + x + 1) % BYTES_PER_MPI_LIMB) == 0) { 5148c2ecf20Sopenharmony_ci val->d[j--] = a; 5158c2ecf20Sopenharmony_ci a = 0; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci z += x; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return val; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_read_raw_from_sgl); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci/* Perform a two's complement operation on buffer P of size N bytes. */ 5268c2ecf20Sopenharmony_cistatic void twocompl(unsigned char *p, unsigned int n) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci int i; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci for (i = n-1; i >= 0 && !p[i]; i--) 5318c2ecf20Sopenharmony_ci ; 5328c2ecf20Sopenharmony_ci if (i >= 0) { 5338c2ecf20Sopenharmony_ci if ((p[i] & 0x01)) 5348c2ecf20Sopenharmony_ci p[i] = (((p[i] ^ 0xfe) | 0x01) & 0xff); 5358c2ecf20Sopenharmony_ci else if ((p[i] & 0x02)) 5368c2ecf20Sopenharmony_ci p[i] = (((p[i] ^ 0xfc) | 0x02) & 0xfe); 5378c2ecf20Sopenharmony_ci else if ((p[i] & 0x04)) 5388c2ecf20Sopenharmony_ci p[i] = (((p[i] ^ 0xf8) | 0x04) & 0xfc); 5398c2ecf20Sopenharmony_ci else if ((p[i] & 0x08)) 5408c2ecf20Sopenharmony_ci p[i] = (((p[i] ^ 0xf0) | 0x08) & 0xf8); 5418c2ecf20Sopenharmony_ci else if ((p[i] & 0x10)) 5428c2ecf20Sopenharmony_ci p[i] = (((p[i] ^ 0xe0) | 0x10) & 0xf0); 5438c2ecf20Sopenharmony_ci else if ((p[i] & 0x20)) 5448c2ecf20Sopenharmony_ci p[i] = (((p[i] ^ 0xc0) | 0x20) & 0xe0); 5458c2ecf20Sopenharmony_ci else if ((p[i] & 0x40)) 5468c2ecf20Sopenharmony_ci p[i] = (((p[i] ^ 0x80) | 0x40) & 0xc0); 5478c2ecf20Sopenharmony_ci else 5488c2ecf20Sopenharmony_ci p[i] = 0x80; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) 5518c2ecf20Sopenharmony_ci p[i] ^= 0xff; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ciint mpi_print(enum gcry_mpi_format format, unsigned char *buffer, 5568c2ecf20Sopenharmony_ci size_t buflen, size_t *nwritten, MPI a) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci unsigned int nbits = mpi_get_nbits(a); 5598c2ecf20Sopenharmony_ci size_t len; 5608c2ecf20Sopenharmony_ci size_t dummy_nwritten; 5618c2ecf20Sopenharmony_ci int negative; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (!nwritten) 5648c2ecf20Sopenharmony_ci nwritten = &dummy_nwritten; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci /* Libgcrypt does no always care to set clear the sign if the value 5678c2ecf20Sopenharmony_ci * is 0. For printing this is a bit of a surprise, in particular 5688c2ecf20Sopenharmony_ci * because if some of the formats don't support negative numbers but 5698c2ecf20Sopenharmony_ci * should be able to print a zero. Thus we need this extra test 5708c2ecf20Sopenharmony_ci * for a negative number. 5718c2ecf20Sopenharmony_ci */ 5728c2ecf20Sopenharmony_ci if (a->sign && mpi_cmp_ui(a, 0)) 5738c2ecf20Sopenharmony_ci negative = 1; 5748c2ecf20Sopenharmony_ci else 5758c2ecf20Sopenharmony_ci negative = 0; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci len = buflen; 5788c2ecf20Sopenharmony_ci *nwritten = 0; 5798c2ecf20Sopenharmony_ci if (format == GCRYMPI_FMT_STD) { 5808c2ecf20Sopenharmony_ci unsigned char *tmp; 5818c2ecf20Sopenharmony_ci int extra = 0; 5828c2ecf20Sopenharmony_ci unsigned int n; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci tmp = mpi_get_buffer(a, &n, NULL); 5858c2ecf20Sopenharmony_ci if (!tmp) 5868c2ecf20Sopenharmony_ci return -EINVAL; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (negative) { 5898c2ecf20Sopenharmony_ci twocompl(tmp, n); 5908c2ecf20Sopenharmony_ci if (!(*tmp & 0x80)) { 5918c2ecf20Sopenharmony_ci /* Need to extend the sign. */ 5928c2ecf20Sopenharmony_ci n++; 5938c2ecf20Sopenharmony_ci extra = 2; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci } else if (n && (*tmp & 0x80)) { 5968c2ecf20Sopenharmony_ci /* Positive but the high bit of the returned buffer is set. 5978c2ecf20Sopenharmony_ci * Thus we need to print an extra leading 0x00 so that the 5988c2ecf20Sopenharmony_ci * output is interpreted as a positive number. 5998c2ecf20Sopenharmony_ci */ 6008c2ecf20Sopenharmony_ci n++; 6018c2ecf20Sopenharmony_ci extra = 1; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (buffer && n > len) { 6058c2ecf20Sopenharmony_ci /* The provided buffer is too short. */ 6068c2ecf20Sopenharmony_ci kfree(tmp); 6078c2ecf20Sopenharmony_ci return -E2BIG; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci if (buffer) { 6108c2ecf20Sopenharmony_ci unsigned char *s = buffer; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (extra == 1) 6138c2ecf20Sopenharmony_ci *s++ = 0; 6148c2ecf20Sopenharmony_ci else if (extra) 6158c2ecf20Sopenharmony_ci *s++ = 0xff; 6168c2ecf20Sopenharmony_ci memcpy(s, tmp, n-!!extra); 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci kfree(tmp); 6198c2ecf20Sopenharmony_ci *nwritten = n; 6208c2ecf20Sopenharmony_ci return 0; 6218c2ecf20Sopenharmony_ci } else if (format == GCRYMPI_FMT_USG) { 6228c2ecf20Sopenharmony_ci unsigned int n = (nbits + 7)/8; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* Note: We ignore the sign for this format. */ 6258c2ecf20Sopenharmony_ci /* FIXME: for performance reasons we should put this into 6268c2ecf20Sopenharmony_ci * mpi_aprint because we can then use the buffer directly. 6278c2ecf20Sopenharmony_ci */ 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (buffer && n > len) 6308c2ecf20Sopenharmony_ci return -E2BIG; 6318c2ecf20Sopenharmony_ci if (buffer) { 6328c2ecf20Sopenharmony_ci unsigned char *tmp; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci tmp = mpi_get_buffer(a, &n, NULL); 6358c2ecf20Sopenharmony_ci if (!tmp) 6368c2ecf20Sopenharmony_ci return -EINVAL; 6378c2ecf20Sopenharmony_ci memcpy(buffer, tmp, n); 6388c2ecf20Sopenharmony_ci kfree(tmp); 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci *nwritten = n; 6418c2ecf20Sopenharmony_ci return 0; 6428c2ecf20Sopenharmony_ci } else if (format == GCRYMPI_FMT_PGP) { 6438c2ecf20Sopenharmony_ci unsigned int n = (nbits + 7)/8; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* The PGP format can only handle unsigned integers. */ 6468c2ecf20Sopenharmony_ci if (negative) 6478c2ecf20Sopenharmony_ci return -EINVAL; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci if (buffer && n+2 > len) 6508c2ecf20Sopenharmony_ci return -E2BIG; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci if (buffer) { 6538c2ecf20Sopenharmony_ci unsigned char *tmp; 6548c2ecf20Sopenharmony_ci unsigned char *s = buffer; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci s[0] = nbits >> 8; 6578c2ecf20Sopenharmony_ci s[1] = nbits; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci tmp = mpi_get_buffer(a, &n, NULL); 6608c2ecf20Sopenharmony_ci if (!tmp) 6618c2ecf20Sopenharmony_ci return -EINVAL; 6628c2ecf20Sopenharmony_ci memcpy(s+2, tmp, n); 6638c2ecf20Sopenharmony_ci kfree(tmp); 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci *nwritten = n+2; 6668c2ecf20Sopenharmony_ci return 0; 6678c2ecf20Sopenharmony_ci } else if (format == GCRYMPI_FMT_SSH) { 6688c2ecf20Sopenharmony_ci unsigned char *tmp; 6698c2ecf20Sopenharmony_ci int extra = 0; 6708c2ecf20Sopenharmony_ci unsigned int n; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci tmp = mpi_get_buffer(a, &n, NULL); 6738c2ecf20Sopenharmony_ci if (!tmp) 6748c2ecf20Sopenharmony_ci return -EINVAL; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci if (negative) { 6778c2ecf20Sopenharmony_ci twocompl(tmp, n); 6788c2ecf20Sopenharmony_ci if (!(*tmp & 0x80)) { 6798c2ecf20Sopenharmony_ci /* Need to extend the sign. */ 6808c2ecf20Sopenharmony_ci n++; 6818c2ecf20Sopenharmony_ci extra = 2; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci } else if (n && (*tmp & 0x80)) { 6848c2ecf20Sopenharmony_ci n++; 6858c2ecf20Sopenharmony_ci extra = 1; 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci if (buffer && n+4 > len) { 6898c2ecf20Sopenharmony_ci kfree(tmp); 6908c2ecf20Sopenharmony_ci return -E2BIG; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if (buffer) { 6948c2ecf20Sopenharmony_ci unsigned char *s = buffer; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci *s++ = n >> 24; 6978c2ecf20Sopenharmony_ci *s++ = n >> 16; 6988c2ecf20Sopenharmony_ci *s++ = n >> 8; 6998c2ecf20Sopenharmony_ci *s++ = n; 7008c2ecf20Sopenharmony_ci if (extra == 1) 7018c2ecf20Sopenharmony_ci *s++ = 0; 7028c2ecf20Sopenharmony_ci else if (extra) 7038c2ecf20Sopenharmony_ci *s++ = 0xff; 7048c2ecf20Sopenharmony_ci memcpy(s, tmp, n-!!extra); 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci kfree(tmp); 7078c2ecf20Sopenharmony_ci *nwritten = 4+n; 7088c2ecf20Sopenharmony_ci return 0; 7098c2ecf20Sopenharmony_ci } else if (format == GCRYMPI_FMT_HEX) { 7108c2ecf20Sopenharmony_ci unsigned char *tmp; 7118c2ecf20Sopenharmony_ci int i; 7128c2ecf20Sopenharmony_ci int extra = 0; 7138c2ecf20Sopenharmony_ci unsigned int n = 0; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci tmp = mpi_get_buffer(a, &n, NULL); 7168c2ecf20Sopenharmony_ci if (!tmp) 7178c2ecf20Sopenharmony_ci return -EINVAL; 7188c2ecf20Sopenharmony_ci if (!n || (*tmp & 0x80)) 7198c2ecf20Sopenharmony_ci extra = 2; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (buffer && 2*n + extra + negative + 1 > len) { 7228c2ecf20Sopenharmony_ci kfree(tmp); 7238c2ecf20Sopenharmony_ci return -E2BIG; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci if (buffer) { 7268c2ecf20Sopenharmony_ci unsigned char *s = buffer; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if (negative) 7298c2ecf20Sopenharmony_ci *s++ = '-'; 7308c2ecf20Sopenharmony_ci if (extra) { 7318c2ecf20Sopenharmony_ci *s++ = '0'; 7328c2ecf20Sopenharmony_ci *s++ = '0'; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 7368c2ecf20Sopenharmony_ci unsigned int c = tmp[i]; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci *s++ = (c >> 4) < 10 ? '0'+(c>>4) : 'A'+(c>>4)-10; 7398c2ecf20Sopenharmony_ci c &= 15; 7408c2ecf20Sopenharmony_ci *s++ = c < 10 ? '0'+c : 'A'+c-10; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci *s++ = 0; 7438c2ecf20Sopenharmony_ci *nwritten = s - buffer; 7448c2ecf20Sopenharmony_ci } else { 7458c2ecf20Sopenharmony_ci *nwritten = 2*n + extra + negative + 1; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci kfree(tmp); 7488c2ecf20Sopenharmony_ci return 0; 7498c2ecf20Sopenharmony_ci } else 7508c2ecf20Sopenharmony_ci return -EINVAL; 7518c2ecf20Sopenharmony_ci} 7528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_print); 753