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