Line data Source code
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 18 : base64_encode(char *dst, const char *enc_table, const void *src, size_t src_len)
75 : {
76 : uint32_t raw_u32;
77 :
78 18 : if (!dst || !src || src_len <= 0) {
79 6 : 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 118 : while (src_len >= 4) {
92 106 : raw_u32 = from_be32(src);
93 :
94 106 : *dst++ = enc_table[(raw_u32 >> 26) & BASE64_ENC_BITMASK];
95 106 : *dst++ = enc_table[(raw_u32 >> 20) & BASE64_ENC_BITMASK];
96 106 : *dst++ = enc_table[(raw_u32 >> 14) & BASE64_ENC_BITMASK];
97 106 : *dst++ = enc_table[(raw_u32 >> 8) & BASE64_ENC_BITMASK];
98 :
99 106 : src_len -= 3;
100 106 : src = (uint8_t *)src + 3;
101 : }
102 :
103 12 : if (src_len == 0) {
104 0 : goto out;
105 : }
106 :
107 12 : raw_u32 = 0;
108 12 : memcpy(&raw_u32, src, src_len);
109 12 : raw_u32 = from_be32(&raw_u32);
110 :
111 12 : *dst++ = enc_table[(raw_u32 >> 26) & BASE64_ENC_BITMASK];
112 12 : *dst++ = enc_table[(raw_u32 >> 20) & BASE64_ENC_BITMASK];
113 12 : *dst++ = (src_len >= 2) ? enc_table[(raw_u32 >> 14) & BASE64_ENC_BITMASK] : BASE64_PADDING_CHAR;
114 12 : *dst++ = (src_len == 3) ? enc_table[(raw_u32 >> 8) & BASE64_ENC_BITMASK] : BASE64_PADDING_CHAR;
115 :
116 12 : out:
117 12 : *dst = '\0';
118 :
119 12 : return 0;
120 : }
121 :
122 : int
123 9 : spdk_base64_encode(char *dst, const void *src, size_t src_len)
124 : {
125 9 : return base64_encode(dst, base64_enc_table, src, src_len);
126 : }
127 :
128 : int
129 9 : spdk_base64_urlsafe_encode(char *dst, const void *src, size_t src_len)
130 : {
131 9 : 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 35 : 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 35 : size_t tail_len = 0;
145 : const uint8_t *src_in;
146 : uint32_t tmp[4];
147 : int i;
148 :
149 35 : if (!src) {
150 2 : return -EINVAL;
151 : }
152 :
153 33 : src_strlen = strlen(src);
154 :
155 : /* strlen of src should be 4n */
156 33 : if (src_strlen == 0 || src_strlen % 4 != 0) {
157 6 : return -EINVAL;
158 : }
159 :
160 : /* Consider Base64 padding, it at most has 2 padding characters. */
161 51 : for (i = 0; i < 2; i++) {
162 41 : if (src[src_strlen - 1] != BASE64_PADDING_CHAR) {
163 17 : break;
164 : }
165 24 : src_strlen--;
166 : }
167 :
168 : /* strlen of src without padding shouldn't be 4n+1 */
169 27 : if (src_strlen == 0 || src_strlen % 4 == 1) {
170 0 : return -EINVAL;
171 : }
172 :
173 27 : if (_dst_len) {
174 27 : *_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 27 : if (!dst) {
179 12 : return 0;
180 : }
181 :
182 15 : 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 134 : while (src_strlen > 4) {
199 119 : tmp[0] = dec_table[*src_in++];
200 119 : tmp[1] = dec_table[*src_in++];
201 119 : tmp[2] = dec_table[*src_in++];
202 119 : tmp[3] = dec_table[*src_in++];
203 :
204 119 : if (tmp[0] == 255 || tmp[1] == 255 || tmp[2] == 255 || tmp[3] == 255) {
205 0 : return -EINVAL;
206 : }
207 :
208 119 : to_be32(dst, tmp[3] << 8 | tmp[2] << 14 | tmp[1] << 20 | tmp[0] << 26);
209 :
210 119 : dst = (uint8_t *)dst + 3;
211 119 : src_strlen -= 4;
212 : }
213 :
214 : /* space of dst is not enough to be used by to_be32 */
215 15 : tmp[0] = dec_table[src_in[0]];
216 15 : tmp[1] = dec_table[src_in[1]];
217 15 : tmp[2] = (src_strlen >= 3) ? dec_table[src_in[2]] : 0;
218 15 : tmp[3] = (src_strlen == 4) ? dec_table[src_in[3]] : 0;
219 15 : tail_len = src_strlen - 1;
220 :
221 15 : if (tmp[0] == 255 || tmp[1] == 255 || tmp[2] == 255 || tmp[3] == 255) {
222 2 : return -EINVAL;
223 : }
224 :
225 13 : to_be32(&tmp[3], tmp[3] << 8 | tmp[2] << 14 | tmp[1] << 20 | tmp[0] << 26);
226 13 : memcpy(dst, (uint8_t *)&tmp[3], tail_len);
227 :
228 13 : return 0;
229 : }
230 :
231 : int
232 18 : 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 18 : return base64_decode(dst, dst_len, base64_dec_table, src);
238 : #endif
239 : }
240 :
241 : int
242 17 : 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 17 : return base64_decode(dst, dst_len, base64_urlsafe_dec_table, src);
249 : #endif
250 : }
|