]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
1 | /* |
2 | * Base64 encoding/decoding (RFC1341) | |
619e6726 | 3 | * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi> |
6fc6879b JM |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * Alternatively, this software may be distributed under the terms of BSD | |
10 | * license. | |
11 | * | |
12 | * See README and COPYING for more details. | |
13 | */ | |
14 | ||
15 | #include "includes.h" | |
16 | ||
17 | #include "os.h" | |
18 | #include "base64.h" | |
19 | ||
20 | static const unsigned char base64_table[65] = | |
21 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
22 | ||
23 | /** | |
24 | * base64_encode - Base64 encode | |
25 | * @src: Data to be encoded | |
26 | * @len: Length of the data to be encoded | |
27 | * @out_len: Pointer to output length variable, or %NULL if not used | |
28 | * Returns: Allocated buffer of out_len bytes of encoded data, | |
29 | * or %NULL on failure | |
30 | * | |
31 | * Caller is responsible for freeing the returned buffer. Returned buffer is | |
32 | * nul terminated to make it easier to use as a C string. The nul terminator is | |
33 | * not included in out_len. | |
34 | */ | |
35 | unsigned char * base64_encode(const unsigned char *src, size_t len, | |
36 | size_t *out_len) | |
37 | { | |
38 | unsigned char *out, *pos; | |
39 | const unsigned char *end, *in; | |
40 | size_t olen; | |
41 | int line_len; | |
42 | ||
43 | olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ | |
44 | olen += olen / 72; /* line feeds */ | |
45 | olen++; /* nul termination */ | |
6b23b704 JM |
46 | if (olen < len) |
47 | return NULL; /* integer overflow */ | |
6fc6879b JM |
48 | out = os_malloc(olen); |
49 | if (out == NULL) | |
50 | return NULL; | |
51 | ||
52 | end = src + len; | |
53 | in = src; | |
54 | pos = out; | |
55 | line_len = 0; | |
56 | while (end - in >= 3) { | |
57 | *pos++ = base64_table[in[0] >> 2]; | |
58 | *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; | |
59 | *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; | |
60 | *pos++ = base64_table[in[2] & 0x3f]; | |
61 | in += 3; | |
62 | line_len += 4; | |
63 | if (line_len >= 72) { | |
64 | *pos++ = '\n'; | |
65 | line_len = 0; | |
66 | } | |
67 | } | |
68 | ||
69 | if (end - in) { | |
70 | *pos++ = base64_table[in[0] >> 2]; | |
71 | if (end - in == 1) { | |
72 | *pos++ = base64_table[(in[0] & 0x03) << 4]; | |
73 | *pos++ = '='; | |
74 | } else { | |
75 | *pos++ = base64_table[((in[0] & 0x03) << 4) | | |
76 | (in[1] >> 4)]; | |
77 | *pos++ = base64_table[(in[1] & 0x0f) << 2]; | |
78 | } | |
79 | *pos++ = '='; | |
80 | line_len += 4; | |
81 | } | |
82 | ||
83 | if (line_len) | |
84 | *pos++ = '\n'; | |
85 | ||
86 | *pos = '\0'; | |
87 | if (out_len) | |
88 | *out_len = pos - out; | |
89 | return out; | |
90 | } | |
91 | ||
92 | ||
93 | /** | |
94 | * base64_decode - Base64 decode | |
95 | * @src: Data to be decoded | |
96 | * @len: Length of the data to be decoded | |
97 | * @out_len: Pointer to output length variable | |
98 | * Returns: Allocated buffer of out_len bytes of decoded data, | |
99 | * or %NULL on failure | |
100 | * | |
101 | * Caller is responsible for freeing the returned buffer. | |
102 | */ | |
103 | unsigned char * base64_decode(const unsigned char *src, size_t len, | |
104 | size_t *out_len) | |
105 | { | |
619e6726 | 106 | unsigned char dtable[256], *out, *pos, block[4], tmp; |
6fc6879b | 107 | size_t i, count, olen; |
619e6726 | 108 | int pad = 0; |
6fc6879b JM |
109 | |
110 | os_memset(dtable, 0x80, 256); | |
111 | for (i = 0; i < sizeof(base64_table) - 1; i++) | |
112 | dtable[base64_table[i]] = (unsigned char) i; | |
113 | dtable['='] = 0; | |
114 | ||
115 | count = 0; | |
116 | for (i = 0; i < len; i++) { | |
117 | if (dtable[src[i]] != 0x80) | |
118 | count++; | |
119 | } | |
120 | ||
72822e7b | 121 | if (count == 0 || count % 4) |
6fc6879b JM |
122 | return NULL; |
123 | ||
124 | olen = count / 4 * 3; | |
125 | pos = out = os_malloc(olen); | |
126 | if (out == NULL) | |
127 | return NULL; | |
128 | ||
129 | count = 0; | |
130 | for (i = 0; i < len; i++) { | |
131 | tmp = dtable[src[i]]; | |
132 | if (tmp == 0x80) | |
133 | continue; | |
134 | ||
619e6726 JM |
135 | if (src[i] == '=') |
136 | pad++; | |
6fc6879b JM |
137 | block[count] = tmp; |
138 | count++; | |
139 | if (count == 4) { | |
140 | *pos++ = (block[0] << 2) | (block[1] >> 4); | |
141 | *pos++ = (block[1] << 4) | (block[2] >> 2); | |
142 | *pos++ = (block[2] << 6) | block[3]; | |
143 | count = 0; | |
619e6726 JM |
144 | if (pad) { |
145 | if (pad == 1) | |
146 | pos--; | |
147 | else if (pad == 2) | |
148 | pos -= 2; | |
149 | else { | |
150 | /* Invalid padding */ | |
151 | os_free(out); | |
152 | return NULL; | |
153 | } | |
154 | break; | |
155 | } | |
6fc6879b JM |
156 | } |
157 | } | |
158 | ||
6fc6879b JM |
159 | *out_len = pos - out; |
160 | return out; | |
161 | } |