You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

base64.c 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. /*
  2. * Copyright 2023 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "config.h"
  17. #include "cryptobox.h"
  18. #include "base64.h"
  19. #include "platform_config.h"
  20. #include "str_util.h"
  21. #include "util.h"
  22. #include "contrib/libottery/ottery.h"
  23. extern unsigned cpu_config;
  24. const uint8_t
  25. base64_table_dec[256] =
  26. {
  27. 255,
  28. 255,
  29. 255,
  30. 255,
  31. 255,
  32. 255,
  33. 255,
  34. 255,
  35. 255,
  36. 255,
  37. 255,
  38. 255,
  39. 255,
  40. 255,
  41. 255,
  42. 255,
  43. 255,
  44. 255,
  45. 255,
  46. 255,
  47. 255,
  48. 255,
  49. 255,
  50. 255,
  51. 255,
  52. 255,
  53. 255,
  54. 255,
  55. 255,
  56. 255,
  57. 255,
  58. 255,
  59. 255,
  60. 255,
  61. 255,
  62. 255,
  63. 255,
  64. 255,
  65. 255,
  66. 255,
  67. 255,
  68. 255,
  69. 255,
  70. 62,
  71. 255,
  72. 255,
  73. 255,
  74. 63,
  75. 52,
  76. 53,
  77. 54,
  78. 55,
  79. 56,
  80. 57,
  81. 58,
  82. 59,
  83. 60,
  84. 61,
  85. 255,
  86. 255,
  87. 255,
  88. 254,
  89. 255,
  90. 255,
  91. 255,
  92. 0,
  93. 1,
  94. 2,
  95. 3,
  96. 4,
  97. 5,
  98. 6,
  99. 7,
  100. 8,
  101. 9,
  102. 10,
  103. 11,
  104. 12,
  105. 13,
  106. 14,
  107. 15,
  108. 16,
  109. 17,
  110. 18,
  111. 19,
  112. 20,
  113. 21,
  114. 22,
  115. 23,
  116. 24,
  117. 25,
  118. 255,
  119. 255,
  120. 255,
  121. 255,
  122. 255,
  123. 255,
  124. 26,
  125. 27,
  126. 28,
  127. 29,
  128. 30,
  129. 31,
  130. 32,
  131. 33,
  132. 34,
  133. 35,
  134. 36,
  135. 37,
  136. 38,
  137. 39,
  138. 40,
  139. 41,
  140. 42,
  141. 43,
  142. 44,
  143. 45,
  144. 46,
  145. 47,
  146. 48,
  147. 49,
  148. 50,
  149. 51,
  150. 255,
  151. 255,
  152. 255,
  153. 255,
  154. 255,
  155. 255,
  156. 255,
  157. 255,
  158. 255,
  159. 255,
  160. 255,
  161. 255,
  162. 255,
  163. 255,
  164. 255,
  165. 255,
  166. 255,
  167. 255,
  168. 255,
  169. 255,
  170. 255,
  171. 255,
  172. 255,
  173. 255,
  174. 255,
  175. 255,
  176. 255,
  177. 255,
  178. 255,
  179. 255,
  180. 255,
  181. 255,
  182. 255,
  183. 255,
  184. 255,
  185. 255,
  186. 255,
  187. 255,
  188. 255,
  189. 255,
  190. 255,
  191. 255,
  192. 255,
  193. 255,
  194. 255,
  195. 255,
  196. 255,
  197. 255,
  198. 255,
  199. 255,
  200. 255,
  201. 255,
  202. 255,
  203. 255,
  204. 255,
  205. 255,
  206. 255,
  207. 255,
  208. 255,
  209. 255,
  210. 255,
  211. 255,
  212. 255,
  213. 255,
  214. 255,
  215. 255,
  216. 255,
  217. 255,
  218. 255,
  219. 255,
  220. 255,
  221. 255,
  222. 255,
  223. 255,
  224. 255,
  225. 255,
  226. 255,
  227. 255,
  228. 255,
  229. 255,
  230. 255,
  231. 255,
  232. 255,
  233. 255,
  234. 255,
  235. 255,
  236. 255,
  237. 255,
  238. 255,
  239. 255,
  240. 255,
  241. 255,
  242. 255,
  243. 255,
  244. 255,
  245. 255,
  246. 255,
  247. 255,
  248. 255,
  249. 255,
  250. 255,
  251. 255,
  252. 255,
  253. 255,
  254. 255,
  255. 255,
  256. 255,
  257. 255,
  258. 255,
  259. 255,
  260. 255,
  261. 255,
  262. 255,
  263. 255,
  264. 255,
  265. 255,
  266. 255,
  267. 255,
  268. 255,
  269. 255,
  270. 255,
  271. 255,
  272. 255,
  273. 255,
  274. 255,
  275. 255,
  276. 255,
  277. 255,
  278. 255,
  279. 255,
  280. 255,
  281. 255,
  282. 255,
  283. };
  284. static const char base64_alphabet[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
  285. typedef struct base64_impl {
  286. unsigned short enabled;
  287. unsigned short min_len;
  288. unsigned int cpu_flags;
  289. const char *desc;
  290. int (*decode)(const char *in, size_t inlen,
  291. unsigned char *out, size_t *outlen);
  292. } base64_impl_t;
  293. #define BASE64_DECLARE(ext) \
  294. int base64_decode_##ext(const char *in, size_t inlen, unsigned char *out, size_t *outlen);
  295. #define BASE64_IMPL(cpuflags, min_len, desc, ext) \
  296. { \
  297. 0, (min_len), (cpuflags), desc, base64_decode_##ext \
  298. }
  299. BASE64_DECLARE(ref);
  300. #define BASE64_REF BASE64_IMPL(0, 0, "ref", ref)
  301. #ifdef RSPAMD_HAS_TARGET_ATTR
  302. #if defined(HAVE_SSE42) && defined(__x86_64__)
  303. int base64_decode_sse42(const char *in, size_t inlen,
  304. unsigned char *out, size_t *outlen) __attribute__((__target__("sse4.2")));
  305. BASE64_DECLARE(sse42);
  306. #define BASE64_SSE42 BASE64_IMPL(CPUID_SSE42, 24, "sse42", sse42)
  307. #endif
  308. #endif
  309. #ifdef RSPAMD_HAS_TARGET_ATTR
  310. #if defined(HAVE_AVX2) && defined(__x86_64__)
  311. int base64_decode_avx2(const char *in, size_t inlen,
  312. unsigned char *out, size_t *outlen) __attribute__((__target__("avx2")));
  313. BASE64_DECLARE(avx2);
  314. #define BASE64_AVX2 BASE64_IMPL(CPUID_AVX2, 128, "avx2", avx2)
  315. #endif
  316. #endif
  317. static base64_impl_t base64_list[] = {
  318. BASE64_REF,
  319. #ifdef BASE64_SSE42
  320. BASE64_SSE42,
  321. #endif
  322. #ifdef BASE64_AVX2
  323. BASE64_AVX2,
  324. #endif
  325. };
  326. static const base64_impl_t *base64_ref = &base64_list[0];
  327. const char *
  328. base64_load(void)
  329. {
  330. unsigned int i;
  331. const base64_impl_t *opt_impl = base64_ref;
  332. /* Enable reference */
  333. base64_list[0].enabled = true;
  334. if (cpu_config != 0) {
  335. for (i = 1; i < G_N_ELEMENTS(base64_list); i++) {
  336. if (base64_list[i].cpu_flags & cpu_config) {
  337. base64_list[i].enabled = true;
  338. opt_impl = &base64_list[i];
  339. }
  340. }
  341. }
  342. return opt_impl->desc;
  343. }
  344. gboolean
  345. rspamd_cryptobox_base64_decode(const char *in, gsize inlen,
  346. unsigned char *out, gsize *outlen)
  347. {
  348. const base64_impl_t *opt_impl = base64_ref;
  349. for (int i = G_N_ELEMENTS(base64_list) - 1; i > 0; i--) {
  350. if (base64_list[i].enabled && base64_list[i].min_len <= inlen) {
  351. opt_impl = &base64_list[i];
  352. break;
  353. }
  354. }
  355. return opt_impl->decode(in, inlen, out, outlen);
  356. }
  357. double
  358. base64_test(bool generic, size_t niters, size_t len, size_t str_len)
  359. {
  360. size_t cycles;
  361. unsigned char *in, *out, *tmp;
  362. double t1, t2, total = 0;
  363. gsize outlen;
  364. g_assert(len > 0);
  365. in = g_malloc(len);
  366. tmp = g_malloc(len);
  367. ottery_rand_bytes(in, len);
  368. out = rspamd_encode_base64_fold(in, len, str_len, &outlen,
  369. RSPAMD_TASK_NEWLINES_CRLF);
  370. if (generic) {
  371. base64_list[0].decode(out, outlen, tmp, &len);
  372. }
  373. else {
  374. rspamd_cryptobox_base64_decode(out, outlen, tmp, &len);
  375. }
  376. g_assert(memcmp(in, tmp, len) == 0);
  377. for (cycles = 0; cycles < niters; cycles++) {
  378. t1 = rspamd_get_ticks(TRUE);
  379. if (generic) {
  380. base64_list[0].decode(out, outlen, tmp, &len);
  381. }
  382. else {
  383. rspamd_cryptobox_base64_decode(out, outlen, tmp, &len);
  384. }
  385. t2 = rspamd_get_ticks(TRUE);
  386. total += t2 - t1;
  387. }
  388. g_free(in);
  389. g_free(tmp);
  390. g_free(out);
  391. return total;
  392. }
  393. gboolean
  394. rspamd_cryptobox_base64_is_valid(const char *in, gsize inlen)
  395. {
  396. const unsigned char *p, *end;
  397. if (inlen == 0) {
  398. return FALSE;
  399. }
  400. p = in;
  401. end = in + inlen;
  402. while (p < end && *p != '=') {
  403. if (!g_ascii_isspace(*p)) {
  404. if (base64_table_dec[*p] == 255) {
  405. return FALSE;
  406. }
  407. }
  408. p++;
  409. }
  410. return TRUE;
  411. }