~ubuntu-branches/ubuntu/precise/libssh/precise

« back to all changes in this revision

Viewing changes to src/base64.c

  • Committer: Bazaar Package Importer
  • Author(s): Laurent Bigonville
  • Date: 2011-06-15 15:48:07 UTC
  • mfrom: (1.1.10 upstream) (4.1.12 sid)
  • Revision ID: james.westby@ubuntu.com-20110615154807-3muklcqfftr1vtch
Tags: 0.5.0-2
* debian/patches/0002-Check-for-NULL-pointers-in-string-c.patch:
  Consolidate patch (Should fix previous REJECT)
* Support multiarch spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * base64.c - support for base64 alphabet system, described in RFC1521
 
3
 *
 
4
 * This file is part of the SSH Library
 
5
 *
 
6
 * Copyright (c) 2005-2005 by Aris Adamantiadis
 
7
 *
 
8
 * The SSH Library is free software; you can redistribute it and/or modify
 
9
 * it under the terms of the GNU Lesser General Public License as published by
 
10
 * the Free Software Foundation; either version 2.1 of the License, or (at your
 
11
 * option) any later version.
 
12
 *
 
13
 * The SSH Library is distributed in the hope that it will be useful, but
 
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
15
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 
16
 * License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU Lesser General Public License
 
19
 * along with the SSH Library; see the file COPYING.  If not, write to
 
20
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 
21
 * MA 02111-1307, USA.
 
22
 */
 
23
 
 
24
/* just the dirtiest part of code i ever made */
 
25
#include <string.h>
 
26
#include <stdio.h>
 
27
#include <stdlib.h>
 
28
 
 
29
#include "libssh/priv.h"
 
30
#include "libssh/buffer.h"
 
31
 
 
32
static char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
33
                         "abcdefghijklmnopqrstuvwxyz"
 
34
                         "0123456789+/";
 
35
 
 
36
/* Transformations */
 
37
#define SET_A(n, i) do { (n) |= ((i) & 63) <<18; } while (0)
 
38
#define SET_B(n, i) do { (n) |= ((i) & 63) <<12; } while (0)
 
39
#define SET_C(n, i) do { (n) |= ((i) & 63) << 6; } while (0)
 
40
#define SET_D(n, i) do { (n) |= ((i) & 63); } while (0)
 
41
 
 
42
#define GET_A(n) (unsigned char) (((n) & 0xff0000) >> 16)
 
43
#define GET_B(n) (unsigned char) (((n) & 0xff00) >> 8)
 
44
#define GET_C(n) (unsigned char) ((n) & 0xff)
 
45
 
 
46
static int _base64_to_bin(unsigned char dest[3], const char *source, int num);
 
47
static int get_equals(char *string);
 
48
 
 
49
/* First part: base64 to binary */
 
50
 
 
51
/**
 
52
 * @internal
 
53
 *
 
54
 * @brief Translates a base64 string into a binary one.
 
55
 *
 
56
 * @returns A buffer containing the decoded string, NULL if something went
 
57
 *          wrong (e.g. incorrect char).
 
58
 */
 
59
ssh_buffer base64_to_bin(const char *source) {
 
60
  ssh_buffer buffer = NULL;
 
61
  unsigned char block[3];
 
62
  char *base64;
 
63
  char *ptr;
 
64
  size_t len;
 
65
  int equals;
 
66
 
 
67
  base64 = strdup(source);
 
68
  if (base64 == NULL) {
 
69
    return NULL;
 
70
  }
 
71
  ptr = base64;
 
72
 
 
73
  /* Get the number of equals signs, which mirrors the padding */
 
74
  equals = get_equals(ptr);
 
75
  if (equals > 2) {
 
76
    SAFE_FREE(base64);
 
77
    return NULL;
 
78
  }
 
79
 
 
80
  buffer = ssh_buffer_new();
 
81
  if (buffer == NULL) {
 
82
    SAFE_FREE(base64);
 
83
    return NULL;
 
84
  }
 
85
 
 
86
  len = strlen(ptr);
 
87
  while (len > 4) {
 
88
    if (_base64_to_bin(block, ptr, 3) < 0) {
 
89
      goto error;
 
90
    }
 
91
    if (buffer_add_data(buffer, block, 3) < 0) {
 
92
      goto error;
 
93
    }
 
94
    len -= 4;
 
95
    ptr += 4;
 
96
  }
 
97
 
 
98
  /*
 
99
   * Depending on the number of bytes resting, there are 3 possibilities
 
100
   * from the RFC.
 
101
   */
 
102
  switch (len) {
 
103
    /*
 
104
     * (1) The final quantum of encoding input is an integral multiple of
 
105
     *     24 bits. Here, the final unit of encoded output will be an integral
 
106
     *     multiple of 4 characters with no "=" padding
 
107
     */
 
108
    case 4:
 
109
      if (equals != 0) {
 
110
        goto error;
 
111
      }
 
112
      if (_base64_to_bin(block, ptr, 3) < 0) {
 
113
        goto error;
 
114
      }
 
115
      if (buffer_add_data(buffer, block, 3) < 0) {
 
116
        goto error;
 
117
      }
 
118
      SAFE_FREE(base64);
 
119
 
 
120
      return buffer;
 
121
    /*
 
122
     * (2) The final quantum of encoding input is exactly 8 bits; here, the
 
123
     *     final unit of encoded output will be two characters followed by
 
124
     *     two "=" padding characters.
 
125
     */
 
126
    case 2:
 
127
      if (equals != 2){
 
128
        goto error;
 
129
      }
 
130
 
 
131
      if (_base64_to_bin(block, ptr, 1) < 0) {
 
132
        goto error;
 
133
      }
 
134
      if (buffer_add_data(buffer, block, 1) < 0) {
 
135
        goto error;
 
136
      }
 
137
      SAFE_FREE(base64);
 
138
 
 
139
      return buffer;
 
140
    /*
 
141
     * The final quantum of encoding input is exactly 16 bits. Here, the final
 
142
     * unit of encoded output will be three characters followed by one "="
 
143
     * padding character.
 
144
     */
 
145
    case 3:
 
146
      if (equals != 1) {
 
147
        goto error;
 
148
      }
 
149
      if (_base64_to_bin(block, ptr, 2) < 0) {
 
150
        goto error;
 
151
      }
 
152
      if (buffer_add_data(buffer,block,2) < 0) {
 
153
        goto error;
 
154
      }
 
155
      SAFE_FREE(base64);
 
156
 
 
157
      return buffer;
 
158
    default:
 
159
      /* 4,3,2 are the only padding size allowed */
 
160
      goto error;
 
161
  }
 
162
 
 
163
error:
 
164
  SAFE_FREE(base64);
 
165
  ssh_buffer_free(buffer);
 
166
  return NULL;
 
167
}
 
168
 
 
169
#define BLOCK(letter, n) do {ptr = strchr(alphabet, source[n]); \
 
170
                             if(!ptr) return -1; \
 
171
                             i = ptr - alphabet; \
 
172
                             SET_##letter(*block, i); \
 
173
                         } while(0)
 
174
 
 
175
/* Returns 0 if ok, -1 if not (ie invalid char into the stuff) */
 
176
static int to_block4(unsigned long *block, const char *source, int num) {
 
177
  char *ptr;
 
178
  unsigned int i;
 
179
 
 
180
  *block = 0;
 
181
  if (num < 1) {
 
182
    return 0;
 
183
  }
 
184
 
 
185
  BLOCK(A, 0); /* 6 bit */
 
186
  BLOCK(B,1); /* 12 bit */
 
187
 
 
188
  if (num < 2) {
 
189
    return 0;
 
190
  }
 
191
 
 
192
  BLOCK(C, 2); /* 18 bit */
 
193
 
 
194
  if (num < 3) {
 
195
    return 0;
 
196
  }
 
197
 
 
198
  BLOCK(D, 3); /* 24 bit */
 
199
 
 
200
  return 0;
 
201
}
 
202
 
 
203
/* num = numbers of final bytes to be decoded */
 
204
static int _base64_to_bin(unsigned char dest[3], const char *source, int num) {
 
205
  unsigned long block;
 
206
 
 
207
  if (to_block4(&block, source, num) < 0) {
 
208
    return -1;
 
209
  }
 
210
  dest[0] = GET_A(block);
 
211
  dest[1] = GET_B(block);
 
212
  dest[2] = GET_C(block);
 
213
 
 
214
  return 0;
 
215
}
 
216
 
 
217
/* Count the number of "=" signs and replace them by zeroes */
 
218
static int get_equals(char *string) {
 
219
  char *ptr = string;
 
220
  int num = 0;
 
221
 
 
222
  while ((ptr=strchr(ptr,'=')) != NULL) {
 
223
    num++;
 
224
    *ptr = '\0';
 
225
    ptr++;
 
226
  }
 
227
 
 
228
  return num;
 
229
}
 
230
 
 
231
/* thanks sysk for debugging my mess :) */
 
232
#define BITS(n) ((1 << (n)) - 1)
 
233
static void _bin_to_base64(unsigned char *dest, const unsigned char source[3],
 
234
    int len) {
 
235
  switch (len) {
 
236
    case 1:
 
237
      dest[0] = alphabet[(source[0] >> 2)];
 
238
      dest[1] = alphabet[((source[0] & BITS(2)) << 4)];
 
239
      dest[2] = '=';
 
240
      dest[3] = '=';
 
241
      break;
 
242
    case 2:
 
243
      dest[0] = alphabet[source[0] >> 2];
 
244
      dest[1] = alphabet[(source[1] >> 4) | ((source[0] & BITS(2)) << 4)];
 
245
      dest[2] = alphabet[(source[1] & BITS(4)) << 2];
 
246
      dest[3] = '=';
 
247
      break;
 
248
    case 3:
 
249
      dest[0] = alphabet[(source[0] >> 2)];
 
250
      dest[1] = alphabet[(source[1] >> 4) | ((source[0] & BITS(2)) << 4)];
 
251
      dest[2] = alphabet[ (source[2] >> 6) | (source[1] & BITS(4)) << 2];
 
252
      dest[3] = alphabet[source[2] & BITS(6)];
 
253
      break;
 
254
  }
 
255
}
 
256
 
 
257
/**
 
258
 * @internal
 
259
 *
 
260
 * @brief Converts binary data to a base64 string.
 
261
 *
 
262
 * @returns the converted string
 
263
 */
 
264
unsigned char *bin_to_base64(const unsigned char *source, int len) {
 
265
  unsigned char *base64;
 
266
  unsigned char *ptr;
 
267
  int flen = len + (3 - (len % 3)); /* round to upper 3 multiple */
 
268
  flen = (4 * flen) / 3 + 1;
 
269
 
 
270
  base64 = malloc(flen);
 
271
  if (base64 == NULL) {
 
272
    return NULL;
 
273
  }
 
274
  ptr = base64;
 
275
 
 
276
  while(len > 0){
 
277
    _bin_to_base64(ptr, source, len > 3 ? 3 : len);
 
278
    ptr += 4;
 
279
    source += 3;
 
280
    len -= 3;
 
281
  }
 
282
  ptr[0] = '\0';
 
283
 
 
284
  return base64;
 
285
}
 
286
 
 
287
/* vim: set ts=2 sw=2 et cindent: */