Tizen 2.0 Release
[external/libgnutls26.git] / lib / auth_srp_sb64.c
1 /*
2  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008, 2010 Free Software
3  * Foundation, Inc.
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
9  * The GnuTLS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA
23  *
24  */
25
26 #include <gnutls_int.h>
27 #include <gnutls_errors.h>
28 #include <gnutls_datum.h>
29 #include <auth_srp_passwd.h>
30
31 #ifdef ENABLE_SRP
32
33 /* this a modified base64 for srp !!! 
34  * It seems that everybody makes an own base64 conversion.
35  */
36 static const uint8_t b64table[] =
37   "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
38
39 static const uint8_t asciitable[128] = {
40   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
41   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
42   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
43   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
44   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
45   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
46   0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
47   0xff, 0xff, 0xff, 0xff, 0x3e, 0x3f,
48   0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
49   0x06, 0x07, 0x08, 0x09, 0xff, 0xff,
50   0xff, 0xff, 0xff, 0xff, 0xff, 0x0a,
51   0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
52   0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
53   0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
54   0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
55   0x23, 0xff, 0xff, 0xff, 0xff, 0xff,
56   0xff, 0x24, 0x25, 0x26, 0x27, 0x28,
57   0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
58   0x2f, 0x30, 0x31, 0x32, 0x33, 0x34,
59   0x35, 0x36, 0x37, 0x38, 0x39, 0x3a,
60   0x3b, 0x3c, 0x3d, 0xff, 0xff, 0xff,
61   0xff, 0xff
62 };
63
64 inline static int
65 encode (uint8_t * result, const uint8_t * rdata, int left)
66 {
67
68   int data_len;
69   int c, ret = 4;
70   uint8_t data[3];
71
72   if (left > 3)
73     data_len = 3;
74   else
75     data_len = left;
76
77   data[0] = data[1] = data[2] = 0;
78   memcpy (data, rdata, data_len);
79
80   switch (data_len)
81     {
82     case 3:
83       result[0] = b64table[((data[0] & 0xfc) >> 2)];
84       result[1] =
85         b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
86                   ((data[1] & 0xf0) >> 4))];
87       result[2] =
88         b64table[((((data[1] & 0x0f) << 2) & 0xff) |
89                   ((data[2] & 0xc0) >> 6))];
90       result[3] = b64table[(data[2] & 0x3f) & 0xff];
91       break;
92     case 2:
93       if ((c = ((data[0] & 0xf0) >> 4)) != 0)
94         {
95           result[0] = b64table[c];
96           result[1] =
97             b64table[((((data[0] & 0x0f) << 2) & 0xff) |
98                       ((data[1] & 0xc0) >> 6))];
99           result[2] = b64table[(data[1] & 0x3f) & 0xff];
100           result[3] = '\0';
101           ret -= 1;
102         }
103       else
104         {
105           if ((c = ((data[0] & 0x0f) << 2) | ((data[1] & 0xc0) >> 6)) != 0)
106             {
107               result[0] = b64table[c];
108               result[1] = b64table[data[1] & 0x3f];
109               result[2] = '\0';
110               result[3] = '\0';
111               ret -= 2;
112             }
113           else
114             {
115               result[0] = b64table[data[0] & 0x3f];
116               result[1] = '\0';
117               result[2] = '\0';
118               result[3] = '\0';
119               ret -= 3;
120             }
121         }
122       break;
123     case 1:
124       if ((c = ((data[0] & 0xc0) >> 6)) != 0)
125         {
126           result[0] = b64table[c];
127           result[1] = b64table[(data[0] & 0x3f) & 0xff];
128           result[2] = '\0';
129           result[3] = '\0';
130           ret -= 2;
131         }
132       else
133         {
134           result[0] = b64table[(data[0] & 0x3f) & 0xff];
135           result[1] = '\0';
136           result[2] = '\0';
137           result[3] = '\0';
138           ret -= 3;
139         }
140       break;
141     default:
142       return -1;
143     }
144
145   return ret;
146
147 }
148
149 /* encodes data and puts the result into result (locally allocated)
150  * The result_size is the return value
151  */
152 static int
153 _gnutls_sbase64_encode (uint8_t * data, size_t data_size, uint8_t ** result)
154 {
155   unsigned i, j;
156   int ret, tmp;
157   opaque tmpres[4];
158   int mod = data_size % 3;
159
160   ret = mod;
161   if (ret != 0)
162     ret = 4;
163   else
164     ret = 0;
165
166   ret += (data_size * 4) / 3;
167
168   (*result) = gnutls_calloc (1, ret + 1);
169   if ((*result) == NULL)
170     return -1;
171
172   i = j = 0;
173 /* encode the bytes that are not a multiple of 3 
174  */
175   if (mod > 0)
176     {
177       tmp = encode (tmpres, &data[0], mod);
178       if (tmp < 0)
179         {
180           gnutls_free ((*result));
181           return tmp;
182         }
183
184       memcpy (&(*result)[0], tmpres, tmp);
185       i = mod;
186       j = tmp;
187
188     }
189 /* encode the rest
190  */
191   for (; i < data_size; i += 3, j += 4)
192     {
193       tmp = encode (tmpres, &data[i], data_size - i);
194       if (tmp < 0)
195         {
196           gnutls_free ((*result));
197           return tmp;
198         }
199       memcpy (&(*result)[j], tmpres, tmp);
200     }
201
202   return strlen (*result);
203 }
204
205
206 /* data must be 4 bytes
207  * result should be 3 bytes
208  */
209 #define TOASCII(c) (c < 127 ? asciitable[c] : 0xff)
210 inline static int
211 decode (uint8_t * result, const uint8_t * data)
212 {
213   uint8_t a1, a2;
214   int ret = 3;
215
216   memset (result, 0, 3);
217
218   a1 = TOASCII (data[3]);
219   a2 = TOASCII (data[2]);
220   if (a1 != 0xff)
221     result[2] = a1 & 0xff;
222   else
223     return -1;
224   if (a2 != 0xff)
225     result[2] |= ((a2 & 0x03) << 6) & 0xff;
226
227   a1 = a2;
228   a2 = TOASCII (data[1]);
229   if (a1 != 0xff)
230     result[1] = ((a1 & 0x3c) >> 2);
231   if (a2 != 0xff)
232     result[1] |= ((a2 & 0x0f) << 4);
233   else if (a1 == 0xff || result[1] == 0)
234     ret--;
235
236   a1 = a2;
237   a2 = TOASCII (data[0]);
238   if (a1 != 0xff)
239     result[0] = (((a1 & 0x30) >> 4) & 0xff);
240   if (a2 != 0xff)
241     result[0] |= ((a2 << 2) & 0xff);
242   else if (a1 == 0xff || result[0] == 0)
243     ret--;
244
245   return ret;
246 }
247
248 /* decodes data and puts the result into result (locally allocated)
249  * The result_size is the return value.
250  * That function does not ignore newlines tabs etc. You should remove them
251  * before calling it.
252  */
253 int
254 _gnutls_sbase64_decode (uint8_t * data, size_t idata_size, uint8_t ** result)
255 {
256   unsigned i, j;
257   int ret, left;
258   int data_size, tmp;
259   uint8_t datrev[4];
260   uint8_t tmpres[3];
261
262   data_size = (idata_size / 4) * 4;
263   left = idata_size % 4;
264
265   ret = (data_size / 4) * 3;
266
267   if (left > 0)
268     ret += 3;
269
270   (*result) = gnutls_malloc (ret + 1);
271   if ((*result) == NULL)
272     return -1;
273
274   /* the first "block" is treated with special care */
275   tmp = 0;
276   if (left > 0)
277     {
278       memset (datrev, 0, 4);
279       memcpy (&datrev[4 - left], data, left);
280
281       tmp = decode (tmpres, datrev);
282       if (tmp < 0)
283         {
284           gnutls_free ((*result));
285           *result = NULL;
286           return tmp;
287         }
288
289       memcpy (*result, &tmpres[3 - tmp], tmp);
290       if (tmp < 3)
291         ret -= (3 - tmp);
292     }
293
294   /* rest data */
295   for (i = left, j = tmp; i < idata_size; i += 4)
296     {
297       tmp = decode (tmpres, &data[i]);
298       if (tmp < 0)
299         {
300           gnutls_free ((*result));
301           *result = NULL;
302           return tmp;
303         }
304       memcpy (&(*result)[j], tmpres, tmp);
305       if (tmp < 3)
306         ret -= (3 - tmp);
307       j += 3;
308     }
309
310   return ret;
311 }
312
313 /**
314  * gnutls_srp_base64_encode:
315  * @data: contain the raw data
316  * @result: the place where base64 data will be copied
317  * @result_size: holds the size of the result
318  *
319  * This function will convert the given data to printable data, using
320  * the base64 encoding, as used in the libsrp.  This is the encoding
321  * used in SRP password files.  If the provided buffer is not long
322  * enough GNUTLS_E_SHORT_MEMORY_BUFFER is returned.
323  *
324  * Warning!  This base64 encoding is not the "standard" encoding, so
325  * do not use it for non-SRP purposes.
326  *
327  * Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not
328  * long enough, or 0 on success.
329  **/
330 int
331 gnutls_srp_base64_encode (const gnutls_datum_t * data, char *result,
332                           size_t * result_size)
333 {
334   opaque *ret;
335   int size;
336
337   size = _gnutls_sbase64_encode (data->data, data->size, &ret);
338   if (size < 0)
339     return size;
340
341   if (result == NULL || *result_size < (size_t) size)
342     {
343       gnutls_free (ret);
344       *result_size = size;
345       return GNUTLS_E_SHORT_MEMORY_BUFFER;
346     }
347   else
348     {
349       memcpy (result, ret, size);
350       gnutls_free (ret);
351       *result_size = size;
352     }
353
354   return 0;
355 }
356
357 /**
358  * gnutls_srp_base64_encode_alloc:
359  * @data: contains the raw data
360  * @result: will hold the newly allocated encoded data
361  *
362  * This function will convert the given data to printable data, using
363  * the base64 encoding.  This is the encoding used in SRP password
364  * files.  This function will allocate the required memory to hold
365  * the encoded data.
366  *
367  * You should use gnutls_free() to free the returned data.
368  *
369  * Warning!  This base64 encoding is not the "standard" encoding, so
370  * do not use it for non-SRP purposes.
371  *
372  * Returns: 0 on success, or an error code.
373  **/
374 int
375 gnutls_srp_base64_encode_alloc (const gnutls_datum_t * data,
376                                 gnutls_datum_t * result)
377 {
378   opaque *ret;
379   int size;
380
381   size = _gnutls_sbase64_encode (data->data, data->size, &ret);
382   if (size < 0)
383     return size;
384
385   if (result == NULL)
386     {
387       gnutls_free (ret);
388       return GNUTLS_E_INVALID_REQUEST;
389     }
390   else
391     {
392       result->data = ret;
393       result->size = size;
394     }
395
396   return 0;
397 }
398
399 /**
400  * gnutls_srp_base64_decode:
401  * @b64_data: contain the encoded data
402  * @result: the place where decoded data will be copied
403  * @result_size: holds the size of the result
404  *
405  * This function will decode the given encoded data, using the base64
406  * encoding found in libsrp.
407  *
408  * Note that @b64_data should be null terminated.
409  *
410  * Warning!  This base64 encoding is not the "standard" encoding, so
411  * do not use it for non-SRP purposes.
412  *
413  * Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not
414  * long enough, or 0 on success.
415  **/
416 int
417 gnutls_srp_base64_decode (const gnutls_datum_t * b64_data, char *result,
418                           size_t * result_size)
419 {
420   opaque *ret;
421   int size;
422
423   size = _gnutls_sbase64_decode (b64_data->data, b64_data->size, &ret);
424   if (size < 0)
425     return size;
426
427   if (result == NULL || *result_size < (size_t) size)
428     {
429       gnutls_free (ret);
430       *result_size = size;
431       return GNUTLS_E_SHORT_MEMORY_BUFFER;
432     }
433   else
434     {
435       memcpy (result, ret, size);
436       gnutls_free (ret);
437       *result_size = size;
438     }
439
440   return 0;
441 }
442
443 /**
444  * gnutls_srp_base64_decode_alloc:
445  * @b64_data: contains the encoded data
446  * @result: the place where decoded data lie
447  *
448  * This function will decode the given encoded data. The decoded data
449  * will be allocated, and stored into result.  It will decode using
450  * the base64 algorithm as used in libsrp.
451  *
452  * You should use gnutls_free() to free the returned data.
453  *
454  * Warning!  This base64 encoding is not the "standard" encoding, so
455  * do not use it for non-SRP purposes.
456  *
457  * Returns: 0 on success, or an error code.
458  **/
459 int
460 gnutls_srp_base64_decode_alloc (const gnutls_datum_t * b64_data,
461                                 gnutls_datum_t * result)
462 {
463   opaque *ret;
464   int size;
465
466   size = _gnutls_sbase64_decode (b64_data->data, b64_data->size, &ret);
467   if (size < 0)
468     return size;
469
470   if (result == NULL)
471     {
472       gnutls_free (ret);
473       return GNUTLS_E_INVALID_REQUEST;
474     }
475   else
476     {
477       result->data = ret;
478       result->size = size;
479     }
480
481   return 0;
482 }
483
484 #endif /* ENABLE_SRP */