|
1 | 1 | #include <cassert> |
2 | 2 | #include <cstring> |
| 3 | +#include <cstdarg> |
3 | 4 | #include <algorithm> |
4 | 5 | #include <filesystem> |
5 | | -#include <system_error> |
6 | 6 | #include <boost/asio/version.hpp> |
7 | | -#include <openssl/bio.h> |
8 | | -#include <openssl/evp.h> |
9 | | -#include <openssl/buffer.h> |
10 | 7 | #include "http.h" |
11 | 8 |
|
12 | 9 | namespace fs = std::filesystem; |
@@ -742,39 +739,90 @@ namespace http |
742 | 739 |
|
743 | 740 | //---------------------------------------------------------------------------------------------------------------- |
744 | 741 |
|
745 | | - std::string base64_encode(std::string_view data) |
| 742 | + constexpr std::array<uint8_t, 64> base64_encode_table = { |
| 743 | + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', |
| 744 | + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', |
| 745 | + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' |
| 746 | + }; |
| 747 | + |
| 748 | + constexpr std::array<uint8_t, 256> base64_decoded_table = [] { |
| 749 | + std::array<uint8_t, 256> table{}; |
| 750 | + for (size_t i = 0 ; i < base64_encode_table.size() ; ++i) |
| 751 | + table[base64_encode_table[i]] = i; |
| 752 | + return table; |
| 753 | + }(); |
| 754 | + |
| 755 | + std::string base64_encode(const size_t ndata, const uint8_t* data) |
746 | 756 | { |
747 | | - BIO* b64 = BIO_new(BIO_f_base64()); |
748 | | - BIO* bio = BIO_new(BIO_s_mem()); |
749 | | - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); |
750 | | - bio = BIO_push(b64, bio); |
751 | | - |
752 | | - BIO_write(bio, data.data(), data.size()); |
753 | | - BIO_flush(bio); |
| 757 | + std::string ret; |
| 758 | + ret.reserve((ndata+2) / 3 * 4); |
| 759 | + uint8_t word{0}; |
| 760 | + uint8_t off{6}; |
| 761 | + |
| 762 | + for (size_t i = 0 ; i < ndata ; ++i) |
| 763 | + { |
| 764 | + const uint8_t byte = data[i]; |
| 765 | + |
| 766 | + for (int j = 7 ; j >= 0 ; --j) |
| 767 | + { |
| 768 | + const uint8_t bit = (byte >> j) & 0x1; |
| 769 | + |
| 770 | + word |= (bit << --off); |
| 771 | + |
| 772 | + if (off == 0) |
| 773 | + { |
| 774 | + assert(word < 64); |
| 775 | + ret.push_back(base64_encode_table[word]); |
| 776 | + off = 6; |
| 777 | + word = 0; |
| 778 | + } |
| 779 | + } |
| 780 | + } |
754 | 781 |
|
755 | | - BUF_MEM* buffer_ptr{nullptr}; |
756 | | - BIO_get_mem_ptr(bio, &buffer_ptr); |
| 782 | + assert(off == 6 || off == 2 || off == 4); |
757 | 783 |
|
758 | | - std::string encoded(buffer_ptr->data, buffer_ptr->length); |
759 | | - BIO_free_all(bio); |
760 | | - return encoded; |
| 784 | + if (off < 6) |
| 785 | + { |
| 786 | + const size_t npadding = off / 2; |
| 787 | + ret.push_back(base64_encode_table[word]); |
| 788 | + for (size_t i = 0 ; i < npadding ; ++i) |
| 789 | + ret.push_back('='); |
| 790 | + } |
| 791 | + |
| 792 | + return ret; |
761 | 793 | } |
762 | 794 |
|
763 | | - std::string base64_decode(std::string_view data) |
| 795 | + std::vector<uint8_t> base64_decode(std::string_view data) |
764 | 796 | { |
765 | | - BIO* b64 = BIO_new(BIO_f_base64()); |
766 | | - BIO* bio = BIO_new_mem_buf(data.data(), data.size()); |
767 | | - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); |
768 | | - bio = BIO_push(b64, bio); |
769 | | - |
770 | | - std::string output(data.size(), '\0'); // Base64 expands by 4/3, so input is always >= output |
771 | | - int decoded_len = BIO_read(bio, output.data(), output.size()); |
772 | | - if (decoded_len < 0) |
773 | | - fprintf(stderr, "Failed to base64 decode data\n"); |
774 | | - |
775 | | - output.resize(std::max(decoded_len, 0)); |
776 | | - BIO_free_all(bio); |
777 | | - return output; |
| 797 | + std::vector<uint8_t> ret; |
| 798 | + ret.reserve(data.size() / 4 * 3); |
| 799 | + uint8_t word{0}; |
| 800 | + uint8_t off{8}; |
| 801 | + |
| 802 | + for (size_t i = 0 ; i < data.size() ; ++i) |
| 803 | + { |
| 804 | + if (data[i] == '=') |
| 805 | + continue; |
| 806 | + |
| 807 | + const uint8_t sixtet = base64_decoded_table[data[i]]; |
| 808 | + |
| 809 | + for (int j = 5 ; j >= 0 ; --j) |
| 810 | + { |
| 811 | + const uint8_t bit = (sixtet >> j) & 0x1; |
| 812 | + |
| 813 | + word |= (bit << --off); |
| 814 | + |
| 815 | + if (off == 0) |
| 816 | + { |
| 817 | + assert(word < 256); |
| 818 | + ret.push_back(word); |
| 819 | + off = 8; |
| 820 | + word = 0; |
| 821 | + } |
| 822 | + } |
| 823 | + } |
| 824 | + |
| 825 | + return ret; |
778 | 826 | } |
779 | 827 |
|
780 | 828 | //---------------------------------------------------------------------------------------------------------------- |
|
0 commit comments