1 /*
2 * Copyright (c) 2015 by Farsight Security, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * Copyright (c) 2006 Christian Biere <christianbiere@gmx.de>
19 * All rights reserved.
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions
23 * are met:
24 *
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 * 3. Neither the name of the authors nor the names of its contributors
31 * may be used to endorse or promote products derived from this software
32 * without specific prior written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 * SUCH DAMAGE.
45 */
46
47 /*
48 * See RFC 4648 for details about Base 32 hex encoding:
49 * http://tools.ietf.org/html/rfc4648
50 */
51
52 #include <stdint.h>
53 #include <string.h>
54
55 #include "b32_decode.h"
56
57 #ifndef G_N_ELEMENTS
58 #define G_N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0]))
59 #endif
60
61 #define ZERO(x) memset((x), 0, sizeof *(x))
62
63 static inline void *
ptr_add_offset(void * p,size_t offset)64 ptr_add_offset(void *p, size_t offset)
65 {
66 /* Using size_t instead of 'char *' because pointers don't wrap. */
67 return (void *) ((size_t) p + offset);
68 }
69
70 static inline const void *
cast_to_constpointer(const void * p)71 cast_to_constpointer(const void *p)
72 {
73 return p;
74 }
75
76 static inline bool
is_ascii_lower(int c)77 is_ascii_lower(int c)
78 {
79 return c >= 97 && c <= 122; /* a-z */
80 }
81
82 static inline int
ascii_toupper(int c)83 ascii_toupper(int c)
84 {
85 return is_ascii_lower(c) ? c - 32 : c;
86 }
87
88 static inline size_t
ptr_diff(const void * a,const void * b)89 ptr_diff(const void *a, const void *b)
90 {
91 return (const char *) a - (const char *) b;
92 }
93
94 static const char base32_alphabet[32] = {
95 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
96 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
97 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
98 'U', 'V'
99 };
100
101 static char base32_map[(size_t) (unsigned char) -1 + 1];
102
103 /**
104 * Decode a base32 encoding of `len' bytes of `data' into the buffer `dst'.
105 *
106 * @param dst destination buffer
107 * @param size length of destination
108 * @param data start of data to decode
109 * @param len amount of encoded data to decode
110 *
111 * @return the amount of bytes decoded into the destination.
112 */
113 size_t
base32_decode(void * dst,size_t size,const char * data,size_t len)114 base32_decode(void *dst, size_t size, const char *data, size_t len)
115 {
116 const char *end = ptr_add_offset(dst, size);
117 const unsigned char *p = cast_to_constpointer(data);
118 char s[8];
119 char *q = dst;
120 int pad = 0;
121 size_t i, si;
122
123 if (0 == base32_map[0]) {
124 for (i = 0; i < G_N_ELEMENTS(base32_map); i++) {
125 const char *x;
126
127 x = memchr(base32_alphabet, ascii_toupper(i),
128 sizeof base32_alphabet);
129 base32_map[i] = x ? (x - base32_alphabet) : (unsigned char) -1;
130 }
131 }
132
133 ZERO(&s);
134 si = 0;
135 i = 0;
136
137 while (i < len) {
138 unsigned char c;
139
140 c = p[i++];
141 if ('=' == c) {
142 pad++;
143 c = 0;
144 } else {
145 c = base32_map[c];
146 if ((unsigned char) -1 == c) {
147 return -1;
148 }
149 }
150
151 s[si++] = c;
152
153 if (G_N_ELEMENTS(s) == si || pad > 0 || i == len) {
154 char b[5];
155 size_t bi;
156
157 memset(&s[si], 0, G_N_ELEMENTS(s) - si);
158 si = 0;
159
160 b[0] =
161 ((s[0] << 3) & 0xf8) |
162 ((s[1] >> 2) & 0x07);
163 b[1] =
164 ((s[1] & 0x03) << 6) |
165 ((s[2] & 0x1f) << 1) |
166 ((s[3] >> 4) & 1);
167 b[2] =
168 ((s[3] & 0x0f) << 4) |
169 ((s[4] >> 1) & 0x0f);
170 b[3] =
171 ((s[4] & 1) << 7) |
172 ((s[5] & 0x1f) << 2) |
173 ((s[6] >> 3) & 0x03);
174 b[4] =
175 ((s[6] & 0x07) << 5) |
176 (s[7] & 0x1f);
177
178 for (bi = 0; bi < G_N_ELEMENTS(b) && q != end; bi++) {
179 *q++ = b[bi];
180 }
181 }
182
183 if (end == q) {
184 break;
185 }
186 }
187
188 return ptr_diff(q, dst);
189 }
190