X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/8c6fa3fbaccc22127280bf77a48fab5a3ee0716e..46b0747592074017ff0ea4b33d4a7194235886e5:/libs/crypto/bfstream.cpp diff --git a/libs/crypto/bfstream.cpp b/libs/crypto/bfstream.cpp new file mode 100644 index 00000000..3325bd1a --- /dev/null +++ b/libs/crypto/bfstream.cpp @@ -0,0 +1,142 @@ +#include "stg/bfstream.h" + +#include "stg/blowfish.h" + +#include + +namespace +{ + +#ifndef BFSTREAM_BUF_SIZE +const size_t BUFFER_SIZE = 1024; +#else +const size_t BUFFER_SIZE = BFSTREAM_BUF_SIZE; +#endif + +class COMMON +{ + public: + typedef bool (* CALLBACK)(const void * block, size_t size, void * data); + typedef void (* PROC)(void * dest, const void * source, size_t length, const BLOWFISH_CTX * ctx); + + COMMON(const std::string & key, CALLBACK callback, void * data, PROC proc) + : m_ptr(m_buffer), + m_callback(callback), + m_data(data), + m_proc(proc), + m_ok(true) + { + InitContext(key.c_str(), key.length(), &m_ctx); + memset(m_buffer, 0, sizeof(m_buffer)); + } + + void Put(const void * data, size_t size, bool last) + { + size_t dataSize = m_ptr - m_buffer; + while (dataSize + size > sizeof(m_buffer)) + { + memcpy(m_ptr, data, sizeof(m_buffer) - dataSize); // Fill buffer + size -= sizeof(m_buffer) - dataSize; // Adjust size + data = static_cast(data) + sizeof(m_buffer) - dataSize; // Adjust data pointer + m_proc(m_buffer, m_buffer, sizeof(m_buffer), &m_ctx); // Process + m_ok = m_ok && m_callback(m_buffer, sizeof(m_buffer), m_data); // Consume + m_ptr = m_buffer; + dataSize = 0; + } + if (!m_ok) + return; + memcpy(m_ptr, data, size); + m_ptr += size; + m_tryConsume(last); + } + + bool IsOk() const { return m_ok; } + + private: + char m_buffer[BUFFER_SIZE]; + char * m_ptr; + CALLBACK m_callback; + void * m_data; + BLOWFISH_CTX m_ctx; + PROC m_proc; + bool m_ok; + + void m_tryConsume(bool last) + { + size_t dataSize = (m_ptr - m_buffer) & ~7; + size_t remainder = m_ptr - m_buffer - dataSize; + if (last && remainder > 0) + { + dataSize += 8; + remainder = 0; + } + if (!last && dataSize == 0) // Allow to call callback with 0 data on last call. + return; + m_proc(m_buffer, m_buffer, dataSize, &m_ctx); + m_ok = m_ok && m_callback(m_buffer, dataSize, m_data); + if (!m_ok) + return; + if (remainder > 0) + memmove(m_buffer, m_buffer + dataSize, remainder); + m_ptr = m_buffer + remainder; + } +}; + +} // namespace anonymous + +using STG::ENCRYPT_STREAM; +using STG::DECRYPT_STREAM; + +class ENCRYPT_STREAM::IMPL : public COMMON +{ + public: + IMPL(const std::string & key, CALLBACK callback, void * data) + : COMMON(key, callback, data, EncryptString) + {} +}; + +class DECRYPT_STREAM::IMPL : public COMMON +{ + public: + IMPL(const std::string & key, CALLBACK callback, void * data) + : COMMON(key, callback, data, DecryptString) + {} +}; + +ENCRYPT_STREAM::ENCRYPT_STREAM(const std::string & key, CALLBACK callback, void * data) + : m_impl(new IMPL(key, callback, data)) +{} + +ENCRYPT_STREAM::~ENCRYPT_STREAM() +{ +delete m_impl; +} + +void ENCRYPT_STREAM::Put(const void * data, size_t size, bool last) +{ +m_impl->Put(data, size, last); +} + +bool ENCRYPT_STREAM::IsOk() const +{ +return m_impl->IsOk(); +} + +DECRYPT_STREAM::DECRYPT_STREAM(const std::string & key, CALLBACK callback, void * data) + : m_impl(new IMPL(key, callback, data)) +{} + +DECRYPT_STREAM::~DECRYPT_STREAM() +{ +delete m_impl; +} + +void DECRYPT_STREAM::Put(const void * data, size_t size, bool last) +{ +m_impl->Put(data, size, last); +} + +bool DECRYPT_STREAM::IsOk() const +{ +return m_impl->IsOk(); +}