Skip to content

Commit 2d4d1ee

Browse files
tstrukherbertx
authored andcommitted
lib/mpi: Add mpi sgl helpers
Add mpi_read_raw_from_sgl and mpi_write_to_sgl helpers. Signed-off-by: Tadeusz Struk <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
1 parent 9ad92bd commit 2d4d1ee

File tree

2 files changed

+200
-0
lines changed

2 files changed

+200
-0
lines changed

include/linux/mpi.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#define G10_MPI_H
3232

3333
#include <linux/types.h>
34+
#include <linux/scatterlist.h>
3435

3536
/* DSI defines */
3637

@@ -78,13 +79,16 @@ void mpi_swap(MPI a, MPI b);
7879
MPI do_encode_md(const void *sha_buffer, unsigned nbits);
7980
MPI mpi_read_raw_data(const void *xbuffer, size_t nbytes);
8081
MPI mpi_read_from_buffer(const void *buffer, unsigned *ret_nread);
82+
MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int len);
8183
int mpi_fromstr(MPI val, const char *str);
8284
u32 mpi_get_keyid(MPI a, u32 *keyid);
8385
void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign);
8486
int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes,
8587
int *sign);
8688
void *mpi_get_secure_buffer(MPI a, unsigned *nbytes, int *sign);
8789
int mpi_set_buffer(MPI a, const void *buffer, unsigned nbytes, int sign);
90+
int mpi_write_to_sgl(MPI a, struct scatterlist *sg, unsigned *nbytes,
91+
int *sign);
8892

8993
#define log_mpidump g10_log_mpidump
9094

lib/mpi/mpicoder.c

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,199 @@ int mpi_set_buffer(MPI a, const void *xbuffer, unsigned nbytes, int sign)
319319
return 0;
320320
}
321321
EXPORT_SYMBOL_GPL(mpi_set_buffer);
322+
323+
/**
324+
* mpi_write_to_sgl() - Funnction exports MPI to an sgl (msb first)
325+
*
326+
* This function works in the same way as the mpi_read_buffer, but it
327+
* takes an sgl instead of u8 * buf.
328+
*
329+
* @a: a multi precision integer
330+
* @sgl: scatterlist to write to. Needs to be at least
331+
* mpi_get_size(a) long.
332+
* @nbytes: in/out param - it has the be set to the maximum number of
333+
* bytes that can be written to sgl. This has to be at least
334+
* the size of the integer a. On return it receives the actual
335+
* length of the data written.
336+
* @sign: if not NULL, it will be set to the sign of a.
337+
*
338+
* Return: 0 on success or error code in case of error
339+
*/
340+
int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes,
341+
int *sign)
342+
{
343+
u8 *p, *p2;
344+
mpi_limb_t alimb, alimb2;
345+
unsigned int n = mpi_get_size(a);
346+
int i, x, y = 0, lzeros = 0, buf_len;
347+
348+
if (!nbytes || *nbytes < n)
349+
return -EINVAL;
350+
351+
if (sign)
352+
*sign = a->sign;
353+
354+
p = (void *)&a->d[a->nlimbs] - 1;
355+
356+
for (i = a->nlimbs * sizeof(alimb) - 1; i >= 0; i--, p--) {
357+
if (!*p)
358+
lzeros++;
359+
else
360+
break;
361+
}
362+
363+
*nbytes = n - lzeros;
364+
buf_len = sgl->length;
365+
p2 = sg_virt(sgl);
366+
367+
for (i = a->nlimbs - 1; i >= 0; i--) {
368+
alimb = a->d[i];
369+
p = (u8 *)&alimb2;
370+
#if BYTES_PER_MPI_LIMB == 4
371+
*p++ = alimb >> 24;
372+
*p++ = alimb >> 16;
373+
*p++ = alimb >> 8;
374+
*p++ = alimb;
375+
#elif BYTES_PER_MPI_LIMB == 8
376+
*p++ = alimb >> 56;
377+
*p++ = alimb >> 48;
378+
*p++ = alimb >> 40;
379+
*p++ = alimb >> 32;
380+
*p++ = alimb >> 24;
381+
*p++ = alimb >> 16;
382+
*p++ = alimb >> 8;
383+
*p++ = alimb;
384+
#else
385+
#error please implement for this limb size.
386+
#endif
387+
if (lzeros > 0) {
388+
if (lzeros >= sizeof(alimb)) {
389+
p -= sizeof(alimb);
390+
continue;
391+
} else {
392+
mpi_limb_t *limb1 = (void *)p - sizeof(alimb);
393+
mpi_limb_t *limb2 = (void *)p - sizeof(alimb)
394+
+ lzeros;
395+
*limb1 = *limb2;
396+
p -= lzeros;
397+
y = lzeros;
398+
}
399+
lzeros -= sizeof(alimb);
400+
}
401+
402+
p = p - (sizeof(alimb) - y);
403+
404+
for (x = 0; x < sizeof(alimb) - y; x++) {
405+
if (!buf_len) {
406+
sgl = sg_next(sgl);
407+
if (!sgl)
408+
return -EINVAL;
409+
buf_len = sgl->length;
410+
p2 = sg_virt(sgl);
411+
}
412+
*p2++ = *p++;
413+
buf_len--;
414+
}
415+
y = 0;
416+
}
417+
return 0;
418+
}
419+
EXPORT_SYMBOL_GPL(mpi_write_to_sgl);
420+
421+
/*
422+
* mpi_read_raw_from_sgl() - Function allocates an MPI and populates it with
423+
* data from the sgl
424+
*
425+
* This function works in the same way as the mpi_read_raw_data, but it
426+
* takes an sgl instead of void * buffer. i.e. it allocates
427+
* a new MPI and reads the content of the sgl to the MPI.
428+
*
429+
* @sgl: scatterlist to read from
430+
* @len: number of bytes to read
431+
*
432+
* Return: Pointer to a new MPI or NULL on error
433+
*/
434+
MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int len)
435+
{
436+
struct scatterlist *sg;
437+
int x, i, j, z, lzeros, ents;
438+
unsigned int nbits, nlimbs, nbytes;
439+
mpi_limb_t a;
440+
MPI val = NULL;
441+
442+
lzeros = 0;
443+
ents = sg_nents(sgl);
444+
445+
for_each_sg(sgl, sg, ents, i) {
446+
const u8 *buff = sg_virt(sg);
447+
int len = sg->length;
448+
449+
while (len-- && !*buff++)
450+
lzeros++;
451+
452+
if (len && *buff)
453+
break;
454+
455+
ents--;
456+
lzeros = 0;
457+
}
458+
459+
sgl = sg;
460+
461+
if (!ents)
462+
nbytes = 0;
463+
else
464+
nbytes = len - lzeros;
465+
466+
nbits = nbytes * 8;
467+
if (nbits > MAX_EXTERN_MPI_BITS) {
468+
pr_info("MPI: mpi too large (%u bits)\n", nbits);
469+
return NULL;
470+
}
471+
472+
if (nbytes > 0)
473+
nbits -= count_leading_zeros(*(u8 *)(sg_virt(sgl) + lzeros));
474+
else
475+
nbits = 0;
476+
477+
nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB);
478+
val = mpi_alloc(nlimbs);
479+
if (!val)
480+
return NULL;
481+
482+
val->nbits = nbits;
483+
val->sign = 0;
484+
val->nlimbs = nlimbs;
485+
486+
if (nbytes == 0)
487+
return val;
488+
489+
j = nlimbs - 1;
490+
a = 0;
491+
z = 0;
492+
x = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
493+
x %= BYTES_PER_MPI_LIMB;
494+
495+
for_each_sg(sgl, sg, ents, i) {
496+
const u8 *buffer = sg_virt(sg) + lzeros;
497+
int len = sg->length - lzeros;
498+
int buf_shift = x;
499+
500+
if (sg_is_last(sg) && (len % BYTES_PER_MPI_LIMB))
501+
len += BYTES_PER_MPI_LIMB - (len % BYTES_PER_MPI_LIMB);
502+
503+
for (; x < len + buf_shift; x++) {
504+
a <<= 8;
505+
a |= *buffer++;
506+
if (((z + x + 1) % BYTES_PER_MPI_LIMB) == 0) {
507+
val->d[j--] = a;
508+
a = 0;
509+
}
510+
}
511+
z += x;
512+
x = 0;
513+
lzeros = 0;
514+
}
515+
return val;
516+
}
517+
EXPORT_SYMBOL_GPL(mpi_read_raw_from_sgl);

0 commit comments

Comments
 (0)