1488570ebSJim Harris /* SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse * Copyright (C) 2018 Intel Corporation. All rights reserved.
3d483d8a4SRui Chang * Copyright(c) ARM Limited. 2021 All rights reserved.
48aaa7079SLiu Xiaodong * All rights reserved.
58aaa7079SLiu Xiaodong */
68aaa7079SLiu Xiaodong
78aaa7079SLiu Xiaodong #include "spdk/stdinc.h"
88aaa7079SLiu Xiaodong #include "spdk/endian.h"
98aaa7079SLiu Xiaodong #include "spdk/base64.h"
108aaa7079SLiu Xiaodong
11a41fb6e6SRichael Zhuang #ifdef __aarch64__
12d483d8a4SRui Chang #ifdef __ARM_FEATURE_SVE
13d483d8a4SRui Chang #include "base64_sve.c"
14d483d8a4SRui Chang #else
15a41fb6e6SRichael Zhuang #include "base64_neon.c"
16a41fb6e6SRichael Zhuang #endif
17d483d8a4SRui Chang #endif
18d483d8a4SRui Chang
19a41fb6e6SRichael Zhuang
208aaa7079SLiu Xiaodong #define BASE64_ENC_BITMASK 0x3FUL
218aaa7079SLiu Xiaodong #define BASE64_PADDING_CHAR '='
228aaa7079SLiu Xiaodong
238aaa7079SLiu Xiaodong static const char base64_enc_table[] =
248aaa7079SLiu Xiaodong "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
258aaa7079SLiu Xiaodong "abcdefghijklmnopqrstuvwxyz"
268aaa7079SLiu Xiaodong "0123456789+/";
278aaa7079SLiu Xiaodong
28cc6920a4SJosh Soref static const char base64_urlsafe_enc_table[] =
298aaa7079SLiu Xiaodong "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
308aaa7079SLiu Xiaodong "abcdefghijklmnopqrstuvwxyz"
318aaa7079SLiu Xiaodong "0123456789-_";
328aaa7079SLiu Xiaodong
338aaa7079SLiu Xiaodong static const uint8_t
348aaa7079SLiu Xiaodong base64_dec_table[] = {
358aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
368aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
378aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
388aaa7079SLiu Xiaodong 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255,
398aaa7079SLiu Xiaodong 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
408aaa7079SLiu Xiaodong 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
418aaa7079SLiu Xiaodong 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
428aaa7079SLiu Xiaodong 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255,
438aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
448aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
458aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
468aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
478aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
488aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
498aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
508aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
518aaa7079SLiu Xiaodong };
528aaa7079SLiu Xiaodong
538aaa7079SLiu Xiaodong static const uint8_t
548aaa7079SLiu Xiaodong base64_urlsafe_dec_table[] = {
558aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
568aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
578aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255,
588aaa7079SLiu Xiaodong 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255,
598aaa7079SLiu Xiaodong 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
608aaa7079SLiu Xiaodong 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 63,
618aaa7079SLiu Xiaodong 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
628aaa7079SLiu Xiaodong 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255,
638aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
648aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
658aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
668aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
678aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
688aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
698aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
708aaa7079SLiu Xiaodong 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
718aaa7079SLiu Xiaodong };
728aaa7079SLiu Xiaodong
738aaa7079SLiu Xiaodong static int
base64_encode(char * dst,const char * enc_table,const void * src,size_t src_len)7457c2b0c5SSeth Howell base64_encode(char *dst, const char *enc_table, const void *src, size_t src_len)
758aaa7079SLiu Xiaodong {
768aaa7079SLiu Xiaodong uint32_t raw_u32;
778aaa7079SLiu Xiaodong
788aaa7079SLiu Xiaodong if (!dst || !src || src_len <= 0) {
798aaa7079SLiu Xiaodong return -EINVAL;
808aaa7079SLiu Xiaodong }
818aaa7079SLiu Xiaodong
82a41fb6e6SRichael Zhuang #ifdef __aarch64__
83d483d8a4SRui Chang #ifdef __ARM_FEATURE_SVE
84d483d8a4SRui Chang base64_encode_sve(&dst, enc_table, &src, &src_len);
85d483d8a4SRui Chang #else
8657c2b0c5SSeth Howell base64_encode_neon64(&dst, enc_table, &src, &src_len);
87a41fb6e6SRichael Zhuang #endif
88d483d8a4SRui Chang #endif
89d483d8a4SRui Chang
90a41fb6e6SRichael Zhuang
918aaa7079SLiu Xiaodong while (src_len >= 4) {
928aaa7079SLiu Xiaodong raw_u32 = from_be32(src);
938aaa7079SLiu Xiaodong
948aaa7079SLiu Xiaodong *dst++ = enc_table[(raw_u32 >> 26) & BASE64_ENC_BITMASK];
958aaa7079SLiu Xiaodong *dst++ = enc_table[(raw_u32 >> 20) & BASE64_ENC_BITMASK];
968aaa7079SLiu Xiaodong *dst++ = enc_table[(raw_u32 >> 14) & BASE64_ENC_BITMASK];
978aaa7079SLiu Xiaodong *dst++ = enc_table[(raw_u32 >> 8) & BASE64_ENC_BITMASK];
988aaa7079SLiu Xiaodong
998aaa7079SLiu Xiaodong src_len -= 3;
100*075d422fSKonrad Sztyber src = (uint8_t *)src + 3;
1018aaa7079SLiu Xiaodong }
1028aaa7079SLiu Xiaodong
1038aaa7079SLiu Xiaodong if (src_len == 0) {
1048aaa7079SLiu Xiaodong goto out;
1058aaa7079SLiu Xiaodong }
1068aaa7079SLiu Xiaodong
1078aaa7079SLiu Xiaodong raw_u32 = 0;
1088aaa7079SLiu Xiaodong memcpy(&raw_u32, src, src_len);
1098aaa7079SLiu Xiaodong raw_u32 = from_be32(&raw_u32);
1108aaa7079SLiu Xiaodong
1118aaa7079SLiu Xiaodong *dst++ = enc_table[(raw_u32 >> 26) & BASE64_ENC_BITMASK];
1128aaa7079SLiu Xiaodong *dst++ = enc_table[(raw_u32 >> 20) & BASE64_ENC_BITMASK];
1138aaa7079SLiu Xiaodong *dst++ = (src_len >= 2) ? enc_table[(raw_u32 >> 14) & BASE64_ENC_BITMASK] : BASE64_PADDING_CHAR;
1148aaa7079SLiu Xiaodong *dst++ = (src_len == 3) ? enc_table[(raw_u32 >> 8) & BASE64_ENC_BITMASK] : BASE64_PADDING_CHAR;
1158aaa7079SLiu Xiaodong
1168aaa7079SLiu Xiaodong out:
1178aaa7079SLiu Xiaodong *dst = '\0';
1188aaa7079SLiu Xiaodong
1198aaa7079SLiu Xiaodong return 0;
1208aaa7079SLiu Xiaodong }
1218aaa7079SLiu Xiaodong
1228aaa7079SLiu Xiaodong int
spdk_base64_encode(char * dst,const void * src,size_t src_len)1238aaa7079SLiu Xiaodong spdk_base64_encode(char *dst, const void *src, size_t src_len)
1248aaa7079SLiu Xiaodong {
12557c2b0c5SSeth Howell return base64_encode(dst, base64_enc_table, src, src_len);
1268aaa7079SLiu Xiaodong }
1278aaa7079SLiu Xiaodong
1288aaa7079SLiu Xiaodong int
spdk_base64_urlsafe_encode(char * dst,const void * src,size_t src_len)1298aaa7079SLiu Xiaodong spdk_base64_urlsafe_encode(char *dst, const void *src, size_t src_len)
1308aaa7079SLiu Xiaodong {
131cc6920a4SJosh Soref return base64_encode(dst, base64_urlsafe_enc_table, src, src_len);
1328aaa7079SLiu Xiaodong }
1338aaa7079SLiu Xiaodong
134d483d8a4SRui Chang #if defined(__aarch64__) && !defined(__ARM_FEATURE_SVE)
135a41fb6e6SRichael Zhuang static int
base64_decode(void * dst,size_t * _dst_len,const uint8_t * dec_table,const uint8_t * dec_table_opt,const char * src)13657c2b0c5SSeth Howell base64_decode(void *dst, size_t *_dst_len, const uint8_t *dec_table,
137a41fb6e6SRichael Zhuang const uint8_t *dec_table_opt, const char *src)
138a41fb6e6SRichael Zhuang #else
1398aaa7079SLiu Xiaodong static int
14057c2b0c5SSeth Howell base64_decode(void *dst, size_t *_dst_len, const uint8_t *dec_table, const char *src)
141a41fb6e6SRichael Zhuang #endif
1428aaa7079SLiu Xiaodong {
143a41fb6e6SRichael Zhuang size_t src_strlen;
1448aaa7079SLiu Xiaodong size_t tail_len = 0;
1458aaa7079SLiu Xiaodong const uint8_t *src_in;
1468aaa7079SLiu Xiaodong uint32_t tmp[4];
1478aaa7079SLiu Xiaodong int i;
1488aaa7079SLiu Xiaodong
14906fc4cadSMike Carlin if (!src) {
1508aaa7079SLiu Xiaodong return -EINVAL;
1518aaa7079SLiu Xiaodong }
1528aaa7079SLiu Xiaodong
1538aaa7079SLiu Xiaodong src_strlen = strlen(src);
1548aaa7079SLiu Xiaodong
1558aaa7079SLiu Xiaodong /* strlen of src should be 4n */
1568aaa7079SLiu Xiaodong if (src_strlen == 0 || src_strlen % 4 != 0) {
1578aaa7079SLiu Xiaodong return -EINVAL;
1588aaa7079SLiu Xiaodong }
1598aaa7079SLiu Xiaodong
1608aaa7079SLiu Xiaodong /* Consider Base64 padding, it at most has 2 padding characters. */
1618aaa7079SLiu Xiaodong for (i = 0; i < 2; i++) {
1628aaa7079SLiu Xiaodong if (src[src_strlen - 1] != BASE64_PADDING_CHAR) {
1638aaa7079SLiu Xiaodong break;
1648aaa7079SLiu Xiaodong }
1658aaa7079SLiu Xiaodong src_strlen--;
1668aaa7079SLiu Xiaodong }
1678aaa7079SLiu Xiaodong
1688aaa7079SLiu Xiaodong /* strlen of src without padding shouldn't be 4n+1 */
1698aaa7079SLiu Xiaodong if (src_strlen == 0 || src_strlen % 4 == 1) {
1708aaa7079SLiu Xiaodong return -EINVAL;
1718aaa7079SLiu Xiaodong }
1728aaa7079SLiu Xiaodong
173a41fb6e6SRichael Zhuang if (_dst_len) {
174a41fb6e6SRichael Zhuang *_dst_len = spdk_base64_get_decoded_len(src_strlen);
175a41fb6e6SRichael Zhuang }
17606fc4cadSMike Carlin
17706fc4cadSMike Carlin /* If dst is NULL, the client is only concerned w/ _dst_len, return */
17806fc4cadSMike Carlin if (!dst) {
17906fc4cadSMike Carlin return 0;
18006fc4cadSMike Carlin }
18106fc4cadSMike Carlin
1828aaa7079SLiu Xiaodong src_in = (const uint8_t *) src;
1838aaa7079SLiu Xiaodong
184a41fb6e6SRichael Zhuang #ifdef __aarch64__
185d483d8a4SRui Chang #ifdef __ARM_FEATURE_SVE
186d483d8a4SRui Chang base64_decode_sve(&dst, dec_table, &src_in, &src_strlen);
187d483d8a4SRui Chang #else
18857c2b0c5SSeth Howell base64_decode_neon64(&dst, dec_table_opt, &src_in, &src_strlen);
189d483d8a4SRui Chang #endif
190a41fb6e6SRichael Zhuang
191a41fb6e6SRichael Zhuang if (src_strlen == 0) {
192a41fb6e6SRichael Zhuang return 0;
193a41fb6e6SRichael Zhuang }
194a41fb6e6SRichael Zhuang #endif
195a41fb6e6SRichael Zhuang
196d483d8a4SRui Chang
1978aaa7079SLiu Xiaodong /* space of dst can be used by to_be32 */
1988aaa7079SLiu Xiaodong while (src_strlen > 4) {
1998aaa7079SLiu Xiaodong tmp[0] = dec_table[*src_in++];
2008aaa7079SLiu Xiaodong tmp[1] = dec_table[*src_in++];
2018aaa7079SLiu Xiaodong tmp[2] = dec_table[*src_in++];
2028aaa7079SLiu Xiaodong tmp[3] = dec_table[*src_in++];
2038aaa7079SLiu Xiaodong
2048aaa7079SLiu Xiaodong if (tmp[0] == 255 || tmp[1] == 255 || tmp[2] == 255 || tmp[3] == 255) {
2058aaa7079SLiu Xiaodong return -EINVAL;
2068aaa7079SLiu Xiaodong }
2078aaa7079SLiu Xiaodong
2088aaa7079SLiu Xiaodong to_be32(dst, tmp[3] << 8 | tmp[2] << 14 | tmp[1] << 20 | tmp[0] << 26);
2098aaa7079SLiu Xiaodong
210*075d422fSKonrad Sztyber dst = (uint8_t *)dst + 3;
2118aaa7079SLiu Xiaodong src_strlen -= 4;
2128aaa7079SLiu Xiaodong }
2138aaa7079SLiu Xiaodong
2148aaa7079SLiu Xiaodong /* space of dst is not enough to be used by to_be32 */
2158aaa7079SLiu Xiaodong tmp[0] = dec_table[src_in[0]];
2168aaa7079SLiu Xiaodong tmp[1] = dec_table[src_in[1]];
2178aaa7079SLiu Xiaodong tmp[2] = (src_strlen >= 3) ? dec_table[src_in[2]] : 0;
2188aaa7079SLiu Xiaodong tmp[3] = (src_strlen == 4) ? dec_table[src_in[3]] : 0;
2198aaa7079SLiu Xiaodong tail_len = src_strlen - 1;
2208aaa7079SLiu Xiaodong
2218aaa7079SLiu Xiaodong if (tmp[0] == 255 || tmp[1] == 255 || tmp[2] == 255 || tmp[3] == 255) {
2228aaa7079SLiu Xiaodong return -EINVAL;
2238aaa7079SLiu Xiaodong }
2248aaa7079SLiu Xiaodong
2258aaa7079SLiu Xiaodong to_be32(&tmp[3], tmp[3] << 8 | tmp[2] << 14 | tmp[1] << 20 | tmp[0] << 26);
2268aaa7079SLiu Xiaodong memcpy(dst, (uint8_t *)&tmp[3], tail_len);
2278aaa7079SLiu Xiaodong
2288aaa7079SLiu Xiaodong return 0;
2298aaa7079SLiu Xiaodong }
2308aaa7079SLiu Xiaodong
2318aaa7079SLiu Xiaodong int
spdk_base64_decode(void * dst,size_t * dst_len,const char * src)2328aaa7079SLiu Xiaodong spdk_base64_decode(void *dst, size_t *dst_len, const char *src)
2338aaa7079SLiu Xiaodong {
234d483d8a4SRui Chang #if defined(__aarch64__) && !defined(__ARM_FEATURE_SVE)
23557c2b0c5SSeth Howell return base64_decode(dst, dst_len, base64_dec_table, base64_dec_table_neon64, src);
236a41fb6e6SRichael Zhuang #else
23757c2b0c5SSeth Howell return base64_decode(dst, dst_len, base64_dec_table, src);
238a41fb6e6SRichael Zhuang #endif
2398aaa7079SLiu Xiaodong }
2408aaa7079SLiu Xiaodong
2418aaa7079SLiu Xiaodong int
spdk_base64_urlsafe_decode(void * dst,size_t * dst_len,const char * src)2428aaa7079SLiu Xiaodong spdk_base64_urlsafe_decode(void *dst, size_t *dst_len, const char *src)
2438aaa7079SLiu Xiaodong {
244d483d8a4SRui Chang #if defined(__aarch64__) && !defined(__ARM_FEATURE_SVE)
24557c2b0c5SSeth Howell return base64_decode(dst, dst_len, base64_urlsafe_dec_table, base64_urlsafe_dec_table_neon64,
246a41fb6e6SRichael Zhuang src);
247a41fb6e6SRichael Zhuang #else
24857c2b0c5SSeth Howell return base64_decode(dst, dst_len, base64_urlsafe_dec_table, src);
249a41fb6e6SRichael Zhuang #endif
2508aaa7079SLiu Xiaodong }
251