base64_rfc4648.cpp 3.5 KB

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