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
base64_encode(char * dst,const char * enc_table,const void * src,size_t src_len)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 = (uint8_t *)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
spdk_base64_encode(char * dst,const void * src,size_t src_len)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
spdk_base64_urlsafe_encode(char * dst,const void * src,size_t src_len)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
base64_decode(void * dst,size_t * _dst_len,const uint8_t * dec_table,const uint8_t * dec_table_opt,const char * src)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 = (uint8_t *)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
spdk_base64_decode(void * dst,size_t * dst_len,const char * src)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
spdk_base64_urlsafe_decode(void * dst,size_t * dst_len,const char * src)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