6116fc4990da929e572b324bcfba8a5c01330999
[linux-2.6.git] / lib / mpi / mpicoder.c
1 /* mpicoder.c  -  Coder for the external representation of MPIs
2  * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include "mpi-internal.h"
22
23 #define DIM(v) (sizeof(v)/sizeof((v)[0]))
24 #define MAX_EXTERN_MPI_BITS 16384
25
26 static uint8_t asn[15] =        /* Object ID is 1.3.14.3.2.26 */
27 { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
28         0x02, 0x1a, 0x05, 0x00, 0x04, 0x14
29 };
30
31 MPI do_encode_md(const void *sha_buffer, unsigned nbits)
32 {
33         int nframe = (nbits + 7) / 8;
34         uint8_t *frame, *fr_pt;
35         int i = 0, n;
36         size_t asnlen = DIM(asn);
37         MPI a = MPI_NULL;
38
39         if (SHA1_DIGEST_LENGTH + asnlen + 4 > nframe)
40                 pr_info("MPI: can't encode a %d bit MD into a %d bits frame\n",
41                        (int)(SHA1_DIGEST_LENGTH * 8), (int)nbits);
42
43         /* We encode the MD in this way:
44          *
45          *       0  A PAD(n bytes)   0  ASN(asnlen bytes)  MD(len bytes)
46          *
47          * PAD consists of FF bytes.
48          */
49         frame = kmalloc(nframe, GFP_KERNEL);
50         if (!frame)
51                 return MPI_NULL;
52         n = 0;
53         frame[n++] = 0;
54         frame[n++] = 1;         /* block type */
55         i = nframe - SHA1_DIGEST_LENGTH - asnlen - 3;
56
57         if (i <= 1) {
58                 pr_info("MPI: message digest encoding failed\n");
59                 kfree(frame);
60                 return a;
61         }
62
63         memset(frame + n, 0xff, i);
64         n += i;
65         frame[n++] = 0;
66         memcpy(frame + n, &asn, asnlen);
67         n += asnlen;
68         memcpy(frame + n, sha_buffer, SHA1_DIGEST_LENGTH);
69         n += SHA1_DIGEST_LENGTH;
70
71         i = nframe;
72         fr_pt = frame;
73
74         if (n != nframe) {
75                 printk
76                     ("MPI: message digest encoding failed, frame length is wrong\n");
77                 kfree(frame);
78                 return a;
79         }
80
81         a = mpi_alloc((nframe + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB);
82         if (a)
83                 mpi_set_buffer(a, frame, nframe, 0);
84         kfree(frame);
85
86         return a;
87 }
88
89 MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread)
90 {
91         const uint8_t *buffer = xbuffer;
92         int i, j;
93         unsigned nbits, nbytes, nlimbs, nread = 0;
94         mpi_limb_t a;
95         MPI val = MPI_NULL;
96
97         if (*ret_nread < 2)
98                 goto leave;
99         nbits = buffer[0] << 8 | buffer[1];
100
101         if (nbits > MAX_EXTERN_MPI_BITS) {
102                 pr_info("MPI: mpi too large (%u bits)\n", nbits);
103                 goto leave;
104         }
105         buffer += 2;
106         nread = 2;
107
108         nbytes = (nbits + 7) / 8;
109         nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
110         val = mpi_alloc(nlimbs);
111         if (!val)
112                 return MPI_NULL;
113         i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
114         i %= BYTES_PER_MPI_LIMB;
115         val->nbits = nbits;
116         j = val->nlimbs = nlimbs;
117         val->sign = 0;
118         for (; j > 0; j--) {
119                 a = 0;
120                 for (; i < BYTES_PER_MPI_LIMB; i++) {
121                         if (++nread > *ret_nread) {
122                                 printk
123                                     ("MPI: mpi larger than buffer nread=%d ret_nread=%d\n",
124                                      nread, *ret_nread);
125                                 goto leave;
126                         }
127                         a <<= 8;
128                         a |= *buffer++;
129                 }
130                 i = 0;
131                 val->d[j - 1] = a;
132         }
133
134 leave:
135         *ret_nread = nread;
136         return val;
137 }
138 EXPORT_SYMBOL_GPL(mpi_read_from_buffer);
139
140 /****************
141  * Make an mpi from a character string.
142  */
143 int mpi_fromstr(MPI val, const char *str)
144 {
145         int hexmode = 0, sign = 0, prepend_zero = 0, i, j, c, c1, c2;
146         unsigned nbits, nbytes, nlimbs;
147         mpi_limb_t a;
148
149         if (*str == '-') {
150                 sign = 1;
151                 str++;
152         }
153         if (*str == '0' && str[1] == 'x')
154                 hexmode = 1;
155         else
156                 return -EINVAL; /* other bases are not yet supported */
157         str += 2;
158
159         nbits = strlen(str) * 4;
160         if (nbits % 8)
161                 prepend_zero = 1;
162         nbytes = (nbits + 7) / 8;
163         nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
164         if (val->alloced < nlimbs)
165                 if (!mpi_resize(val, nlimbs))
166                         return -ENOMEM;
167         i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
168         i %= BYTES_PER_MPI_LIMB;
169         j = val->nlimbs = nlimbs;
170         val->sign = sign;
171         for (; j > 0; j--) {
172                 a = 0;
173                 for (; i < BYTES_PER_MPI_LIMB; i++) {
174                         if (prepend_zero) {
175                                 c1 = '0';
176                                 prepend_zero = 0;
177                         } else
178                                 c1 = *str++;
179                         assert(c1);
180                         c2 = *str++;
181                         assert(c2);
182                         if (c1 >= '0' && c1 <= '9')
183                                 c = c1 - '0';
184                         else if (c1 >= 'a' && c1 <= 'f')
185                                 c = c1 - 'a' + 10;
186                         else if (c1 >= 'A' && c1 <= 'F')
187                                 c = c1 - 'A' + 10;
188                         else {
189                                 mpi_clear(val);
190                                 return 1;
191                         }
192                         c <<= 4;
193                         if (c2 >= '0' && c2 <= '9')
194                                 c |= c2 - '0';
195                         else if (c2 >= 'a' && c2 <= 'f')
196                                 c |= c2 - 'a' + 10;
197                         else if (c2 >= 'A' && c2 <= 'F')
198                                 c |= c2 - 'A' + 10;
199                         else {
200                                 mpi_clear(val);
201                                 return 1;
202                         }
203                         a <<= 8;
204                         a |= c;
205                 }
206                 i = 0;
207
208                 val->d[j - 1] = a;
209         }
210
211         return 0;
212 }
213 EXPORT_SYMBOL_GPL(mpi_fromstr);
214
215 /****************
216  * Special function to get the low 8 bytes from an mpi.
217  * This can be used as a keyid; KEYID is an 2 element array.
218  * Return the low 4 bytes.
219  */
220 u32 mpi_get_keyid(const MPI a, u32 *keyid)
221 {
222 #if BYTES_PER_MPI_LIMB == 4
223         if (keyid) {
224                 keyid[0] = a->nlimbs >= 2 ? a->d[1] : 0;
225                 keyid[1] = a->nlimbs >= 1 ? a->d[0] : 0;
226         }
227         return a->nlimbs >= 1 ? a->d[0] : 0;
228 #elif BYTES_PER_MPI_LIMB == 8
229         if (keyid) {
230                 keyid[0] = a->nlimbs ? (u32) (a->d[0] >> 32) : 0;
231                 keyid[1] = a->nlimbs ? (u32) (a->d[0] & 0xffffffff) : 0;
232         }
233         return a->nlimbs ? (u32) (a->d[0] & 0xffffffff) : 0;
234 #else
235 #error Make this function work with other LIMB sizes
236 #endif
237 }
238
239 /****************
240  * Return an allocated buffer with the MPI (msb first).
241  * NBYTES receives the length of this buffer. Caller must free the
242  * return string (This function does return a 0 byte buffer with NBYTES
243  * set to zero if the value of A is zero. If sign is not NULL, it will
244  * be set to the sign of the A.
245  */
246 void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign)
247 {
248         uint8_t *p, *buffer;
249         mpi_limb_t alimb;
250         int i;
251         unsigned int n;
252
253         if (sign)
254                 *sign = a->sign;
255         *nbytes = n = a->nlimbs * BYTES_PER_MPI_LIMB;
256         if (!n)
257                 n++;            /* avoid zero length allocation */
258         p = buffer = kmalloc(n, GFP_KERNEL);
259         if (!p)
260                 return NULL;
261
262         for (i = a->nlimbs - 1; i >= 0; i--) {
263                 alimb = a->d[i];
264 #if BYTES_PER_MPI_LIMB == 4
265                 *p++ = alimb >> 24;
266                 *p++ = alimb >> 16;
267                 *p++ = alimb >> 8;
268                 *p++ = alimb;
269 #elif BYTES_PER_MPI_LIMB == 8
270                 *p++ = alimb >> 56;
271                 *p++ = alimb >> 48;
272                 *p++ = alimb >> 40;
273                 *p++ = alimb >> 32;
274                 *p++ = alimb >> 24;
275                 *p++ = alimb >> 16;
276                 *p++ = alimb >> 8;
277                 *p++ = alimb;
278 #else
279 #error please implement for this limb size.
280 #endif
281         }
282
283         /* this is sub-optimal but we need to do the shift operation
284          * because the caller has to free the returned buffer */
285         for (p = buffer; !*p && *nbytes; p++, --*nbytes)
286                 ;
287         if (p != buffer)
288                 memmove(buffer, p, *nbytes);
289
290         return buffer;
291 }
292 EXPORT_SYMBOL_GPL(mpi_get_buffer);
293
294 /****************
295  * Use BUFFER to update MPI.
296  */
297 int mpi_set_buffer(MPI a, const void *xbuffer, unsigned nbytes, int sign)
298 {
299         const uint8_t *buffer = xbuffer, *p;
300         mpi_limb_t alimb;
301         int nlimbs;
302         int i;
303
304         nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
305         if (RESIZE_IF_NEEDED(a, nlimbs) < 0)
306                 return -ENOMEM;
307         a->sign = sign;
308
309         for (i = 0, p = buffer + nbytes - 1; p >= buffer + BYTES_PER_MPI_LIMB;) {
310 #if BYTES_PER_MPI_LIMB == 4
311                 alimb = (mpi_limb_t) *p--;
312                 alimb |= (mpi_limb_t) *p-- << 8;
313                 alimb |= (mpi_limb_t) *p-- << 16;
314                 alimb |= (mpi_limb_t) *p-- << 24;
315 #elif BYTES_PER_MPI_LIMB == 8
316                 alimb = (mpi_limb_t) *p--;
317                 alimb |= (mpi_limb_t) *p-- << 8;
318                 alimb |= (mpi_limb_t) *p-- << 16;
319                 alimb |= (mpi_limb_t) *p-- << 24;
320                 alimb |= (mpi_limb_t) *p-- << 32;
321                 alimb |= (mpi_limb_t) *p-- << 40;
322                 alimb |= (mpi_limb_t) *p-- << 48;
323                 alimb |= (mpi_limb_t) *p-- << 56;
324 #else
325 #error please implement for this limb size.
326 #endif
327                 a->d[i++] = alimb;
328         }
329         if (p >= buffer) {
330 #if BYTES_PER_MPI_LIMB == 4
331                 alimb = *p--;
332                 if (p >= buffer)
333                         alimb |= (mpi_limb_t) *p-- << 8;
334                 if (p >= buffer)
335                         alimb |= (mpi_limb_t) *p-- << 16;
336                 if (p >= buffer)
337                         alimb |= (mpi_limb_t) *p-- << 24;
338 #elif BYTES_PER_MPI_LIMB == 8
339                 alimb = (mpi_limb_t) *p--;
340                 if (p >= buffer)
341                         alimb |= (mpi_limb_t) *p-- << 8;
342                 if (p >= buffer)
343                         alimb |= (mpi_limb_t) *p-- << 16;
344                 if (p >= buffer)
345                         alimb |= (mpi_limb_t) *p-- << 24;
346                 if (p >= buffer)
347                         alimb |= (mpi_limb_t) *p-- << 32;
348                 if (p >= buffer)
349                         alimb |= (mpi_limb_t) *p-- << 40;
350                 if (p >= buffer)
351                         alimb |= (mpi_limb_t) *p-- << 48;
352                 if (p >= buffer)
353                         alimb |= (mpi_limb_t) *p-- << 56;
354 #else
355 #error please implement for this limb size.
356 #endif
357                 a->d[i++] = alimb;
358         }
359         a->nlimbs = i;
360
361         if (i != nlimbs) {
362                 pr_emerg("MPI: mpi_set_buffer: Assertion failed (%d != %d)", i,
363                        nlimbs);
364                 BUG();
365         }
366         return 0;
367 }
368 EXPORT_SYMBOL_GPL(mpi_set_buffer);