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