added: possibility to encode the session cookie (added files core/sessionidmanager.h and core/sessionidmanager.cpp)
added: config options: // whether or not we should encode the session cookie // (we have a special algorithm) // default: false bool session_cookie_encode; // if session_cookie_encode is true then you should provide // a file where AES keys will be stored std::wstring session_keys_file; // each session has an index -- an unsigned int value // this value is sent in the cookie string (is encoded) // and is incremented when session_index_time_increment time is passed since the last incrementing // if a client sent the cookie back the difference between // current index and the index in the cookie should be less than or equal to session_allow_index_difference // default: 8 size_t session_allow_index_difference; // the time which should pass after the session index is incremented // default: 30 // (session_allow_index_difference + 1) * session_index_time_increment should be less than a time // load of a page and all elements on it such as images (of course it depends on client's download too) time_t session_index_time_increment; // time in seconds after a new AES key pair should be generated // we have 256 pairs of keys so this time multiplied by 256 should not be less than // the max time of a session (session_remember_max_idle), // by default: 256 * 2 days = 512 days = 1.4 year > 3 months (session_remember_max_idle) // default: 172800 = 2 days (max: 2678400 = 1 month, min: 10) size_t session_key_renew_time; changed: when printing the time of a request we print only two non-zero digits git-svn-id: svn://ttmath.org/publicrep/winix/trunk@994 e52654a7-88a9-db11-a3e9-0013d4bc506epull/3/head
parent
3547d326b8
commit
76314aab10
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
o = acceptbaseparser.o app.o basethread.o bbcodeparser.o compress.o config.o crypt.o dircontainer.o dirs.o groups.o htmlfilter.o httpsimpleparser.o image.o ipbancontainer.o item.o job.o lastcontainer.o loadavg.o lock.o log.o misc.o mount.o mountparser.o mounts.o plugin.o plugindata.o postmultiparser.o rebus.o request.o run.o session.o sessioncontainer.o sessionmanager.o sessionparser.o slog.o synchro.o system.o threadmanager.o timezone.o timezones.o user.o users.o
|
||||
o = acceptbaseparser.o app.o basethread.o bbcodeparser.o compress.o config.o crypt.o dircontainer.o dirs.o groups.o htmlfilter.o httpsimpleparser.o image.o ipbancontainer.o item.o job.o lastcontainer.o loadavg.o lock.o log.o misc.o mount.o mountparser.o mounts.o plugin.o plugindata.o postmultiparser.o rebus.o request.o run.o session.o sessioncontainer.o sessionidmanager.o sessionmanager.o sessionparser.o slog.o synchro.o system.o threadmanager.o timezone.o timezones.o user.o users.o
|
||||
|
@ -0,0 +1,561 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "sessionidmanager.h"
|
||||
#include "space/spaceparser.h"
|
||||
#include "utf8/utf8.h"
|
||||
#include "date/date.h"
|
||||
#include "log.h"
|
||||
#include "misc.h"
|
||||
|
||||
|
||||
namespace Winix
|
||||
{
|
||||
|
||||
|
||||
SessionIdManager::SessionIdManager()
|
||||
{
|
||||
algorithm_type = 'a';
|
||||
key_tab_size = 256;
|
||||
key_index = 0;
|
||||
last_key_generated = 0;
|
||||
key_renew_time = 60;
|
||||
was_inited = false;
|
||||
}
|
||||
|
||||
|
||||
void SessionIdManager::Init(const std::wstring & keys_file)
|
||||
{
|
||||
was_inited = true;
|
||||
|
||||
key_tab1.resize(key_tab_size);
|
||||
key_tab2.resize(key_tab_size);
|
||||
|
||||
aes1.resize(key_tab_size);
|
||||
aes2.resize(key_tab_size);
|
||||
|
||||
key_file_name = keys_file;
|
||||
ReadKeysFromFile(key_file_name);
|
||||
}
|
||||
|
||||
|
||||
void SessionIdManager::SetKeyRenewTime(time_t renew_time)
|
||||
{
|
||||
key_renew_time = renew_time;
|
||||
|
||||
if( key_renew_time < 10 )
|
||||
key_renew_time = 10;
|
||||
|
||||
time_t one_month = 60 * 60 * 24 * 31;
|
||||
|
||||
if( key_renew_time > one_month )
|
||||
key_renew_time = one_month;
|
||||
}
|
||||
|
||||
|
||||
void SessionIdManager::ReadKey(const wchar_t * name, PT::Space & space, std::vector<std::string> & dest_key)
|
||||
{
|
||||
std::vector<std::wstring> keys;
|
||||
std::string key_ascii, key_base64_decoded;
|
||||
|
||||
space.ListText(name, keys);
|
||||
|
||||
for(size_t i=0 ; i<key_tab_size ; ++i)
|
||||
dest_key[i].clear();
|
||||
|
||||
for(size_t i=0 ; i<keys.size() && i<key_tab_size ; ++i)
|
||||
{
|
||||
dest_key[i].clear();
|
||||
|
||||
if( PT::WideToUTF8(keys[i], key_ascii) )
|
||||
{
|
||||
if( base64.Decode(key_ascii, key_base64_decoded) )
|
||||
{
|
||||
size_t len = key_base64_decoded.size();
|
||||
|
||||
if( len == 16 || len == 24 || len == 32 )
|
||||
{
|
||||
dest_key[i] = key_base64_decoded;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SessionIdManager::InitializeAesKeys(size_t index)
|
||||
{
|
||||
if( !aes1[index].Key((unsigned char*)key_tab1[index].c_str(), key_tab1[index].size()) )
|
||||
log << log1 << "SIM: I cannot initialize a key1, size of the key: " << key_tab1[index].size() << logend;
|
||||
|
||||
if( !aes2[index].Key((unsigned char*)key_tab2[index].c_str(), key_tab2[index].size()) )
|
||||
log << log1 << "SIM: I cannot initialize a key2, size of the key: " << key_tab2[index].size() << logend;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SessionIdManager::InitializeAesKeys()
|
||||
{
|
||||
for(size_t i=0 ; i < key_tab_size ; ++i)
|
||||
{
|
||||
if( AreKeysCorrect(i) )
|
||||
InitializeAesKeys(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool SessionIdManager::ReadKeysFromFile(const wchar_t * file)
|
||||
{
|
||||
PT::Space space;
|
||||
PT::SpaceParser parser;
|
||||
PT::Date date;
|
||||
|
||||
parser.SetSpace(space);
|
||||
PT::SpaceParser::Status status = parser.Parse(file);
|
||||
|
||||
if( status == PT::SpaceParser::ok )
|
||||
{
|
||||
key_index = space.Size(L"key_index");
|
||||
|
||||
if( key_index >= 256 )
|
||||
key_index = 0;
|
||||
|
||||
if( date.Parse(space.Text(L"last_key_generated", L"0")) )
|
||||
last_key_generated = date.ToTime();
|
||||
|
||||
ReadKey(L"key_tab1", space, key_tab1);
|
||||
ReadKey(L"key_tab2", space, key_tab2);
|
||||
InitializeAesKeys();
|
||||
}
|
||||
else
|
||||
{
|
||||
log << log1 << "SIM: I cannot read the session keys from: " << file << logend;
|
||||
}
|
||||
|
||||
return status == PT::SpaceParser::ok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool SessionIdManager::ReadKeysFromFile(const std::wstring & file)
|
||||
{
|
||||
return ReadKeysFromFile(file.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SessionIdManager::SaveKeysToFile(std::vector<std::string> & keys)
|
||||
{
|
||||
out_file << "(\n";
|
||||
|
||||
for(size_t i=0 ; i<keys.size() ; ++i)
|
||||
{
|
||||
base64.Encode(keys[i], tmp_key_base64_encoded);
|
||||
out_file << '\"' << tmp_key_base64_encoded << "\"\n";
|
||||
}
|
||||
|
||||
out_file << ")\n\n";
|
||||
tmp_key_base64_encoded.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool SessionIdManager::SaveKeysToFile(const wchar_t * file)
|
||||
{
|
||||
PT::Date date = last_key_generated;
|
||||
PT::WideToUTF8(file, file_name_ascii);
|
||||
|
||||
out_file.clear();
|
||||
out_file.open(file_name_ascii, std::ios_base::binary | std::ios_base::out);
|
||||
|
||||
if( out_file )
|
||||
{
|
||||
out_file << "key_index = " << key_index << "\n";
|
||||
|
||||
out_file << "last_key_generated = \"";
|
||||
date.Serialize(out_file);
|
||||
out_file << "\"\n\n";
|
||||
|
||||
out_file << "key_tab1 = ";
|
||||
SaveKeysToFile(key_tab1);
|
||||
|
||||
out_file << "key_tab2 = ";
|
||||
SaveKeysToFile(key_tab2);
|
||||
|
||||
out_file.flush();
|
||||
}
|
||||
|
||||
out_file.close();
|
||||
file_name_ascii.clear();
|
||||
SetPriv(file, 0600);
|
||||
|
||||
return !out_file.fail();
|
||||
}
|
||||
|
||||
|
||||
bool SessionIdManager::SaveKeysToFile(const std::wstring & file)
|
||||
{
|
||||
return SaveKeysToFile(file.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool SessionIdManager::AreKeysCorrect(size_t index)
|
||||
{
|
||||
if( index >= 256 )
|
||||
return false;
|
||||
|
||||
size_t len = key_tab1[index].size();
|
||||
|
||||
if( len != 16 && len != 24 && len != 32 )
|
||||
return false;
|
||||
|
||||
len = key_tab2[index].size();
|
||||
|
||||
if( len != 16 && len != 24 && len != 32 )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* IMPROVE ME
|
||||
* we need a better algorithm
|
||||
*/
|
||||
void SessionIdManager::GenerateKey(std::string & key, time_t cur_utc_time)
|
||||
{
|
||||
unsigned int pid = (unsigned int)getpid();
|
||||
unsigned int t = (unsigned int)cur_utc_time;
|
||||
|
||||
key.clear();
|
||||
|
||||
for(size_t i=0 ; i<16 ; ++i)
|
||||
{
|
||||
unsigned int r = rand();
|
||||
unsigned int v = r ^ pid ^ t;
|
||||
v = ((v >> 24) ^ (v >> 16) ^ (v >> 8) ^ v) & 0xff;
|
||||
|
||||
key.push_back((unsigned char)v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SessionIdManager::GenerateKeys(size_t index, time_t cur_utc_time)
|
||||
{
|
||||
GenerateKey(key_tab1[index], cur_utc_time);
|
||||
GenerateKey(key_tab2[index], cur_utc_time);
|
||||
InitializeAesKeys(index);
|
||||
|
||||
last_key_generated = cur_utc_time;
|
||||
|
||||
if( !SaveKeysToFile(key_file_name) )
|
||||
log << log2 << "SIM: I cannot save the session keys to: " << key_file_name << logend;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SessionIdManager::CheckKeys(time_t cur_utc_time)
|
||||
{
|
||||
if( !AreKeysCorrect(key_index) )
|
||||
{
|
||||
log << log1 << "SIM: keys with index: " << key_index << " are incorrect, generating new keys" << logend;
|
||||
|
||||
GenerateKeys(key_index, cur_utc_time);
|
||||
}
|
||||
else
|
||||
if( last_key_generated + key_renew_time < cur_utc_time )
|
||||
{
|
||||
key_index += 1;
|
||||
|
||||
if( key_index >= key_tab_size )
|
||||
key_index = 0;
|
||||
|
||||
log << log2 << "SIM: generating new AES keys with index: " << key_index << logend;
|
||||
|
||||
GenerateKeys(key_index, cur_utc_time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SessionIdManager::RandPadding(size_t & pad_top_size, char & pad_top_value,
|
||||
size_t & pad_bottom_size, char & pad_bottom_value)
|
||||
{
|
||||
pad_top_size = (std::rand() * 5) / RAND_MAX; // multiply by 5 (not by 4)
|
||||
|
||||
if( pad_top_size > 4 )
|
||||
pad_top_size = 4;
|
||||
|
||||
pad_top_size += 5; // now pad_top_size is from <5;9>
|
||||
pad_top_value = (char)std::rand();
|
||||
|
||||
pad_bottom_size = 14 - pad_top_size; // pad_bottom_size is from <5;9> too
|
||||
pad_bottom_value = (char)std::rand();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SessionIdManager::AppendSum(std::string & str)
|
||||
{
|
||||
int s = 0;
|
||||
|
||||
for(size_t i=0 ; i<str.size() ; ++i)
|
||||
s += (int)(unsigned char)str[i];
|
||||
|
||||
str += (unsigned char)s;
|
||||
}
|
||||
|
||||
|
||||
void SessionIdManager::AppendXor(std::string & str)
|
||||
{
|
||||
int s = 0;
|
||||
|
||||
for(size_t i=0 ; i<str.size() ; ++i)
|
||||
s ^= (int)(unsigned char)str[i];
|
||||
|
||||
str += (unsigned char)s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SessionIdManager::CopyString(const std::string & in, std::wstring & out)
|
||||
{
|
||||
out.clear();
|
||||
|
||||
if( out.capacity() < in.size() )
|
||||
out.reserve(in.size());
|
||||
|
||||
for(size_t i=0 ; i<in.size() ; ++i)
|
||||
out += in[i];
|
||||
}
|
||||
|
||||
|
||||
void SessionIdManager::CopyString(const std::wstring & in, std::string & out)
|
||||
{
|
||||
out.clear();
|
||||
|
||||
if( out.capacity() < in.size() )
|
||||
out.reserve(in.size());
|
||||
|
||||
for(size_t i=0 ; i<in.size() ; ++i)
|
||||
out += in[i];
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool SessionIdManager::Encode(std::string & str)
|
||||
{
|
||||
if( str.size() != 34 )
|
||||
return false;
|
||||
|
||||
if( !aes1[key_index].Encode((unsigned char*)string_token.c_str()+2, 16) )
|
||||
{
|
||||
log << log1 << "SIM: I cannot AES encode the first part of the token" << logend;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !aes2[key_index].Encode((unsigned char*)string_token.c_str()+16+2, 16) )
|
||||
{
|
||||
log << log1 << "SIM: I cannot AES encode the second part of the token" << logend;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SessionIdManager::EncodeToken(size_t id, unsigned int index, time_t cur_utc_time, std::wstring & token)
|
||||
{
|
||||
size_t pad_top_size;
|
||||
size_t pad_bottom_size;
|
||||
char pad_top_value;
|
||||
char pad_bottom_value;
|
||||
|
||||
string_token.clear();
|
||||
string_token.reserve(50);
|
||||
|
||||
if( !was_inited )
|
||||
return false;
|
||||
|
||||
CheckKeys(cur_utc_time);
|
||||
RandPadding(pad_top_size, pad_top_value, pad_bottom_size, pad_bottom_value);
|
||||
|
||||
string_token += algorithm_type;
|
||||
string_token += (unsigned char)key_index;
|
||||
string_token += pad_top_value;
|
||||
string_token += pad_bottom_value;
|
||||
string_token += (unsigned char)pad_top_size;
|
||||
string_token += (unsigned char)pad_bottom_size;
|
||||
string_token.append(pad_top_size, pad_top_value);
|
||||
Append(string_token, id);
|
||||
Append(string_token, index);
|
||||
string_token.append(pad_bottom_size, pad_bottom_value);
|
||||
AppendSum(string_token);
|
||||
AppendXor(string_token);
|
||||
|
||||
if( !Encode(string_token) )
|
||||
return false;
|
||||
|
||||
base64.Encode(string_token, string_token_base64);
|
||||
CopyString(string_token_base64, token);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SessionIdManager::IsPaddingCorrect(const char * str, size_t len, char val)
|
||||
{
|
||||
if( len < 5 || len > 9 )
|
||||
return false;
|
||||
|
||||
for(size_t i=0 ; i<len ; ++i)
|
||||
if( str[i] != val )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SessionIdManager::DecodeAES(const char * str, size_t key)
|
||||
{
|
||||
if( !aes1[key].Decode((unsigned char*)str, 16) )
|
||||
{
|
||||
log << log1 << "SIM: I cannot AES decode the first block" << logend;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !aes2[key].Decode((unsigned char*)str + 16, 16) )
|
||||
{
|
||||
log << log1 << "SIM: I cannot AES decode the second block" << logend;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SessionIdManager::CheckControlSums(const char * str)
|
||||
{
|
||||
char old_sum = *(str++);
|
||||
char old_xor = *(str++);
|
||||
|
||||
string_token.erase(string_token.size()-2);
|
||||
|
||||
AppendSum(string_token);
|
||||
AppendXor(string_token);
|
||||
|
||||
if( old_sum != string_token[string_token.size()-2] ||
|
||||
old_xor != string_token[string_token.size()-1] )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SessionIdManager::DecodeTokenA(size_t & id, unsigned int & index)
|
||||
{
|
||||
size_t pad_top_size;
|
||||
size_t pad_bottom_size;
|
||||
char pad_top_value;
|
||||
char pad_bottom_value;
|
||||
|
||||
const char * str = string_token.c_str() + 1;
|
||||
size_t key = (unsigned char)(*str);
|
||||
|
||||
str += 1;
|
||||
|
||||
if( !DecodeAES(str, key) )
|
||||
return false;
|
||||
|
||||
pad_top_value = *(str++);
|
||||
pad_bottom_value = *(str++);
|
||||
pad_top_size = (unsigned char)*(str++);
|
||||
pad_bottom_size = (unsigned char)*(str++);
|
||||
|
||||
if( pad_bottom_size != 14 - pad_top_size )
|
||||
return false;
|
||||
|
||||
if( !IsPaddingCorrect(str, pad_top_size, pad_top_value) )
|
||||
return false;
|
||||
|
||||
str += pad_top_size;
|
||||
|
||||
Read(str, id);
|
||||
str += 8; // sizeof(id), it's better to use constant '8' instead of sizeof() operator
|
||||
// because at the beginning we are making a test whether the string size is equal to 34
|
||||
// (in the future sizeof(size_t) can be different from 8)
|
||||
Read(str, index);
|
||||
str += 4; // sizeof(index)
|
||||
|
||||
if( !IsPaddingCorrect(str, pad_bottom_size, pad_bottom_value) )
|
||||
return false;
|
||||
|
||||
str += pad_bottom_size;
|
||||
|
||||
return CheckControlSums(str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool SessionIdManager::DecodeToken(const std::wstring & token, size_t & id, unsigned int & index)
|
||||
{
|
||||
if( !was_inited )
|
||||
return false;
|
||||
|
||||
CopyString(token, string_token_base64);
|
||||
|
||||
if( !base64.Decode(string_token_base64, string_token) )
|
||||
return false;
|
||||
|
||||
if( string_token.size() != 34 )
|
||||
return false;
|
||||
|
||||
if( string_token[0] == 'a' )
|
||||
return DecodeTokenA(id, index);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Winix
|
||||
|
||||
|
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|