xref: /spdk/lib/util/base64.c (revision 588dfe314bb83d86effdf67ec42837b11c2620bf)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2018 Intel Corporation. All rights reserved.
3  *   Copyright(c) ARM Limited. 2021 All rights reserved.
4  *   All rights reserved.
5  */
6 
7 #include "spdk/stdinc.h"
8 #include "spdk/endian.h"
9 #include "spdk/base64.h"
10 
11 #ifdef __aarch64__
12 #ifdef __ARM_FEATURE_SVE
13 #include "base64_sve.c"
14 #else
15 #include "base64_neon.c"
16 #endif
17 #endif
18 
19 
20 #define BASE64_ENC_BITMASK 0x3FUL
21 #define BASE64_PADDING_CHAR '='
22 
23 static const char base64_enc_table[] =
24 	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
25 	"abcdefghijklmnopqrstuvwxyz"
26 	"0123456789+/";
27 
28 static const char base64_urlsafe_enc_table[] =
29 	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
30 	"abcdefghijklmnopqrstuvwxyz"
31 	"0123456789-_";
32 
33 static const uint8_t
34 base64_dec_table[] = {
35 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
36 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
37 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
38 	52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255, 255, 255, 255, 255,
39 	255,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
40 	15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
41 	255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,
42 	41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51, 255, 255, 255, 255, 255,
43 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
44 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
45 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
46 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
47 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
48 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
49 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
50 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
51 };
52 
53 static const uint8_t
54 base64_urlsafe_dec_table[] = {
55 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
56 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
57 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,  62, 255, 255,
58 	52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255, 255, 255, 255, 255,
59 	255,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
60 	15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255,  63,
61 	255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,
62 	41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51, 255, 255, 255, 255, 255,
63 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
64 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
65 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
66 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
67 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
68 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
69 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
70 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
71 };
72 
73 static int
74 base64_encode(char *dst, const char *enc_table, const void *src, size_t src_len)
75 {
76 	uint32_t raw_u32;
77 
78 	if (!dst || !src || src_len <= 0) {
79 		return -EINVAL;
80 	}
81 
82 #ifdef __aarch64__
83 #ifdef __ARM_FEATURE_SVE
84 	base64_encode_sve(&dst, enc_table, &src, &src_len);
85 #else
86 	base64_encode_neon64(&dst, enc_table, &src, &src_len);
87 #endif
88 #endif
89 
90 
91 	while (src_len >= 4) {
92 		raw_u32 = from_be32(src);
93 
94 		*dst++ = enc_table[(raw_u32 >> 26) & BASE64_ENC_BITMASK];
95 		*dst++ = enc_table[(raw_u32 >> 20) & BASE64_ENC_BITMASK];
96 		*dst++ = enc_table[(raw_u32 >> 14) & BASE64_ENC_BITMASK];
97 		*dst++ = enc_table[(raw_u32 >> 8) & BASE64_ENC_BITMASK];
98 
99 		src_len -= 3;
100 		src += 3;
101 	}
102 
103 	if (src_len == 0) {
104 		goto out;
105 	}
106 
107 	raw_u32 = 0;
108 	memcpy(&raw_u32, src, src_len);
109 	raw_u32 = from_be32(&raw_u32);
110 
111 	*dst++ = enc_table[(raw_u32 >> 26) & BASE64_ENC_BITMASK];
112 	*dst++ = enc_table[(raw_u32 >> 20) & BASE64_ENC_BITMASK];
113 	*dst++ = (src_len >= 2) ? enc_table[(raw_u32 >> 14) & BASE64_ENC_BITMASK] : BASE64_PADDING_CHAR;
114 	*dst++ = (src_len == 3) ? enc_table[(raw_u32 >> 8) & BASE64_ENC_BITMASK] : BASE64_PADDING_CHAR;
115 
116 out:
117 	*dst = '\0';
118 
119 	return 0;
120 }
121 
122 int
123 spdk_base64_encode(char *dst, const void *src, size_t src_len)
124 {
125 	return base64_encode(dst, base64_enc_table, src, src_len);
126 }
127 
128 int
129 spdk_base64_urlsafe_encode(char *dst, const void *src, size_t src_len)
130 {
131 	return base64_encode(dst, base64_urlsafe_enc_table, src, src_len);
132 }
133 
134 #if defined(__aarch64__) && !defined(__ARM_FEATURE_SVE)
135 static int
136 base64_decode(void *dst, size_t *_dst_len, const uint8_t *dec_table,
137 	      const uint8_t *dec_table_opt, const char *src)
138 #else
139 static int
140 base64_decode(void *dst, size_t *_dst_len, const uint8_t *dec_table, const char *src)
141 #endif
142 {
143 	size_t src_strlen;
144 	size_t tail_len = 0;
145 	const uint8_t *src_in;
146 	uint32_t tmp[4];
147 	int i;
148 
149 	if (!src) {
150 		return -EINVAL;
151 	}
152 
153 	src_strlen = strlen(src);
154 
155 	/* strlen of src should be 4n */
156 	if (src_strlen == 0 || src_strlen % 4 != 0) {
157 		return -EINVAL;
158 	}
159 
160 	/* Consider Base64 padding, it at most has 2 padding characters. */
161 	for (i = 0; i < 2; i++) {
162 		if (src[src_strlen - 1] != BASE64_PADDING_CHAR) {
163 			break;
164 		}
165 		src_strlen--;
166 	}
167 
168 	/* strlen of src without padding shouldn't be 4n+1 */
169 	if (src_strlen == 0 || src_strlen % 4 == 1) {
170 		return -EINVAL;
171 	}
172 
173 	if (_dst_len) {
174 		*_dst_len = spdk_base64_get_decoded_len(src_strlen);
175 	}
176 
177 	/* If dst is NULL, the client is only concerned w/ _dst_len, return */
178 	if (!dst) {
179 		return 0;
180 	}
181 
182 	src_in = (const uint8_t *) src;
183 
184 #ifdef __aarch64__
185 #ifdef __ARM_FEATURE_SVE
186 	base64_decode_sve(&dst, dec_table, &src_in, &src_strlen);
187 #else
188 	base64_decode_neon64(&dst, dec_table_opt, &src_in, &src_strlen);
189 #endif
190 
191 	if (src_strlen == 0) {
192 		return 0;
193 	}
194 #endif
195 
196 
197 	/* space of dst can be used by to_be32 */
198 	while (src_strlen > 4) {
199 		tmp[0] = dec_table[*src_in++];
200 		tmp[1] = dec_table[*src_in++];
201 		tmp[2] = dec_table[*src_in++];
202 		tmp[3] = dec_table[*src_in++];
203 
204 		if (tmp[0] == 255 || tmp[1] == 255 || tmp[2] == 255 || tmp[3] == 255) {
205 			return -EINVAL;
206 		}
207 
208 		to_be32(dst, tmp[3] << 8 | tmp[2] << 14 | tmp[1] << 20 | tmp[0] << 26);
209 
210 		dst += 3;
211 		src_strlen -= 4;
212 	}
213 
214 	/* space of dst is not enough to be used by to_be32 */
215 	tmp[0] = dec_table[src_in[0]];
216 	tmp[1] = dec_table[src_in[1]];
217 	tmp[2] = (src_strlen >= 3) ? dec_table[src_in[2]] : 0;
218 	tmp[3] = (src_strlen == 4) ? dec_table[src_in[3]] : 0;
219 	tail_len = src_strlen - 1;
220 
221 	if (tmp[0] == 255 || tmp[1] == 255 || tmp[2] == 255 || tmp[3] == 255) {
222 		return -EINVAL;
223 	}
224 
225 	to_be32(&tmp[3], tmp[3] << 8 | tmp[2] << 14 | tmp[1] << 20 | tmp[0] << 26);
226 	memcpy(dst, (uint8_t *)&tmp[3], tail_len);
227 
228 	return 0;
229 }
230 
231 int
232 spdk_base64_decode(void *dst, size_t *dst_len, const char *src)
233 {
234 #if defined(__aarch64__) && !defined(__ARM_FEATURE_SVE)
235 	return base64_decode(dst, dst_len, base64_dec_table, base64_dec_table_neon64, src);
236 #else
237 	return base64_decode(dst, dst_len, base64_dec_table, src);
238 #endif
239 }
240 
241 int
242 spdk_base64_urlsafe_decode(void *dst, size_t *dst_len, const char *src)
243 {
244 #if defined(__aarch64__) && !defined(__ARM_FEATURE_SVE)
245 	return base64_decode(dst, dst_len, base64_urlsafe_dec_table, base64_urlsafe_dec_table_neon64,
246 			     src);
247 #else
248 	return base64_decode(dst, dst_len, base64_urlsafe_dec_table, src);
249 #endif
250 }
251