// // Created by imper on 10/10/21. // #ifndef XOR_CRYPT #define XOR_CRYPT #include #include #include #include "log-console" #include #include #include #include #define LOG_COLOR color::faint << color::yellow #define ERR_COLOR color::red #define PRINT_PREFIX _detail_::_log_ << log_console::l_lock << log_console::l_localtime << l_location #define LOG (PRINT_PREFIX << LOG_COLOR) #define ERR (PRINT_PREFIX << ERR_COLOR) #define ENDENTLN color::reset << log_console::l_endent namespace xc { namespace pipe { enum : int { read = 0, write, size }; } namespace _detail_ __attribute__((visibility("hidden"))) { extern log_console _log_; extern log_console _err_; } typedef unsigned char byte; typedef unsigned long size_t; template concept string_type = std::is_same_v || std::is_same_v; static inline void turn_logging(bool status = false) { xc::_detail_::_log_ << (status ? log_console::on : log_console::off); } static inline constexpr byte* copy_data_to(const void* data, byte* to, size_t size) { auto* tmp = static_cast(data); if (data == to) return to; if (!to || !data) return nullptr; for (size_t i = 0; i < size; ++i) to[i] = tmp[i]; return to; } static inline constexpr byte* copy_data(const void* data, size_t size) { auto* res = size && data ? new byte[size] : nullptr; return copy_data_to(data, res, size); } class buffer { public: inline buffer() noexcept: m_mem(nullptr), m_capacity(0) { } inline buffer(size_t size) noexcept: m_mem(new byte[size]), m_capacity(size) { } inline buffer(void* buffer, size_t size) noexcept: m_mem(static_cast(buffer)), m_capacity(size) { } inline buffer(const buffer& another) noexcept: m_mem(copy_data(another.m_mem, another.m_capacity)), m_capacity(another.m_capacity) { } inline buffer(buffer&& another) noexcept: m_mem(another.m_mem), m_capacity(another.m_capacity) { another.m_capacity = 0; another.m_mem = nullptr; LOG << "Pointer " << static_cast(m_mem) << color::reset << LOG_COLOR << " from buffer " << static_cast(&another) << color::reset << LOG_COLOR << " moved to buffer " << static_cast(this) << color::reset << LOG_COLOR << "\nCapacity = " << m_capacity << ENDENTLN; } [[nodiscard]] inline size_t capacity() const { return m_capacity; } inline void realloc(size_t size) { LOG << "Deallocating buffer " << m_mem << color::reset << LOG_COLOR << " of size " << m_capacity << color::reset << LOG_COLOR << "..." << ENDENTLN; delete[] m_mem; m_capacity = size; m_mem = new byte[size]; LOG << "Allocated new buffer " << m_mem << color::reset << LOG_COLOR << " of size " << m_capacity << ENDENTLN; } inline void dealloc() { LOG << "Deallocating buffer " << m_mem << color::reset << LOG_COLOR << " of size " << m_capacity << color::reset << LOG_COLOR << "..." << ENDENTLN; delete[] m_mem; LOG << "Deallocated buffer " << m_mem << ENDENTLN; m_capacity = 0; m_mem = nullptr; } [[nodiscard]] inline void* clone_mem() const { return copy_data(m_mem, m_capacity); } inline size_t clone_mem(void* res, size_t size) const { size_t ret_size = std::min(size, m_capacity); copy_data_to(m_mem, static_cast(res), ret_size); return ret_size; } [[nodiscard]] inline const void* get() const { return m_mem; } [[nodiscard]] inline void* get() { return m_mem; } inline void* abort_mem() { void* res = m_mem; LOG << "Released buffer " << m_mem << color::reset << LOG_COLOR << " of size " << m_capacity << ENDENTLN; m_capacity = 0; m_mem = nullptr; return res; } inline void from(const void* data, size_t size) { delete[] m_mem; m_capacity = size; m_mem = copy_data(data, size); LOG << "Created buffer " << m_mem << color::reset << LOG_COLOR << " of size " << m_capacity << color::reset << LOG_COLOR << " from given " << data << ENDENTLN; } inline void take(void* data, size_t size) { delete[] m_mem; m_capacity = size; m_mem = static_cast(data); LOG << "Captured buffer " << m_mem << color::reset << LOG_COLOR << " of size " << m_capacity << ENDENTLN; } private: byte* m_mem; size_t m_capacity; }; class source { public: source(const source&) = delete; inline source(source&&) = default; inline operator bool() const { return last_read > 0; } [[nodiscard]] inline virtual size_t available() = 0; inline virtual ssize_t read(void* data, size_t size) { ssize_t read = ::read(fd, data, size); last_read = read; if (read < 0) { char error[128]; ::strerror_r(errno, error, 128); ERR << "error " << errno << " in read() " << color::italic << error << ENDENTLN; } return read; } [[nodiscard]] inline ssize_t get_last_read() const { return last_read; } inline void close() { if (fd > 0) { if (::close(fd) < 0) { char error[128]; ::strerror_r(errno, error, 128); ERR << "error " << errno << " in close() " << color::italic << error << ENDENTLN; } fd = -1; } } inline ~source() = default; protected: friend class xor_decrypt; ssize_t last_read = -1; int fd; explicit source(int fd) : fd(fd) { } }; class empty_source : public source { public: inline empty_source() : source(-1) { } [[nodiscard]] inline size_t available() override { return 0; } inline ssize_t read(void*, size_t) override { last_read = -1; return -1; } }; class file_source : public source { public: inline explicit file_source(FILE* file_ptr) : source(file_ptr->_fileno) { } [[nodiscard]] inline size_t available() override { struct stat st{ }; ::fstat(fd, &st); return st.st_size; } inline ssize_t read(void* data, size_t size) override { return source::read(data, size); } }; class stream_source : public source { public: inline explicit stream_source(int stream_fd) : source(stream_fd) { } inline explicit stream_source(FILE* stream_ptr) : stream_source(stream_ptr->_fileno) { } [[nodiscard]] inline size_t available() override { long available; ::ioctl(fd, FIONREAD, &available); if (available <= 0) ::ioctl(fd, FIOQSIZE, &available); return available; } inline ssize_t read(void* data, size_t size) override { return source::read(data, size); } }; class buffer_source : public source { public: inline explicit buffer_source(buffer* buffer) : source(-1), buf(buffer) { } [[nodiscard]] inline size_t available() override { return buf->capacity(); } inline ssize_t read(void* data, size_t size) override { return buf->clone_mem(data, size); } private: buffer* buf; }; class destination { public: destination(const destination&) = delete; inline destination(destination&&) = default; inline operator bool() const { return last_write > 0; } inline virtual ssize_t write(const void* data, size_t size) { ssize_t wrote = ::write(fd, data, size); last_write = wrote; if (wrote < 0) { char error[128]; ::strerror_r(errno, error, 128); ERR << "error " << errno << " in write() " << color::italic << error << ENDENTLN; } return wrote; } [[nodiscard]] inline ssize_t get_last_write() const { return last_write; } inline void close() { if (fd > 0) { if (::close(fd) < 0) { char error[128]; ::strerror_r(errno, error, 128); ERR << "error " << errno << " in close() " << color::italic << error << ENDENTLN; } fd = -1; } } inline ~destination() = default; protected: friend class xor_encrypt; ssize_t last_write = -1; int fd; explicit destination(int fd) : fd(fd) { } }; class empty_destination : public destination { public: empty_destination() : destination(-1) { } ssize_t write(const void*, size_t) override { last_write = -1; return -1; } }; class file_destination : public destination { public: explicit file_destination(FILE* file_ptr) : destination(file_ptr->_fileno) { } ssize_t write(const void* data, size_t size) override { return destination::write(data, size); } }; class stream_destination : public destination { public: explicit stream_destination(int stream_fd) : destination(stream_fd) { } explicit stream_destination(FILE* stream_ptr) : stream_destination(stream_ptr->_fileno) { } ssize_t write(const void* data, size_t size) override { return destination::write(data, size); } }; class buffer_destination : public destination { public: explicit buffer_destination(buffer* buffer) : destination(-1), buf(buffer) { } ssize_t write(const void* data, size_t size) override { buf->take(const_cast(data), size); last_write = size; return size; } private: buffer* buf; }; class xor_crypt { public: inline void set_password(const void* password, size_t size) { passwd = copy_data(password, size); passwd_size = size; LOG << "xor_crypt object " << static_cast(this) << color::reset << LOG_COLOR << "'s password changed (check password manually with debugger)!" << ENDENTLN; } inline void reset_iter() { passwd_iter = 0; LOG << "xor_crypt object " << static_cast(this) << color::reset << LOG_COLOR << "'s password iterator reset!" << ENDENTLN; } inline void crypt(byte* data, size_t size) { LOG << "Crypting buffer " << static_cast(data) << color::reset << LOG_COLOR << " of size" << size << color::reset << LOG_COLOR << ENDENTLN; for (byte* i = data; i < data + size; ++i) { *i ^= passwd[passwd_iter++]; passwd_iter %= passwd_size; } LOG << "Crypted buffer " << static_cast(data) << color::reset << LOG_COLOR << ". Password iterator = " << passwd_iter << ENDENTLN; } protected: inline xor_crypt(const void* password, size_t size) : passwd(copy_data(password, size)), passwd_size(size) { } inline xor_crypt(const xor_crypt& xc) : passwd(copy_data(xc.passwd, xc.passwd_size)), passwd_size(xc.passwd_size), passwd_iter(xc.passwd_iter) { } inline xor_crypt(xor_crypt&& xc) noexcept: passwd(xc.passwd), passwd_size(xc.passwd_size), passwd_iter(xc.passwd_iter) { xc.passwd = nullptr; xc.passwd_size = 0; xc.passwd_iter = 0; } byte* passwd; size_t passwd_size; size_t passwd_iter{ }; }; class xor_decrypt : public xor_crypt { public: inline xor_decrypt(const void* password, size_t size, source* source = nullptr) : xor_crypt(password, size), src(source) { } inline explicit xor_decrypt(const std::string& password, source* source = nullptr) : xor_decrypt(password.c_str(), password.size(), source) { } inline xor_decrypt(const xor_decrypt& xd) = delete; inline xor_decrypt(xor_decrypt&& xd) noexcept: xor_crypt(std::move(xd)), src(std::move(xd.src)) { } inline ssize_t read(void* data, size_t size) { ssize_t res = src->read(data, size); crypt(static_cast(data), res); return res; } inline void set_source(source* source) { src = std::unique_ptr(source); } [[nodiscard]] inline size_t available() const { return src->available(); } void close_fd() { src->close(); } private: std::unique_ptr src; }; class xor_encrypt : public xor_crypt { public: inline xor_encrypt(const void* password, size_t size, destination* destination = nullptr) : xor_crypt(password, size), dest(destination) { } inline explicit xor_encrypt(const std::string& password, destination* destination = nullptr) : xor_encrypt(password.c_str(), password.size(), destination) { } inline xor_encrypt(const xor_encrypt& xe) = delete; inline xor_encrypt(xor_encrypt&& xe) noexcept: xor_crypt(std::move(xe)), dest(std::move(xe.dest)) { } inline ssize_t write(const void* data, size_t size) { auto* tmp = copy_data(data, size); crypt(tmp, size); return dest->write(tmp, size); } inline void set_destination(destination* _dest) { dest = std::unique_ptr(_dest); } inline void close_fd() { dest->close(); } private: std::unique_ptr dest; }; /// xor-decrypt declarations inline xor_decrypt& operator>>(buffer* source_buf, xor_decrypt& xd) { xd.set_source(new buffer_source(source_buf)); return xd; } inline xor_decrypt& operator>>(FILE* source_file, xor_decrypt& xd) { xd.set_source(new file_source(source_file)); return xd; } inline xor_decrypt& operator>>(int source_fd, xor_decrypt& xd) { xd.set_source(new stream_source(source_fd)); return xd; } inline xor_decrypt& operator>>(xor_decrypt& xd, std::string& res) { size_t size = xd.available(); res.resize(size); char* data = res.data(); xd.read(data, size); return xd; } inline xor_decrypt& operator>>(xor_decrypt& xd, buffer* res) { size_t size = xd.available(); res->realloc(size); xd.read(res->get(), size); return xd; } /// xor-encrypt declarations inline xor_encrypt& operator<<(buffer* dest_buf, xor_encrypt& xe) { xe.set_destination(new buffer_destination(dest_buf)); return xe; } inline xor_encrypt& operator<<(FILE* dest_file, xor_encrypt& xe) { xe.set_destination(new file_destination(dest_file)); return xe; } inline xor_encrypt& operator<<(int dest_fd, xor_encrypt& xe) { xe.set_destination(new stream_destination(dest_fd)); return xe; } template inline xor_encrypt& operator<<(xor_encrypt& xe, const std::basic_string& data) { xe.write(data.c_str(), data.size() * sizeof(char_t)); return xe; } template inline xor_encrypt& operator<<(xor_encrypt& xe, const char_t* data) { xe.write(data, static_strlen(data) * sizeof(char_t)); return xe; } inline xor_encrypt& operator<<(xor_encrypt& xe, const buffer* data) { xe.write(data->get(), data->capacity()); return xe; } } #endif //XOR_CRYPT