hc
2024-05-10 23fa18eaa71266feff7ba8d83022d9e1cc83c65a
kernel/lib/mpi/mpicoder.c
....@@ -25,6 +25,7 @@
2525 #include <linux/string.h>
2626 #include "mpi-internal.h"
2727
28
+#define MAX_EXTERN_SCAN_BYTES (16*1024*1024)
2829 #define MAX_EXTERN_MPI_BITS 16384
2930
3031 /**
....@@ -108,6 +109,112 @@
108109 return val;
109110 }
110111 EXPORT_SYMBOL_GPL(mpi_read_from_buffer);
112
+
113
+/****************
114
+ * Fill the mpi VAL from the hex string in STR.
115
+ */
116
+int mpi_fromstr(MPI val, const char *str)
117
+{
118
+ int sign = 0;
119
+ int prepend_zero = 0;
120
+ int i, j, c, c1, c2;
121
+ unsigned int nbits, nbytes, nlimbs;
122
+ mpi_limb_t a;
123
+
124
+ if (*str == '-') {
125
+ sign = 1;
126
+ str++;
127
+ }
128
+
129
+ /* Skip optional hex prefix. */
130
+ if (*str == '0' && str[1] == 'x')
131
+ str += 2;
132
+
133
+ nbits = strlen(str);
134
+ if (nbits > MAX_EXTERN_SCAN_BYTES) {
135
+ mpi_clear(val);
136
+ return -EINVAL;
137
+ }
138
+ nbits *= 4;
139
+ if ((nbits % 8))
140
+ prepend_zero = 1;
141
+
142
+ nbytes = (nbits+7) / 8;
143
+ nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
144
+
145
+ if (val->alloced < nlimbs)
146
+ mpi_resize(val, nlimbs);
147
+
148
+ i = BYTES_PER_MPI_LIMB - (nbytes % BYTES_PER_MPI_LIMB);
149
+ i %= BYTES_PER_MPI_LIMB;
150
+ j = val->nlimbs = nlimbs;
151
+ val->sign = sign;
152
+ for (; j > 0; j--) {
153
+ a = 0;
154
+ for (; i < BYTES_PER_MPI_LIMB; i++) {
155
+ if (prepend_zero) {
156
+ c1 = '0';
157
+ prepend_zero = 0;
158
+ } else
159
+ c1 = *str++;
160
+
161
+ if (!c1) {
162
+ mpi_clear(val);
163
+ return -EINVAL;
164
+ }
165
+ c2 = *str++;
166
+ if (!c2) {
167
+ mpi_clear(val);
168
+ return -EINVAL;
169
+ }
170
+ if (c1 >= '0' && c1 <= '9')
171
+ c = c1 - '0';
172
+ else if (c1 >= 'a' && c1 <= 'f')
173
+ c = c1 - 'a' + 10;
174
+ else if (c1 >= 'A' && c1 <= 'F')
175
+ c = c1 - 'A' + 10;
176
+ else {
177
+ mpi_clear(val);
178
+ return -EINVAL;
179
+ }
180
+ c <<= 4;
181
+ if (c2 >= '0' && c2 <= '9')
182
+ c |= c2 - '0';
183
+ else if (c2 >= 'a' && c2 <= 'f')
184
+ c |= c2 - 'a' + 10;
185
+ else if (c2 >= 'A' && c2 <= 'F')
186
+ c |= c2 - 'A' + 10;
187
+ else {
188
+ mpi_clear(val);
189
+ return -EINVAL;
190
+ }
191
+ a <<= 8;
192
+ a |= c;
193
+ }
194
+ i = 0;
195
+ val->d[j-1] = a;
196
+ }
197
+
198
+ return 0;
199
+}
200
+EXPORT_SYMBOL_GPL(mpi_fromstr);
201
+
202
+MPI mpi_scanval(const char *string)
203
+{
204
+ MPI a;
205
+
206
+ a = mpi_alloc(0);
207
+ if (!a)
208
+ return NULL;
209
+
210
+ if (mpi_fromstr(a, string)) {
211
+ mpi_free(a);
212
+ return NULL;
213
+ }
214
+ mpi_normalize(a);
215
+ return a;
216
+}
217
+EXPORT_SYMBOL_GPL(mpi_scanval);
111218
112219 static int count_lzeros(MPI a)
113220 {
....@@ -397,7 +504,8 @@
397504
398505 while (sg_miter_next(&miter)) {
399506 buff = miter.addr;
400
- len = miter.length;
507
+ len = min_t(unsigned, miter.length, nbytes);
508
+ nbytes -= len;
401509
402510 for (x = 0; x < len; x++) {
403511 a <<= 8;
....@@ -413,3 +521,232 @@
413521 return val;
414522 }
415523 EXPORT_SYMBOL_GPL(mpi_read_raw_from_sgl);
524
+
525
+/* Perform a two's complement operation on buffer P of size N bytes. */
526
+static void twocompl(unsigned char *p, unsigned int n)
527
+{
528
+ int i;
529
+
530
+ for (i = n-1; i >= 0 && !p[i]; i--)
531
+ ;
532
+ if (i >= 0) {
533
+ if ((p[i] & 0x01))
534
+ p[i] = (((p[i] ^ 0xfe) | 0x01) & 0xff);
535
+ else if ((p[i] & 0x02))
536
+ p[i] = (((p[i] ^ 0xfc) | 0x02) & 0xfe);
537
+ else if ((p[i] & 0x04))
538
+ p[i] = (((p[i] ^ 0xf8) | 0x04) & 0xfc);
539
+ else if ((p[i] & 0x08))
540
+ p[i] = (((p[i] ^ 0xf0) | 0x08) & 0xf8);
541
+ else if ((p[i] & 0x10))
542
+ p[i] = (((p[i] ^ 0xe0) | 0x10) & 0xf0);
543
+ else if ((p[i] & 0x20))
544
+ p[i] = (((p[i] ^ 0xc0) | 0x20) & 0xe0);
545
+ else if ((p[i] & 0x40))
546
+ p[i] = (((p[i] ^ 0x80) | 0x40) & 0xc0);
547
+ else
548
+ p[i] = 0x80;
549
+
550
+ for (i--; i >= 0; i--)
551
+ p[i] ^= 0xff;
552
+ }
553
+}
554
+
555
+int mpi_print(enum gcry_mpi_format format, unsigned char *buffer,
556
+ size_t buflen, size_t *nwritten, MPI a)
557
+{
558
+ unsigned int nbits = mpi_get_nbits(a);
559
+ size_t len;
560
+ size_t dummy_nwritten;
561
+ int negative;
562
+
563
+ if (!nwritten)
564
+ nwritten = &dummy_nwritten;
565
+
566
+ /* Libgcrypt does no always care to set clear the sign if the value
567
+ * is 0. For printing this is a bit of a surprise, in particular
568
+ * because if some of the formats don't support negative numbers but
569
+ * should be able to print a zero. Thus we need this extra test
570
+ * for a negative number.
571
+ */
572
+ if (a->sign && mpi_cmp_ui(a, 0))
573
+ negative = 1;
574
+ else
575
+ negative = 0;
576
+
577
+ len = buflen;
578
+ *nwritten = 0;
579
+ if (format == GCRYMPI_FMT_STD) {
580
+ unsigned char *tmp;
581
+ int extra = 0;
582
+ unsigned int n;
583
+
584
+ tmp = mpi_get_buffer(a, &n, NULL);
585
+ if (!tmp)
586
+ return -EINVAL;
587
+
588
+ if (negative) {
589
+ twocompl(tmp, n);
590
+ if (!(*tmp & 0x80)) {
591
+ /* Need to extend the sign. */
592
+ n++;
593
+ extra = 2;
594
+ }
595
+ } else if (n && (*tmp & 0x80)) {
596
+ /* Positive but the high bit of the returned buffer is set.
597
+ * Thus we need to print an extra leading 0x00 so that the
598
+ * output is interpreted as a positive number.
599
+ */
600
+ n++;
601
+ extra = 1;
602
+ }
603
+
604
+ if (buffer && n > len) {
605
+ /* The provided buffer is too short. */
606
+ kfree(tmp);
607
+ return -E2BIG;
608
+ }
609
+ if (buffer) {
610
+ unsigned char *s = buffer;
611
+
612
+ if (extra == 1)
613
+ *s++ = 0;
614
+ else if (extra)
615
+ *s++ = 0xff;
616
+ memcpy(s, tmp, n-!!extra);
617
+ }
618
+ kfree(tmp);
619
+ *nwritten = n;
620
+ return 0;
621
+ } else if (format == GCRYMPI_FMT_USG) {
622
+ unsigned int n = (nbits + 7)/8;
623
+
624
+ /* Note: We ignore the sign for this format. */
625
+ /* FIXME: for performance reasons we should put this into
626
+ * mpi_aprint because we can then use the buffer directly.
627
+ */
628
+
629
+ if (buffer && n > len)
630
+ return -E2BIG;
631
+ if (buffer) {
632
+ unsigned char *tmp;
633
+
634
+ tmp = mpi_get_buffer(a, &n, NULL);
635
+ if (!tmp)
636
+ return -EINVAL;
637
+ memcpy(buffer, tmp, n);
638
+ kfree(tmp);
639
+ }
640
+ *nwritten = n;
641
+ return 0;
642
+ } else if (format == GCRYMPI_FMT_PGP) {
643
+ unsigned int n = (nbits + 7)/8;
644
+
645
+ /* The PGP format can only handle unsigned integers. */
646
+ if (negative)
647
+ return -EINVAL;
648
+
649
+ if (buffer && n+2 > len)
650
+ return -E2BIG;
651
+
652
+ if (buffer) {
653
+ unsigned char *tmp;
654
+ unsigned char *s = buffer;
655
+
656
+ s[0] = nbits >> 8;
657
+ s[1] = nbits;
658
+
659
+ tmp = mpi_get_buffer(a, &n, NULL);
660
+ if (!tmp)
661
+ return -EINVAL;
662
+ memcpy(s+2, tmp, n);
663
+ kfree(tmp);
664
+ }
665
+ *nwritten = n+2;
666
+ return 0;
667
+ } else if (format == GCRYMPI_FMT_SSH) {
668
+ unsigned char *tmp;
669
+ int extra = 0;
670
+ unsigned int n;
671
+
672
+ tmp = mpi_get_buffer(a, &n, NULL);
673
+ if (!tmp)
674
+ return -EINVAL;
675
+
676
+ if (negative) {
677
+ twocompl(tmp, n);
678
+ if (!(*tmp & 0x80)) {
679
+ /* Need to extend the sign. */
680
+ n++;
681
+ extra = 2;
682
+ }
683
+ } else if (n && (*tmp & 0x80)) {
684
+ n++;
685
+ extra = 1;
686
+ }
687
+
688
+ if (buffer && n+4 > len) {
689
+ kfree(tmp);
690
+ return -E2BIG;
691
+ }
692
+
693
+ if (buffer) {
694
+ unsigned char *s = buffer;
695
+
696
+ *s++ = n >> 24;
697
+ *s++ = n >> 16;
698
+ *s++ = n >> 8;
699
+ *s++ = n;
700
+ if (extra == 1)
701
+ *s++ = 0;
702
+ else if (extra)
703
+ *s++ = 0xff;
704
+ memcpy(s, tmp, n-!!extra);
705
+ }
706
+ kfree(tmp);
707
+ *nwritten = 4+n;
708
+ return 0;
709
+ } else if (format == GCRYMPI_FMT_HEX) {
710
+ unsigned char *tmp;
711
+ int i;
712
+ int extra = 0;
713
+ unsigned int n = 0;
714
+
715
+ tmp = mpi_get_buffer(a, &n, NULL);
716
+ if (!tmp)
717
+ return -EINVAL;
718
+ if (!n || (*tmp & 0x80))
719
+ extra = 2;
720
+
721
+ if (buffer && 2*n + extra + negative + 1 > len) {
722
+ kfree(tmp);
723
+ return -E2BIG;
724
+ }
725
+ if (buffer) {
726
+ unsigned char *s = buffer;
727
+
728
+ if (negative)
729
+ *s++ = '-';
730
+ if (extra) {
731
+ *s++ = '0';
732
+ *s++ = '0';
733
+ }
734
+
735
+ for (i = 0; i < n; i++) {
736
+ unsigned int c = tmp[i];
737
+
738
+ *s++ = (c >> 4) < 10 ? '0'+(c>>4) : 'A'+(c>>4)-10;
739
+ c &= 15;
740
+ *s++ = c < 10 ? '0'+c : 'A'+c-10;
741
+ }
742
+ *s++ = 0;
743
+ *nwritten = s - buffer;
744
+ } else {
745
+ *nwritten = 2*n + extra + negative + 1;
746
+ }
747
+ kfree(tmp);
748
+ return 0;
749
+ } else
750
+ return -EINVAL;
751
+}
752
+EXPORT_SYMBOL_GPL(mpi_print);