hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
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 {
....@@ -413,3 +520,232 @@
413520 return val;
414521 }
415522 EXPORT_SYMBOL_GPL(mpi_read_raw_from_sgl);
523
+
524
+/* Perform a two's complement operation on buffer P of size N bytes. */
525
+static void twocompl(unsigned char *p, unsigned int n)
526
+{
527
+ int i;
528
+
529
+ for (i = n-1; i >= 0 && !p[i]; i--)
530
+ ;
531
+ if (i >= 0) {
532
+ if ((p[i] & 0x01))
533
+ p[i] = (((p[i] ^ 0xfe) | 0x01) & 0xff);
534
+ else if ((p[i] & 0x02))
535
+ p[i] = (((p[i] ^ 0xfc) | 0x02) & 0xfe);
536
+ else if ((p[i] & 0x04))
537
+ p[i] = (((p[i] ^ 0xf8) | 0x04) & 0xfc);
538
+ else if ((p[i] & 0x08))
539
+ p[i] = (((p[i] ^ 0xf0) | 0x08) & 0xf8);
540
+ else if ((p[i] & 0x10))
541
+ p[i] = (((p[i] ^ 0xe0) | 0x10) & 0xf0);
542
+ else if ((p[i] & 0x20))
543
+ p[i] = (((p[i] ^ 0xc0) | 0x20) & 0xe0);
544
+ else if ((p[i] & 0x40))
545
+ p[i] = (((p[i] ^ 0x80) | 0x40) & 0xc0);
546
+ else
547
+ p[i] = 0x80;
548
+
549
+ for (i--; i >= 0; i--)
550
+ p[i] ^= 0xff;
551
+ }
552
+}
553
+
554
+int mpi_print(enum gcry_mpi_format format, unsigned char *buffer,
555
+ size_t buflen, size_t *nwritten, MPI a)
556
+{
557
+ unsigned int nbits = mpi_get_nbits(a);
558
+ size_t len;
559
+ size_t dummy_nwritten;
560
+ int negative;
561
+
562
+ if (!nwritten)
563
+ nwritten = &dummy_nwritten;
564
+
565
+ /* Libgcrypt does no always care to set clear the sign if the value
566
+ * is 0. For printing this is a bit of a surprise, in particular
567
+ * because if some of the formats don't support negative numbers but
568
+ * should be able to print a zero. Thus we need this extra test
569
+ * for a negative number.
570
+ */
571
+ if (a->sign && mpi_cmp_ui(a, 0))
572
+ negative = 1;
573
+ else
574
+ negative = 0;
575
+
576
+ len = buflen;
577
+ *nwritten = 0;
578
+ if (format == GCRYMPI_FMT_STD) {
579
+ unsigned char *tmp;
580
+ int extra = 0;
581
+ unsigned int n;
582
+
583
+ tmp = mpi_get_buffer(a, &n, NULL);
584
+ if (!tmp)
585
+ return -EINVAL;
586
+
587
+ if (negative) {
588
+ twocompl(tmp, n);
589
+ if (!(*tmp & 0x80)) {
590
+ /* Need to extend the sign. */
591
+ n++;
592
+ extra = 2;
593
+ }
594
+ } else if (n && (*tmp & 0x80)) {
595
+ /* Positive but the high bit of the returned buffer is set.
596
+ * Thus we need to print an extra leading 0x00 so that the
597
+ * output is interpreted as a positive number.
598
+ */
599
+ n++;
600
+ extra = 1;
601
+ }
602
+
603
+ if (buffer && n > len) {
604
+ /* The provided buffer is too short. */
605
+ kfree(tmp);
606
+ return -E2BIG;
607
+ }
608
+ if (buffer) {
609
+ unsigned char *s = buffer;
610
+
611
+ if (extra == 1)
612
+ *s++ = 0;
613
+ else if (extra)
614
+ *s++ = 0xff;
615
+ memcpy(s, tmp, n-!!extra);
616
+ }
617
+ kfree(tmp);
618
+ *nwritten = n;
619
+ return 0;
620
+ } else if (format == GCRYMPI_FMT_USG) {
621
+ unsigned int n = (nbits + 7)/8;
622
+
623
+ /* Note: We ignore the sign for this format. */
624
+ /* FIXME: for performance reasons we should put this into
625
+ * mpi_aprint because we can then use the buffer directly.
626
+ */
627
+
628
+ if (buffer && n > len)
629
+ return -E2BIG;
630
+ if (buffer) {
631
+ unsigned char *tmp;
632
+
633
+ tmp = mpi_get_buffer(a, &n, NULL);
634
+ if (!tmp)
635
+ return -EINVAL;
636
+ memcpy(buffer, tmp, n);
637
+ kfree(tmp);
638
+ }
639
+ *nwritten = n;
640
+ return 0;
641
+ } else if (format == GCRYMPI_FMT_PGP) {
642
+ unsigned int n = (nbits + 7)/8;
643
+
644
+ /* The PGP format can only handle unsigned integers. */
645
+ if (negative)
646
+ return -EINVAL;
647
+
648
+ if (buffer && n+2 > len)
649
+ return -E2BIG;
650
+
651
+ if (buffer) {
652
+ unsigned char *tmp;
653
+ unsigned char *s = buffer;
654
+
655
+ s[0] = nbits >> 8;
656
+ s[1] = nbits;
657
+
658
+ tmp = mpi_get_buffer(a, &n, NULL);
659
+ if (!tmp)
660
+ return -EINVAL;
661
+ memcpy(s+2, tmp, n);
662
+ kfree(tmp);
663
+ }
664
+ *nwritten = n+2;
665
+ return 0;
666
+ } else if (format == GCRYMPI_FMT_SSH) {
667
+ unsigned char *tmp;
668
+ int extra = 0;
669
+ unsigned int n;
670
+
671
+ tmp = mpi_get_buffer(a, &n, NULL);
672
+ if (!tmp)
673
+ return -EINVAL;
674
+
675
+ if (negative) {
676
+ twocompl(tmp, n);
677
+ if (!(*tmp & 0x80)) {
678
+ /* Need to extend the sign. */
679
+ n++;
680
+ extra = 2;
681
+ }
682
+ } else if (n && (*tmp & 0x80)) {
683
+ n++;
684
+ extra = 1;
685
+ }
686
+
687
+ if (buffer && n+4 > len) {
688
+ kfree(tmp);
689
+ return -E2BIG;
690
+ }
691
+
692
+ if (buffer) {
693
+ unsigned char *s = buffer;
694
+
695
+ *s++ = n >> 24;
696
+ *s++ = n >> 16;
697
+ *s++ = n >> 8;
698
+ *s++ = n;
699
+ if (extra == 1)
700
+ *s++ = 0;
701
+ else if (extra)
702
+ *s++ = 0xff;
703
+ memcpy(s, tmp, n-!!extra);
704
+ }
705
+ kfree(tmp);
706
+ *nwritten = 4+n;
707
+ return 0;
708
+ } else if (format == GCRYMPI_FMT_HEX) {
709
+ unsigned char *tmp;
710
+ int i;
711
+ int extra = 0;
712
+ unsigned int n = 0;
713
+
714
+ tmp = mpi_get_buffer(a, &n, NULL);
715
+ if (!tmp)
716
+ return -EINVAL;
717
+ if (!n || (*tmp & 0x80))
718
+ extra = 2;
719
+
720
+ if (buffer && 2*n + extra + negative + 1 > len) {
721
+ kfree(tmp);
722
+ return -E2BIG;
723
+ }
724
+ if (buffer) {
725
+ unsigned char *s = buffer;
726
+
727
+ if (negative)
728
+ *s++ = '-';
729
+ if (extra) {
730
+ *s++ = '0';
731
+ *s++ = '0';
732
+ }
733
+
734
+ for (i = 0; i < n; i++) {
735
+ unsigned int c = tmp[i];
736
+
737
+ *s++ = (c >> 4) < 10 ? '0'+(c>>4) : 'A'+(c>>4)-10;
738
+ c &= 15;
739
+ *s++ = c < 10 ? '0'+c : 'A'+c-10;
740
+ }
741
+ *s++ = 0;
742
+ *nwritten = s - buffer;
743
+ } else {
744
+ *nwritten = 2*n + extra + negative + 1;
745
+ }
746
+ kfree(tmp);
747
+ return 0;
748
+ } else
749
+ return -EINVAL;
750
+}
751
+EXPORT_SYMBOL_GPL(mpi_print);