base64: Replace Pad64 variable by macro.
[paraslash.git] / base64.c
1 /*
2 * The code in this file was taken from openssh-5.2p1, Copyright (c) 1996 by
3 * Internet Software Consortium. Portions Copyright (c) 1995 by International
4 * Business Machines, Inc.
5 */
6
7 /** \file base64.c Uudecode and base64decode implementation. */
8
9 #include <regex.h>
10
11 #include "para.h"
12 #include "error.h"
13 #include "base64.h"
14 #include "string.h"
15
16 static const char Base64[] =
17 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
18
19 /** Maximal possible size of the decoded data. */
20 #define BASE64_MAX_DECODED_SIZE(_encoded_size) ((_encoded_size) / 4 * 3)
21
22 #define PAD64 '='
23 /**
24 * base64-decode a buffer.
25 *
26 * \param src The buffer to decode.
27 * \param encoded_size The special value -1 means: look for terminating zero byte.
28 * \param result Points to dynamically allocated target buffer on success.
29 * \param decoded_size Number of bytes written to \a result.
30 *
31 * Skips all whitespace anywhere. Converts characters, four at a time, starting
32 * at (or after) src from base - 64 numbers into three 8 bit bytes in the
33 * target area.
34 *
35 * It is OK to pass a \p NULL pointer as \a decoded_size. The result is
36 * terminated with a zero byte.
37 *
38 * \return Standard. The contents of result \a and \a decoded_size are
39 * undefined on failure.
40 */
41 int base64_decode(char const *src, size_t encoded_size, char **result,
42 size_t *decoded_size)
43 {
44 unsigned int tarindex, state;
45 int ch;
46 char *pos;
47 const char *end = src + encoded_size;
48 unsigned char *target;
49
50 if (encoded_size == (size_t)-1)
51 encoded_size = strlen(src);
52 target = para_malloc(BASE64_MAX_DECODED_SIZE(encoded_size) + 1);
53
54 state = 0;
55 tarindex = 0;
56
57 while (src < end) {
58 ch = *src++;
59 if (para_isspace(ch)) /* Skip whitespace anywhere. */
60 continue;
61
62 if (ch == PAD64)
63 break;
64
65 pos = strchr(Base64, ch);
66 if (pos == NULL) /* A non-base64 character. */
67 goto fail;
68
69 switch (state) {
70 case 0:
71 target[tarindex] = (pos - Base64) << 2;
72 state = 1;
73 break;
74 case 1:
75 target[tarindex] |= (pos - Base64) >> 4;
76 target[tarindex + 1] = ((pos - Base64) & 0x0f) << 4;
77 tarindex++;
78 state = 2;
79 break;
80 case 2:
81 target[tarindex] |= (pos - Base64) >> 2;
82 target[tarindex + 1] = ((pos - Base64) & 0x03) << 6;
83 tarindex++;
84 state = 3;
85 break;
86 case 3:
87 target[tarindex] |= pos - Base64;
88 tarindex++;
89 state = 0;
90 break;
91 }
92 }
93
94 /*
95 * We are done decoding Base-64 chars. Let's see if we ended
96 * on a byte boundary, and/or with erroneous trailing characters.
97 */
98
99 if (*src == PAD64) { /* We got a pad char. */
100 ch = *src++; /* Skip it, get next. */
101 switch (state) {
102 case 0: /* Invalid = in first position */
103 case 1: /* Invalid = in second position */
104 goto fail;
105
106 case 2: /* Valid, means one byte of info */
107 /* Skip any number of spaces. */
108 for (; ch != '\0'; ch = *src++)
109 if (!isspace(ch))
110 break;
111 /* Make sure there is another trailing = sign. */
112 if (ch != PAD64)
113 goto fail;
114 ch = *src++; /* Skip the = */
115 /* Fall through to "single trailing =" case. */
116 /* FALLTHROUGH */
117
118 case 3: /* Valid, means two bytes of info */
119 /*
120 * We know this char is an =. Is there anything but
121 * whitespace after it?
122 */
123 for (; ch != '\0'; ch = *src++)
124 if (!isspace(ch))
125 goto fail;
126
127 /*
128 * Now make sure for cases 2 and 3 that the "extra"
129 * bits that slopped past the last full byte were
130 * zeros. If we don't check them, they become a
131 * subliminal channel.
132 */
133 if (target[tarindex] != 0)
134 goto fail;
135 }
136 } else {
137 /*
138 * We ended by seeing the end of the string. Make sure we
139 * have no partial bytes lying around.
140 */
141 if (state != 0)
142 goto fail;
143 }
144 /* success */
145 target[tarindex] = '\0'; /* just to be sure */
146 *result = (char *)target;
147 if (decoded_size)
148 *decoded_size = tarindex;
149 return 1;
150 fail:
151 free(target);
152 return -E_BASE64;
153 }
154
155 /**
156 * Decode a buffer using the uuencode Base64 algorithm.
157 *
158 * \param src The buffer to decode.
159 * \param encoded_size Number of input bytes in the source buffer.
160 * \param result Contains the decoded data on success.
161 * \param decoded_size Number of output bytes on success.
162 *
163 * This is just a simple wrapper for \ref base64_decode() which strips
164 * whitespace.
165 *
166 * \return The return value of the underlying call to \ref base64_decode().
167 *
168 * \sa uuencode(1), uudecode(1).
169 */
170 int uudecode(char const *src, size_t encoded_size, char **result,
171 size_t *decoded_size)
172 {
173 const char *end = src + encoded_size, *p;
174
175 /* skip whitespace and data */
176 for (p = src; p < end && (*p == ' ' || *p == '\t'); p++)
177 ;
178 for (; p < end && *p != '\0' && *p != ' ' && *p != '\t'; p++)
179 ;
180 /* and remove trailing whitespace because base64_decode needs this */
181 return base64_decode(src, p - src, result, decoded_size);
182 }