cleaned up errno handling.
[gnutls.git] / lib / auth / srp_sb64.c
blob4298f333422d101e3e0059cc9df60e79ac3e9f4d
1 /*
2 * Copyright (C) 2001-2012 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
8 * The GnuTLS is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 #include <gnutls_int.h>
24 #include <gnutls_errors.h>
25 #include <gnutls_datum.h>
26 #include <auth/srp_passwd.h>
28 #ifdef ENABLE_SRP
30 /* this a modified base64 for srp !!!
31 * It seems that everybody makes an own base64 conversion.
33 static const uint8_t b64table[] =
34 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
36 static const uint8_t asciitable[128] = {
37 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
38 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
39 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
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, 0x3e, 0x3f,
45 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
46 0x06, 0x07, 0x08, 0x09, 0xff, 0xff,
47 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a,
48 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
49 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
50 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
51 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
52 0x23, 0xff, 0xff, 0xff, 0xff, 0xff,
53 0xff, 0x24, 0x25, 0x26, 0x27, 0x28,
54 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
55 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34,
56 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a,
57 0x3b, 0x3c, 0x3d, 0xff, 0xff, 0xff,
58 0xff, 0xff
61 inline static int
62 encode (uint8_t * result, const uint8_t * rdata, int left)
65 int data_len;
66 int c, ret = 4;
67 uint8_t data[3];
69 if (left > 3)
70 data_len = 3;
71 else
72 data_len = left;
74 data[0] = data[1] = data[2] = 0;
75 memcpy (data, rdata, data_len);
77 switch (data_len)
79 case 3:
80 result[0] = b64table[((data[0] & 0xfc) >> 2)];
81 result[1] =
82 b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
83 ((data[1] & 0xf0) >> 4))];
84 result[2] =
85 b64table[((((data[1] & 0x0f) << 2) & 0xff) |
86 ((data[2] & 0xc0) >> 6))];
87 result[3] = b64table[(data[2] & 0x3f) & 0xff];
88 break;
89 case 2:
90 if ((c = ((data[0] & 0xf0) >> 4)) != 0)
92 result[0] = b64table[c];
93 result[1] =
94 b64table[((((data[0] & 0x0f) << 2) & 0xff) |
95 ((data[1] & 0xc0) >> 6))];
96 result[2] = b64table[(data[1] & 0x3f) & 0xff];
97 result[3] = '\0';
98 ret -= 1;
100 else
102 if ((c = ((data[0] & 0x0f) << 2) | ((data[1] & 0xc0) >> 6)) != 0)
104 result[0] = b64table[c];
105 result[1] = b64table[data[1] & 0x3f];
106 result[2] = '\0';
107 result[3] = '\0';
108 ret -= 2;
110 else
112 result[0] = b64table[data[0] & 0x3f];
113 result[1] = '\0';
114 result[2] = '\0';
115 result[3] = '\0';
116 ret -= 3;
119 break;
120 case 1:
121 if ((c = ((data[0] & 0xc0) >> 6)) != 0)
123 result[0] = b64table[c];
124 result[1] = b64table[(data[0] & 0x3f) & 0xff];
125 result[2] = '\0';
126 result[3] = '\0';
127 ret -= 2;
129 else
131 result[0] = b64table[(data[0] & 0x3f) & 0xff];
132 result[1] = '\0';
133 result[2] = '\0';
134 result[3] = '\0';
135 ret -= 3;
137 break;
138 default:
139 return -1;
142 return ret;
146 /* encodes data and puts the result into result (locally allocated)
147 * The result_size is the return value
149 static int
150 _gnutls_sbase64_encode (uint8_t * data, size_t data_size, char ** result)
152 unsigned i, j;
153 int ret, tmp;
154 uint8_t tmpres[4];
155 int mod = data_size % 3;
157 ret = mod;
158 if (ret != 0)
159 ret = 4;
160 else
161 ret = 0;
163 ret += (data_size * 4) / 3;
165 (*result) = gnutls_calloc (1, ret + 1);
166 if ((*result) == NULL)
167 return -1;
169 i = j = 0;
170 /* encode the bytes that are not a multiple of 3
172 if (mod > 0)
174 tmp = encode (tmpres, &data[0], mod);
175 if (tmp < 0)
177 gnutls_free ((*result));
178 return tmp;
181 memcpy (&(*result)[0], tmpres, tmp);
182 i = mod;
183 j = tmp;
186 /* encode the rest
188 for (; i < data_size; i += 3, j += 4)
190 tmp = encode (tmpres, &data[i], data_size - i);
191 if (tmp < 0)
193 gnutls_free ((*result));
194 return tmp;
196 memcpy (&(*result)[j], tmpres, tmp);
199 return strlen (*result);
203 /* data must be 4 bytes
204 * result should be 3 bytes
206 #define TOASCII(c) (c < 127 ? asciitable[c] : 0xff)
207 inline static int
208 decode (uint8_t * result, const uint8_t * data)
210 uint8_t a1, a2;
211 int ret = 3;
213 memset (result, 0, 3);
215 a1 = TOASCII (data[3]);
216 a2 = TOASCII (data[2]);
217 if (a1 != 0xff)
218 result[2] = a1 & 0xff;
219 else
220 return -1;
221 if (a2 != 0xff)
222 result[2] |= ((a2 & 0x03) << 6) & 0xff;
224 a1 = a2;
225 a2 = TOASCII (data[1]);
226 if (a1 != 0xff)
227 result[1] = ((a1 & 0x3c) >> 2);
228 if (a2 != 0xff)
229 result[1] |= ((a2 & 0x0f) << 4);
230 else if (a1 == 0xff || result[1] == 0)
231 ret--;
233 a1 = a2;
234 a2 = TOASCII (data[0]);
235 if (a1 != 0xff)
236 result[0] = (((a1 & 0x30) >> 4) & 0xff);
237 if (a2 != 0xff)
238 result[0] |= ((a2 << 2) & 0xff);
239 else if (a1 == 0xff || result[0] == 0)
240 ret--;
242 return ret;
245 /* decodes data and puts the result into result (locally allocated)
246 * The result_size is the return value.
247 * That function does not ignore newlines tabs etc. You should remove them
248 * before calling it.
251 _gnutls_sbase64_decode (char * data, size_t idata_size, uint8_t ** result)
253 unsigned i, j;
254 int ret, left;
255 int data_size, tmp;
256 uint8_t datrev[4];
257 uint8_t tmpres[3];
259 data_size = (idata_size / 4) * 4;
260 left = idata_size % 4;
262 ret = (data_size / 4) * 3;
264 if (left > 0)
265 ret += 3;
267 (*result) = gnutls_malloc (ret + 1);
268 if ((*result) == NULL)
269 return -1;
271 /* the first "block" is treated with special care */
272 tmp = 0;
273 if (left > 0)
275 memset (datrev, 0, 4);
276 memcpy (&datrev[4 - left], data, left);
278 tmp = decode (tmpres, datrev);
279 if (tmp < 0)
281 gnutls_free ((*result));
282 *result = NULL;
283 return tmp;
286 memcpy (*result, &tmpres[3 - tmp], tmp);
287 if (tmp < 3)
288 ret -= (3 - tmp);
291 /* rest data */
292 for (i = left, j = tmp; i < idata_size; i += 4)
294 tmp = decode (tmpres, (uint8_t*)&data[i]);
295 if (tmp < 0)
297 gnutls_free ((*result));
298 *result = NULL;
299 return tmp;
301 memcpy (&(*result)[j], tmpres, tmp);
302 if (tmp < 3)
303 ret -= (3 - tmp);
304 j += 3;
307 return ret;
311 * gnutls_srp_base64_encode:
312 * @data: contain the raw data
313 * @result: the place where base64 data will be copied
314 * @result_size: holds the size of the result
316 * This function will convert the given data to printable data, using
317 * the base64 encoding, as used in the libsrp. This is the encoding
318 * used in SRP password files. If the provided buffer is not long
319 * enough GNUTLS_E_SHORT_MEMORY_BUFFER is returned.
321 * Warning! This base64 encoding is not the "standard" encoding, so
322 * do not use it for non-SRP purposes.
324 * Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not
325 * long enough, or 0 on success.
328 gnutls_srp_base64_encode (const gnutls_datum_t * data, char *result,
329 size_t * result_size)
331 char *res;
332 int size;
334 size = _gnutls_sbase64_encode (data->data, data->size, &res);
335 if (size < 0)
336 return size;
338 if (result == NULL || *result_size < (size_t) size)
340 gnutls_free (res);
341 *result_size = size;
342 return GNUTLS_E_SHORT_MEMORY_BUFFER;
344 else
346 memcpy (result, res, size);
347 gnutls_free (res);
348 *result_size = size;
351 return 0;
355 * gnutls_srp_base64_encode_alloc:
356 * @data: contains the raw data
357 * @result: will hold the newly allocated encoded data
359 * This function will convert the given data to printable data, using
360 * the base64 encoding. This is the encoding used in SRP password
361 * files. This function will allocate the required memory to hold
362 * the encoded data.
364 * You should use gnutls_free() to free the returned data.
366 * Warning! This base64 encoding is not the "standard" encoding, so
367 * do not use it for non-SRP purposes.
369 * Returns: 0 on success, or an error code.
372 gnutls_srp_base64_encode_alloc (const gnutls_datum_t * data,
373 gnutls_datum_t * result)
375 char *res;
376 int size;
378 size = _gnutls_sbase64_encode (data->data, data->size, &res);
379 if (size < 0)
380 return size;
382 if (result == NULL)
384 gnutls_free (res);
385 return GNUTLS_E_INVALID_REQUEST;
387 else
389 result->data = (uint8_t*)res;
390 result->size = size;
393 return 0;
397 * gnutls_srp_base64_decode:
398 * @b64_data: contain the encoded data
399 * @result: the place where decoded data will be copied
400 * @result_size: holds the size of the result
402 * This function will decode the given encoded data, using the base64
403 * encoding found in libsrp.
405 * Note that @b64_data should be null terminated.
407 * Warning! This base64 encoding is not the "standard" encoding, so
408 * do not use it for non-SRP purposes.
410 * Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not
411 * long enough, or 0 on success.
414 gnutls_srp_base64_decode (const gnutls_datum_t * b64_data, char *result,
415 size_t * result_size)
417 uint8_t *res;
418 int size;
420 size = _gnutls_sbase64_decode ((char*)b64_data->data, b64_data->size, &res);
421 if (size < 0)
422 return size;
424 if (result == NULL || *result_size < (size_t) size)
426 gnutls_free (res);
427 *result_size = size;
428 return GNUTLS_E_SHORT_MEMORY_BUFFER;
430 else
432 memcpy (result, res, size);
433 gnutls_free (res);
434 *result_size = size;
437 return 0;
441 * gnutls_srp_base64_decode_alloc:
442 * @b64_data: contains the encoded data
443 * @result: the place where decoded data lie
445 * This function will decode the given encoded data. The decoded data
446 * will be allocated, and stored into result. It will decode using
447 * the base64 algorithm as used in libsrp.
449 * You should use gnutls_free() to free the returned data.
451 * Warning! This base64 encoding is not the "standard" encoding, so
452 * do not use it for non-SRP purposes.
454 * Returns: 0 on success, or an error code.
457 gnutls_srp_base64_decode_alloc (const gnutls_datum_t * b64_data,
458 gnutls_datum_t * result)
460 uint8_t *ret;
461 int size;
463 size = _gnutls_sbase64_decode ((char*)b64_data->data, b64_data->size, &ret);
464 if (size < 0)
465 return size;
467 if (result == NULL)
469 gnutls_free (ret);
470 return GNUTLS_E_INVALID_REQUEST;
472 else
474 result->data = ret;
475 result->size = size;
478 return 0;
481 #endif /* ENABLE_SRP */