OpenVPN
base64.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 1995-2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifdef HAVE_CONFIG_H
35#include "config.h"
36#endif
37
38#include "syshead.h"
39
40#include "base64.h"
41
42#include "memdbg.h"
43
44static char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
45/*
46 * base64 encode input data of length size to malloced
47 * buffer which is returned as *str. Returns string
48 * length of *str.
49 */
50int
51openvpn_base64_encode(const void *data, int size, char **str)
52{
53 if (size < 0)
54 {
55 return -1;
56 }
57 size_t out_size = (size_t)size * 4 / 3 + 4;
58 if (out_size > INT_MAX)
59 {
60 return -1;
61 }
62 char *p = (char *)malloc(out_size);
63 char *start = p;
64 if (p == NULL)
65 {
66 return -1;
67 }
68 const unsigned char *q = (const unsigned char *)data;
69 for (int i = 0; i < size;)
70 {
71 unsigned int c = q[i++];
72 c <<= 8;
73 if (i < size)
74 {
75 c += q[i];
76 }
77 i++;
78 c <<= 8;
79 if (i < size)
80 {
81 c += q[i];
82 }
83 i++;
84 p[0] = base64_chars[(c & 0x00fc0000) >> 18];
85 p[1] = base64_chars[(c & 0x0003f000) >> 12];
86 p[2] = base64_chars[(c & 0x00000fc0) >> 6];
87 p[3] = base64_chars[(c & 0x0000003f) >> 0];
88 if (i > size)
89 {
90 p[3] = '=';
91 }
92 if (i > size + 1)
93 {
94 p[2] = '=';
95 }
96 p += 4;
97 }
98 *p = 0;
99 *str = start;
100 return (int)strlen(start);
101}
102
103static int
104pos(char c)
105{
106 for (char *p = base64_chars; *p; p++)
107 {
108 if (*p == c)
109 {
110 return (int)(p - base64_chars);
111 }
112 }
113 return -1;
114}
115
116#define DECODE_ERROR 0xffffffff
117
118static unsigned int
119token_decode(const char *token)
120{
121 unsigned int val = 0;
122 unsigned int marker = 0;
123 if (!token[0] || !token[1] || !token[2] || !token[3])
124 {
125 return DECODE_ERROR;
126 }
127 for (unsigned int i = 0; i < 4; i++)
128 {
129 val <<= 6;
130 if (token[i] == '=')
131 {
132 marker++;
133 }
134 else if (marker > 0)
135 {
136 return DECODE_ERROR;
137 }
138 else
139 {
140 int char_pos = pos(token[i]);
141 if (unlikely(char_pos < 0)) /* caller should check */
142 {
143 return DECODE_ERROR;
144 }
145 val += (unsigned int)char_pos;
146 }
147 }
148 if (marker > 2)
149 {
150 return DECODE_ERROR;
151 }
152 return (marker << 24) | val;
153}
154/*
155 * Decode base64 str, outputting data to buffer
156 * at data of length size. Return length of
157 * decoded data written or -1 on error or overflow.
158 */
159int
160openvpn_base64_decode(const char *str, void *data, int size)
161{
162 const char *p;
163 unsigned char *q;
164 unsigned char *e = NULL;
165
166 q = data;
167 if (size >= 0)
168 {
169 e = q + size;
170 }
171 for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4)
172 {
173 unsigned int val = token_decode(p);
174 unsigned int marker = (val >> 24) & 0xff;
175 if (val == DECODE_ERROR)
176 {
177 return -1;
178 }
179 if (e && q >= e)
180 {
181 return -1;
182 }
183 *q++ = (val >> 16) & 0xff;
184 if (marker < 2)
185 {
186 if (e && q >= e)
187 {
188 return -1;
189 }
190 *q++ = (val >> 8) & 0xff;
191 }
192 if (marker < 1)
193 {
194 if (e && q >= e)
195 {
196 return -1;
197 }
198 *q++ = val & 0xff;
199 }
200 }
201 return (int)(q - (unsigned char *)data);
202}
static int pos(char c)
Definition base64.c:104
int openvpn_base64_decode(const char *str, void *data, int size)
Definition base64.c:160
static char base64_chars[]
Definition base64.c:44
int openvpn_base64_encode(const void *data, int size, char **str)
Definition base64.c:51
static unsigned int token_decode(const char *token)
Definition base64.c:119
#define DECODE_ERROR
Definition base64.c:116
#define unlikely(x)
Definition syshead.h:35