diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index d2d07d5..fcf500f 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -4,7 +4,7 @@ project(server) file(GLOB_RECURSE server_src "src/*.hpp" "src/*.cpp" -) +) if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -static") diff --git a/server/src/crypto/base64.cpp b/server/src/crypto/base64.cpp index 868b454..2db79f5 100644 --- a/server/src/crypto/base64.cpp +++ b/server/src/crypto/base64.cpp @@ -3,14 +3,18 @@ #define B64_IGNORE 0xFE #define B64_PADDING 0xFF -std::string sosc::cgc::base64_encode(const std::string& data) { +std::string sosc::cgc::base64_encode(const std::string& data, bool unix) { return base64_encode(data.c_str(), data.length()); } -std::string sosc::cgc::base64_encode(const void* raw, size_t length) { +std::string sosc::cgc::base64_encode + (const void* raw, size_t length, bool unix) +{ uint8_t* data = (uint8_t*)raw; const std::string char_table - = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + = (unix) + ? "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; std::string encoded; for(size_t i = 0; i < length; i += 3) { @@ -27,14 +31,30 @@ std::string sosc::cgc::base64_encode(const void* raw, size_t length) { for(int j = 0; j < 4 - padding; ++j) encoded += char_table[(index >> (6 * (3 - j))) & 0x3F]; - - for(int j = 0; j < padding; ++j) - encoded += '='; + + if(!unix) + for(int j = 0; j < padding; ++j) + encoded += '='; } return encoded; } +static uint8_t radix64_decode_char(char c) { + if(c >= '0' && c <= '9') + return c - '0' + 2; + else if(c >= 'A' && c <= 'Z') + return c - 'A' + 12; + else if(c >= 'a' && c <= 'z') + return c - 'a' + 38; + else if(c == '.') + return 0; + else if(c == '/') + return 1; + else + return B64_IGNORE; +} + static uint8_t base64_decode_char(char c) { if(c >= 'A' && c <= 'Z') return c - 'A'; @@ -62,12 +82,13 @@ static void base64_decode_append(std::string* decoded, int data) { *decoded += (char)data; } -std::string sosc::cgc::base64_decode(const std::string& data) { +std::string sosc::cgc::base64_decode(const std::string& data, bool unix) { std::string decoded; int index = 0, j = 0; for(std::string::size_type i = 0; i < data.length(); ++i) { - int sextet = base64_decode_char(data[i]); + int sextet = unix ? radix64_decode_char(data[i]) + : base64_decode_char(data[i]); if(sextet == B64_IGNORE || sextet == B64_PADDING) { if(sextet == B64_PADDING && i >= data.length() - 2 && j > 1) diff --git a/server/src/crypto/base64.hpp b/server/src/crypto/base64.hpp index 10e402c..8663343 100644 --- a/server/src/crypto/base64.hpp +++ b/server/src/crypto/base64.hpp @@ -7,10 +7,10 @@ namespace sosc { namespace cgc { -std::string base64_encode(const std::string& data); -std::string base64_encode(const void* raw, size_t length); +std::string base64_encode(const std::string& data, bool unix = false); +std::string base64_encode(const void* raw, size_t length, bool unix = false); -std::string base64_decode(const std::string& data); +std::string base64_decode(const std::string& data, bool unix = false); }} #endif diff --git a/server/src/crypto/bcrypt.cpp b/server/src/crypto/bcrypt.cpp new file mode 100644 index 0000000..618010a --- /dev/null +++ b/server/src/crypto/bcrypt.cpp @@ -0,0 +1,15 @@ +#include "bcrypt.hpp" + +std::string sosc::cgc::bcrypt_hash(const std::string& input) { + std::string salt = csprng::next_bytes(16), + input_t = input.substr(0, 72); + + Blowfish bfish; + + std::stringstream stream; + stream << "$2b$" << BCRYPT_COST << "$" + << base64_encode(salt, true) + << "b"; + + return stream.str(); +} diff --git a/server/src/crypto/bcrypt.hpp b/server/src/crypto/bcrypt.hpp new file mode 100644 index 0000000..0a74bdc --- /dev/null +++ b/server/src/crypto/bcrypt.hpp @@ -0,0 +1,18 @@ +#ifndef SOSC_CRYPTO_BCRYPT_H +#define SOSC_CRYPTO_BCRYPT_H + +#include +#include +#include "base64.hpp" +#include "bfish.hpp" +#include "../utils/csprng.hpp" + +#define BCRYPT_COST 10 + +namespace sosc { +namespace cgc { +std::string bcrypt_hash(const std::string& input); +bool bcrypt_check(std::string input, std::string hash); +}} + +#endif diff --git a/server/src/crypto/bfish.cpp b/server/src/crypto/bfish.cpp index a00f109..a634564 100644 --- a/server/src/crypto/bfish.cpp +++ b/server/src/crypto/bfish.cpp @@ -184,14 +184,48 @@ static const uint32_t init_sbox[4][256] = { 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6} }; +static void swap(uint32_t& a, uint32_t& b) { + uint32_t temp = a; + a = b; + b = temp; +} + +static void pack_bytes + (const std::string& data, std::string::size_type i, + uint32_t& left, uint32_t& right) +{ + left = right = 0; + for(int j = 0; j < 8; ++j) { + if(j < 4) + left = (left << 8) | (data[(i + j) % data.length()] & 0xFF); + else + right = (right << 8) | (data[(i + j) % data.length()] & 0xFF); + } +} + +static void unpack_bytes + (std::string& data, std::string::size_type i, + uint32_t left, uint32_t right) +{ + for(int j = 0; j < 8; ++j) { + if(j < 4) { + data[i + (3 - j)] = left & 0xFF; + left >>= 8; + } else { + data[i + (7 - j + 4)] = right & 0xFF; + right >>= 8; + } + } +} + sosc::cgc::Blowfish::Blowfish(const std::string& key) { + std::memcpy(this->parr, init_parr, sizeof(init_parr)); + std::memcpy(this->sbox, init_sbox, sizeof(init_sbox)); + this->SetKey(key.c_str(), key.length()); } void sosc::cgc::Blowfish::SetKey(const char* key, size_t length) { - std::memcpy(this->parr, init_parr, sizeof(init_parr)); - std::memcpy(this->sbox, init_sbox, sizeof(init_sbox)); - for(int i = 0; i < 18; ++i) { uint32_t data = 0; for(int j = 0; j < 4; ++j) @@ -216,19 +250,99 @@ void sosc::cgc::Blowfish::SetKey(const char* key, size_t length) { } } +void sosc::cgc::Blowfish::SetEksKey + (const std::string& data, const std::string& key) +{ + for(int i = 0; i < 18; ++i) { + uint32_t pack = 0; + for(int j = 0; j < 4; ++j) + pack = (pack << 8) | key[(i * 4 + j) % key.length()]; + + this->parr[i] ^= pack; + } + + for(int i = 0; i < 18; i += 2) { + + } +} + std::string sosc::cgc::Blowfish::Encrypt(std::string data) const { - size_t pad_length = data.size() % sizeof(uint64_t); + int pad_length = data.length() % sizeof(uint64_t); pad_length = sizeof(uint64_t) - pad_length; - for(size_t i = 0; i < pad_length; ++i) + for(int i = 0; i < pad_length; ++i) data.push_back(0); - for(int i = 0; i < data.size() / sizeof(uint64_t); ++i) { - uint32_t* left = &(((uint32_t*)data.data())[i * 2]); - uint32_t* right = &(((uint32_t*)data.data())[i * 2 + 1]); + for(std::string::size_type i = 0; i < data.size(); i += 8) { + uint32_t left, right; - EncryptBlock(left, right); + pack_bytes(data, i, left, right); + this->EncryptBlock(&left, &right); + unpack_bytes(data, i, left, right); } + + return data; +} + +std::string sosc::cgc::Blowfish::Decrypt(std::string data) const { + if(data.length() % sizeof(uint64_t) != 0) + return ""; + + for(std::string::size_type i = 0; i < data.size(); i += 8) { + uint32_t left, right; + + pack_bytes(data, i, left, right); + this->DecryptBlock(&left, &right); + unpack_bytes(data, i, left, right); + } + + int i = 0; + for(;; i++) + if(data[data.length() - i - 1] != 0) + break; + + data.resize(data.length() - i); + return data; +} + +void sosc::cgc::Blowfish::EncryptBlock + (uint32_t* left, uint32_t* right) const +{ + uint32_t left_t = *left, + right_t = *right; + + for(int i = 0; i < 16; ++i) { + left_t ^= this->parr[i]; + right_t ^= this->Feistel(left_t); + swap(left_t, right_t); + } + + swap(left_t, right_t); + right_t ^= this->parr[16]; + left_t ^= this->parr[17]; + + *left = left_t; + *right = right_t; +} + +void sosc::cgc::Blowfish::DecryptBlock + (uint32_t* left, uint32_t* right) const +{ + uint32_t left_t = *left, + right_t = *right; + + for(int i = 17; i > 1; --i) { + left_t ^= this->parr[i]; + right_t ^= this->Feistel(left_t); + swap(left_t, right_t); + } + + swap(left_t, right_t); + right_t ^= this->parr[1]; + left_t ^= this->parr[0]; + + *left = left_t; + *right = right_t; } uint32_t sosc::cgc::Blowfish::Feistel(uint32_t input) const { diff --git a/server/src/crypto/bfish.hpp b/server/src/crypto/bfish.hpp index 31c74c3..5ac7762 100644 --- a/server/src/crypto/bfish.hpp +++ b/server/src/crypto/bfish.hpp @@ -3,6 +3,7 @@ #include #include +#include "bcrypt.hpp" namespace sosc { namespace cgc { @@ -11,9 +12,11 @@ public: Blowfish(const std::string& key); std::string Encrypt(std::string data) const; - std::string Decrypt(const std::string& data) const; + std::string Decrypt(std::string data) const; private: + Blowfish(); void SetKey(const char* key, size_t length); + void SetEksKey(const std::string& data, const std::string& key); void EncryptBlock(uint32_t* left, uint32_t* right) const; void DecryptBlock(uint32_t* left, uint32_t* right) const; @@ -21,6 +24,8 @@ private: uint32_t parr[18]; uint32_t sbox[4][256]; + + friend std::string sosc::cgc::bcrypt_hash(const std::string&); }; }} diff --git a/server/src/main.cpp b/server/src/main.cpp index c0e83c4..6b65119 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -7,6 +7,8 @@ #include "sock/tcpsock.hpp" #include "crypto/sha1.hpp" #include "crypto/base64.hpp" +#include "crypto/bfish.hpp" +#include "utils/csprng.hpp" int main(int argc, char **argv) { //auto sock = sosc::TcpClient(); @@ -32,5 +34,12 @@ int main(int argc, char **argv) { //std::string a = sosc::cgc::sha1("test", true); + sosc::cgc::Blowfish fish(""); + + std::string test = fish.Encrypt("imagine a test"); + std::string testd = fish.Decrypt(test); + + uint32_t teest = sosc::csprng::next(); + return 0; } diff --git a/server/src/utils/csprng.cpp b/server/src/utils/csprng.cpp new file mode 100644 index 0000000..e02b81e --- /dev/null +++ b/server/src/utils/csprng.cpp @@ -0,0 +1,58 @@ +#include "csprng.hpp" + +#ifdef _WIN32 +// TODO update win32 code to use csprng in advapi32.lib +// NOTE RUNNING ON WINDOWS IS INSECURE DO NOT DOD !!! + +#include + +static struct __rng_ctx { + std::default_random_engine rng; + std::mutex rng_mtx; + + __rng_ctx() : rng(time(NULL)) { } +} _rng_ctx; + +std::string sosc::csprng::next_bytes(std::string::size_type count) { + _rng_ctx.rng_mtx.lock(); + + std::string rand_bytes; + for(std::string::size_type i = 0; i < count; ++i) + rand_bytes += (char)_rng_ctx.rng(); + + _rng_ctx.rng_mtx.unlock(); + return rand_bytes; +} + +#else + +static struct __rng_ctx { + std::ifstream urand; + std::mutex rng_mtx; + + __rng_ctx() { + this->urand.open("/dev/urandom", + std::ifstream::in | std::ifstream::binary); + + if(!this->urand.good()) + throw "Could not establish csprng context."; + } + + ~__rng_ctx() { + this->urand.close(); + } +} _rng_ctx; + +std::string sosc::csprng::next_bytes(std::string::size_type count) { + _rng_ctx.rng_mtx.lock(); + + char* buffer = new char[count]; + _rng_ctx.urand.read(buffer, count); + std::string rand_bytes(buffer, count); + delete[] buffer; + + _rng_ctx.rng_mtx.unlock(); + return rand_bytes; +} + +#endif diff --git a/server/src/utils/csprng.hpp b/server/src/utils/csprng.hpp new file mode 100644 index 0000000..2f88f69 --- /dev/null +++ b/server/src/utils/csprng.hpp @@ -0,0 +1,19 @@ +#ifndef SOSC_UTIL_CSPRNG_H +#define SOSC_UTIL_CSPRNG_H + +#include +#include +#include +#include + +namespace sosc { +namespace csprng { +std::string next_bytes(std::string::size_type count); + +template +T next() { + return *((T*)(next_bytes(sizeof(T)).c_str())); +} +}} + +#endif