/* * This file is a part of Winix * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2014-2018, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #ifndef headerfile_winix_core_sessionidmanager #define headerfile_winix_core_sessionidmanager #include #include #include #include #include "base64.h" #include "space/space.h" #include "aes.h" #include "winixbase.h" namespace Winix { /* * this class is used to encode/decode the session cookie * in which there is a session id and a session's index * * session index is incremented each time a request comes to this session * * format of the encoded token: * 1 byte - algorithm type, currently only one algorithm: 'a' * 1 byte - an AES keys pair index * ---- below everything is encoded by AES (two 128 bits blocks, first block * is encoded by the first key and the second block is encoded by the second key) ------ * 1 byte - top padding value * 1 byte - bottom padding value * 1 byte - top padding size * 1 byte - bottom padding size * 5-9 bytes - top padding * 8 bytes - the session id * 4 bytes - the session index * 5-9 bytes - bottom padding (bottom_padding_size = 14 - top_padding_size) * 1 byte - the sum of all previous bytes * 1 byte - the xor of all previous bytes (with the previous sum too) * * and at the end everyting is base64 encoded * * */ class SessionIdManager : public WinixBase { public: SessionIdManager(); /* * initialization * this method takes about 1MB memory more (for AES key expansions) * if you do not need the session cookie to be enrypted then don't call this method * */ void Init(const std::wstring & keys_file); /* * how often a new AES key pairs should be generated */ void SetKeyRenewTime(time_t renew_time); /* * encode/decode the session cookie * make sure the Init() method is called first */ bool EncodeToken(size_t id, unsigned int index, time_t cur_utc_time, std::wstring & token); bool DecodeToken(const std::wstring & token, size_t & id, unsigned int & index); private: bool was_inited; char algorithm_type; std::string string_token, string_token_base64; std::vector key_tab1, key_tab2; size_t key_index; time_t last_key_generated; time_t key_renew_time; Tito::Base64 base64; size_t key_tab_size; std::ofstream out_file; std::string tmp_key_base64_encoded; std::wstring key_file_name; std::string file_name_ascii; std::vector aes1, aes2; bool ReadKeysFromFile(const wchar_t * file); bool ReadKeysFromFile(const std::wstring & file); bool SaveKeysToFile(const wchar_t * file); bool SaveKeysToFile(const std::wstring & file); void ReadKey(const wchar_t * name, pt::Space & space, std::vector & dest_key); bool AreKeysCorrect(size_t index); void GenerateKeys(size_t index, time_t cur_utc_time); void CheckKeys(time_t cur_utc_time); void GenerateKey(std::string & key, time_t cur_utc_time); void SaveKeysToFile(std::vector & keys); void InitializeAesKeys(); void RandPadding(size_t & pad_top_size, char & pad_top_value, size_t & pad_bottom_size, char & pad_bottom_value); void AppendSum(std::string & str); void AppendXor(std::string & str); void CopyString(const std::string & in, std::wstring & out); void CopyString(const std::wstring & in, std::string & out); bool Encode(std::string & str); bool DecodeTokenA(size_t & id, unsigned int & index); bool IsPaddingCorrect(const char * str, size_t len, char val); bool CheckControlSums(const char * str); void InitializeAesKeys(size_t index); bool DecodeAES(const char * str, size_t key); template void Append(std::string & str, Value val); template void Read(const char * str, Value & val); }; template void SessionIdManager::Append(std::string & str, Value val) { int move = sizeof(Value) * 8 - 8; int v; do { if( move > 0 ) v = ((val >> move) & 0xff); else v = val & 0xff; str += (unsigned char)v; move -= 8; } while( move >= 0 ); } template void SessionIdManager::Read(const char * str, Value & val) { val = 0; for(size_t i=0 ; i