base64_rfc4648.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. #include "base64_rfc4648.hpp"
  2. #include <openssl/bio.h>
  3. #include <openssl/evp.h>
  4. #include "resource_wrapper.hpp"
  5. #include "resource_traits/openssl/bio.hpp"
  6. #include "resource_traits/openssl/bio_chain.hpp"
  7. #pragma comment(lib, "libcrypto")
  8. #pragma comment(lib, "crypt32") // required by libcrypto.lib
  9. #pragma comment(lib, "ws2_32") // required by libcrypto.lib
  10. #define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-keygen\\base64_rfc4648.cpp"
  11. #define NKG_CURRENT_SOURCE_LINE() __LINE__
  12. namespace nkg {
  13. std::string base64_rfc4648::encode(const std::vector<std::uint8_t>& data) {
  14. resource_wrapper bio_b64{ resource_traits::openssl::bio_chain{}, BIO_new(BIO_f_base64()) };
  15. if (bio_b64.is_valid() == false) {
  16. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
  17. }
  18. BIO_set_flags(bio_b64.get(), BIO_FLAGS_BASE64_NO_NL);
  19. resource_wrapper bio_memory{ resource_traits::openssl::bio{}, BIO_new(BIO_s_mem()) };
  20. if (bio_memory.is_valid() == false) {
  21. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
  22. }
  23. BIO_push(bio_b64.get(), bio_memory.get());
  24. for (size_t written_size = 0, left_size = data.size(); left_size != 0;) {
  25. int size_to_write = static_cast<int>(std::min(left_size, static_cast<size_t>(INT_MAX)));
  26. int r = BIO_write(bio_b64.get(), data.data() + written_size, size_to_write);
  27. if (r > 0) {
  28. written_size += r;
  29. left_size -= r;
  30. } else {
  31. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_write failed.");
  32. }
  33. }
  34. BIO_flush(bio_b64.get());
  35. const char* pch = nullptr;
  36. long lch = BIO_get_mem_data(bio_memory.get(), &pch);
  37. bio_memory.discard(); // the bio_chain `bio_b64` will free it
  38. return std::string(pch, lch);
  39. }
  40. std::vector<uint8_t> base64_rfc4648::decode(std::string_view b64_string) {
  41. resource_wrapper bio_b64{ resource_traits::openssl::bio_chain{}, BIO_new(BIO_f_base64()) };
  42. if (bio_b64.is_valid() == false) {
  43. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
  44. }
  45. BIO_set_flags(bio_b64.get(), BIO_FLAGS_BASE64_NO_NL);
  46. resource_wrapper bio_memory{ resource_traits::openssl::bio{}, BIO_new(BIO_s_mem()) };
  47. if (bio_memory.is_valid() == false) {
  48. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
  49. }
  50. BIO_push(bio_b64.get(), bio_memory.get());
  51. for (size_t written_length = 0, left_length = b64_string.length(); left_length != 0;) {
  52. int length_to_write = static_cast<int>(std::min(left_length, static_cast<size_t>(INT_MAX)));
  53. int r = BIO_write(bio_memory.get(), b64_string.data() + written_length, length_to_write);
  54. if (r > 0) {
  55. written_length += r;
  56. left_length -= r;
  57. } else {
  58. throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_write failed.");
  59. }
  60. }
  61. std::vector<uint8_t> retval;
  62. retval.reserve(b64_string.length() * 3 / 4 + 1);
  63. for (uint8_t buf[256];;) {
  64. auto len = BIO_read(bio_b64.get(), buf, sizeof(buf));
  65. if (len > 0) {
  66. retval.insert(retval.end(), buf, buf + len);
  67. } else {
  68. break;
  69. }
  70. }
  71. bio_memory.discard(); // the bio_chain `bio_b64` will free it
  72. return retval;
  73. }
  74. }
  75. #undef NKG_CURRENT_SOURCE_FILE
  76. #undef NKG_CURRENT_SOURCE_LINE