winix/core/sessionidmanager.h

200 lines
5.5 KiB
C++

/*
* This file is a part of Winix
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2014, 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 <string>
#include <vector>
#include <ctime>
#include <fstream>
#include "base64.h"
#include "space/space.h"
#include "aes.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:
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<std::string> 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<Tito::AES> 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<std::string> & 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<std::string> & 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<typename Value>
void Append(std::string & str, Value val);
template<typename Value>
void Read(const char * str, Value & val);
};
template<typename Value>
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<typename Value>
void SessionIdManager::Read(const char * str, Value & val)
{
val = 0;
for(size_t i=0 ; i<sizeof(Value) ; ++i)
{
val = val << 8;
val = val | (unsigned char)str[i];
}
}
} // namespace Winix
#endif