main.cpp
#include "general.h"
#include "server.h"
#include <iostream>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
std::cout << app::AppTag << "Service started" << std::endl;
Server server;
auto retCode = server.Run(std::make_shared<DiffieHellman>());
std::cout << app::AppTag << "Service stoped. Exit code = " << retCode
<< std::endl;
return retCode;
}
server.cpp
#include "server.h"
#include "general.h"
#include "login_form_handler.h"
#include "login_result_handler.h"
#include "auth_service/AuthService.edl.h"
#include <connections.h>
#include <coresrv/nk/transport-kos.h>
#include <coresrv/sl/sl_api.h>
#include <fcntl.h>
#include <iostream>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
Server::Server()
: m_reqArena(
NK_ARENA_INITIALIZER(m_reqBuffer, m_reqBuffer + sizeof(m_reqBuffer)))
, m_resArena(
NK_ARENA_INITIALIZER(m_resBuffer, m_resBuffer + sizeof(m_resBuffer)))
{}
int Server::Run(ISecretDataPtr secret)
{
ServiceId iid;
NkKosTransport transport;
// Gets the server IPC handle for the connection
auto handleClients =
ServiceLocatorRegister(connections::ConnectionName, NULL, 0, &iid);
if (handleClients == INVALID_HANDLE)
{
std::cerr
<< app::AppTag
<< "Error: can`t establish static IPC connection! Connection name: "
<< connections::ConnectionName << std::endl;
return EXIT_FAILURE;
}
// Initializes transport to clients
NkKosTransport_Init(&transport, handleClients, NK_NULL, 0);
// Initializes the Logger entity dispatcher
auth_service_AuthService_entity entity;
auth_service_AuthService_entity_init(
&entity,
LoginFormHandler::CreateImpl(secret),
LoginResultHandler::CreateImpl(secret));
// Main cycle: requests execution.
while (true)
{
nk_req_reset(&m_req);
nk_arena_reset(&m_reqArena);
nk_req_reset(&m_res);
nk_arena_reset(&m_resArena);
if (auto resCode =
nk_transport_recv(&transport.base, &m_req.base_, &m_reqArena);
resCode == NK_EOK)
auth_service_AuthService_entity_dispatch(
&entity, &m_req.base_, &m_reqArena, &m_res.base_, &m_resArena);
else
std::cerr << app::AppTag
<< "Error: nk_transport_recv is not OK. Error code = "
<< resCode << std::endl;
if (auto resCode =
nk_transport_reply(&transport.base, &m_res.base_, &m_resArena);
resCode != NK_EOK)
std::cerr << app::AppTag
<< "Error: nk_transport_reply is not OK. Error code = "
<< resCode << std::endl;
}
return EXIT_SUCCESS;
}
authservice.cpp
#include "authservice.h"
#include <map>
bool AuthService::Authentication(
const std::string &userName, const std::string &password) const
{
const std::map<std::string, std::string> Users = {
{"user1", "password1"}, {"User2", "security"}, {"user3", "R0g9in65"}};
auto it = Users.find(userName);
if (it == Users.end())
{
return false;
}
return it->second == password;
}
diffiehellman.cpp
#include "diffiehellman.h"
#include "formatter.h"
#include <openssl/bn.h>
#include <openssl/rand.h>
#include <chrono>
#include <exception>
#include <iomanip>
#include <iostream>
#include <math.h>
#include <memory.h>
#include <time.h>
#include <vector>
namespace consts {
constexpr uint32_t BnBits = sizeof(uint64_t) * 8;
}
using time_point = std::chrono::system_clock::time_point;
std::string
serializeTimePoint(const time_point &tmNow, const std::string &format)
{
std::time_t tt = std::chrono::system_clock::to_time_t(tmNow);
auto tm = *std::gmtime(&tt);
std::stringstream ss;
ss << std::put_time(&tm, format.c_str());
return ss.str();
}
void InitRandSeed()
{
if (RAND_status())
return;
auto input = std::chrono::system_clock::now();
auto timeStr = serializeTimePoint(input, "UTC: %Y-%m-%d %H:%M:%S");
auto seedStr = timeStr.c_str();
char rndSeed[] =
"string to make the random number generator think it has entropy";
strcpy(rndSeed, seedStr);
RAND_seed(&rndSeed, sizeof(rndSeed));
}
uint64_t Bn2Uint64t(const BIGNUM *bnValue)
{
uint64_t value;
std::istringstream iss(BN_bn2dec(bnValue));
iss >> value;
return value;
}
DiffieHellman::~DiffieHellman()
{
Dispose();
}
void DiffieHellman::Init()
{
std::vector<std::tuple<std::string, std::string>> dhPair = {
{"23", "5"}, {"13", "6"}, {"6734586", "2"}};
srand(static_cast<unsigned int>(time(nullptr)));
uint64_t idx = rand() % 3;
InitRandSeed();
m_bignumDh = std::make_unique<BignumDhData>();
if (!BN_generate_prime_ex(
m_bignumDh->secretKey, consts::BnBits, 0, NULL, NULL, NULL))
{
throw std::runtime_error(
Formatter() << "Unable to get random value for " << consts::BnBits
<< " bits");
}
BN_dec2bn(&m_bignumDh->p, std::get<0>(dhPair[idx]).c_str());
BN_dec2bn(&m_bignumDh->g, std::get<1>(dhPair[idx]).c_str());
if (BN_mod_exp(
m_bignumDh->openKey,
m_bignumDh->g,
m_bignumDh->secretKey,
m_bignumDh->p,
m_bignumDh->ctx) <= 0)
{
throw std::runtime_error("Error of BN_mod_exp.");
}
m_dhData.openKey = Bn2Uint64t(m_bignumDh->openKey);
m_dhData.secretKey = Bn2Uint64t(m_bignumDh->secretKey);
m_dhData.p = Bn2Uint64t(m_bignumDh->p);
m_dhData.g = Bn2Uint64t(m_bignumDh->g);
}
void DiffieHellman::Dispose()
{
m_dhData.g = 0;
m_dhData.p = 0;
m_dhData.secretKey = 0;
m_dhData.openKey = 0;
m_dhData.secret = 0;
m_bignumDh.reset();
}
bool DiffieHellman::IsInit()
{
return m_dhData.p != 0 && m_dhData.g != 0;
}
uint64_t DiffieHellman::GetSecret(uint64_t oppositeOpenKey) const
{
std::stringstream ss;
ss << oppositeOpenKey;
BN_dec2bn(&m_bignumDh->oppositeKey, ss.str().c_str());
if (BN_mod_exp(
m_bignumDh->secret,
m_bignumDh->oppositeKey,
m_bignumDh->secretKey,
m_bignumDh->p,
m_bignumDh->ctx) <= 0)
{
throw std::runtime_error("Error of BN_mod_exp.");
}
return Bn2Uint64t(m_bignumDh->secret);
}
htmlhelper.cpp
#include "htmlhelper.h"
#include <string>
namespace html_helper {
bool ReplaceValueByMask(
std::string &htmlLine, const std::string &mask, const std::string &value)
{
if (mask.empty())
{
return false;
}
auto pos = htmlLine.find(mask);
if (pos > htmlLine.length())
{
return false;
}
auto replacedLine = htmlLine.substr(0, pos);
replacedLine.append(value);
replacedLine.append(
htmlLine.substr(pos + mask.length(), htmlLine.length()));
htmlLine = replacedLine;
return true;
}
bool ReplaceValueByMask(
std::string &htmlLine, const std::string &mask, long value)
{
return ReplaceValueByMask(htmlLine, mask, std::to_string(value));
}
void ReadHtmlLine(std::ifstream &fm, std::string &htmlLine)
{
htmlLine.clear();
std::getline(fm, htmlLine);
if (!fm.eof() && htmlLine.empty())
{
htmlLine = "\n";
}
}
} // namespace html_helper
login_form_handler.cpp
#include "login_form_handler.h"
#include "general.h"
#include "htmlhelper.h"
#include <coresrv/nk/transport-kos.h>
#include <coresrv/sl/sl_api.h>
#include <rtl/stdio.h>
#include <rtl/string.h>
#include <iostream>
namespace consts {
const std::string AuthHtmlFile("mnt/auth.html");
} // namespace consts
struct LoginFormHandlerImpl : auth_service_ILoginForm_ops
{
LoginFormHandler *handler = nullptr;
};
nk_err_t OpenImpl(
struct auth_service_ILoginForm *self,
const auth_service_ILoginForm_Open_req *req,
const nk_arena *reqArena,
auth_service_ILoginForm_Open_res *res,
nk_arena *resArena)
{
auto ops = self != nullptr ?
static_cast<const LoginFormHandlerImpl *>(self->ops) :
nullptr;
if (ops == nullptr)
{
return NK_ENOENT;
}
res->result = ops->handler->OpenLoginStream();
return NK_EOK;
}
nk_err_t DisposeImpl(
struct auth_service_ILoginForm *self,
const auth_service_ILoginForm_Dispose_req *req,
const nk_arena *reqArr,
auth_service_ILoginForm_Dispose_res *res,
nk_arena *resArena)
{
auto reader = self != nullptr ?
static_cast<const LoginFormHandlerImpl *>(self->ops) :
nullptr;
if (reader == nullptr)
{
return NK_ENOENT;
}
reader->handler->Close();
return NK_EOK;
}
nk_err_t ReadImpl(
struct auth_service_ILoginForm *self,
const auth_service_ILoginForm_Read_req *req,
const nk_arena *reqArr,
auth_service_ILoginForm_Read_res *res,
nk_arena *resArena)
{
auto impl = self != nullptr ?
static_cast<const LoginFormHandlerImpl *>(self->ops) :
nullptr;
if (impl == nullptr)
{
return NK_ENOENT;
}
std::string htmlLine;
if (!impl->handler->ReadLine(htmlLine))
{
std::cerr << app::AppTag << __func__
<< " Error: Unable to read html line from file!" << std::endl;
}
nk_char_t *str =
nk_arena_alloc(nk_char_t, resArena, &res->line, htmlLine.length() + 1);
rtl_strncpy(str, htmlLine.c_str(), htmlLine.length());
return NK_EOK;
}
auth_service_ILoginForm *LoginFormHandler::CreateImpl(ISecretDataPtr secretData)
{
static LoginFormHandler reader(secretData);
static LoginFormHandlerImpl ops {};
static auth_service_ILoginForm impl = {.ops = &ops};
ops.Open = OpenImpl;
ops.Read = ReadImpl;
ops.Dispose = DisposeImpl;
ops.handler = &reader;
return &impl;
}
LoginFormHandler::LoginFormHandler(ISecretDataPtr secret) : m_secret(secret)
{}
bool LoginFormHandler::OpenLoginStream()
{
std::cout << app::AppTag << "Open login page request started" << std::endl;
m_secret->Init();
auto dh = m_secret->GetDhData();
m_htmlMaskData.clear();
m_htmlMaskData.emplace("{$serverG}", dh.g);
m_htmlMaskData.emplace("{$serverP}", dh.p);
m_htmlMaskData.emplace("{$serverKey}", dh.openKey);
m_htmlFile.close();
m_htmlFile.open(consts::AuthHtmlFile, std::ifstream::in);
if (!m_htmlFile.is_open())
{
std::cerr << app::AppTag << "Error: File '" << consts::AuthHtmlFile
<< "' not found" << std::endl;
return 0;
}
return m_htmlFile.is_open();
}
bool LoginFormHandler::ReadLine(std::string &htmlLine)
{
try
{
html_helper::ReadHtmlLine(m_htmlFile, htmlLine);
PutSecret(htmlLine);
}
catch (const std::exception &e)
{
std::cerr << app::AppTag << "Error: " << e.what() << std::endl;
return false;
}
return true;
}
void LoginFormHandler::Close()
{
m_htmlMaskData.clear();
m_htmlFile.close();
std::cout << app::AppTag << "Open login page request finished" << std::endl;
}
void LoginFormHandler::PutSecret(std::string &htmlLine)
{
for (auto it : m_htmlMaskData)
{
if (auto pval = std::get_if<std::string>(&it.second))
{
if (html_helper::ReplaceValueByMask(htmlLine, it.first, *pval))
{
break;
}
}
else if (auto pval = std::get_if<long>(&it.second))
{
if (html_helper::ReplaceValueByMask(htmlLine, it.first, *pval))
{
break;
}
}
}
}
login_result_handler.cpp
#include "login_result_handler.h"
#include "authservice.h"
#include "general.h"
#include "htmlhelper.h"
#include <coresrv/nk/transport-kos.h>
#include <coresrv/sl/sl_api.h>
#include <rtl/string.h>
#include <iostream>
#include <sstream>
namespace consts {
const std::string AuthResultOkHtmlFile("mnt/result_ok.html");
const std::string AuthResultErrHtmlFile("mnt/result_err.html");
} // namespace consts
namespace utils {
std::string GetArenaString(const nk_arena *arena, const nk_ptr_t *src)
{
nk_uint32_t msgLength = 0;
nk_char_t *nkMsg = nk_arena_get(nk_char_t, arena, src, &msgLength);
return nkMsg != nullptr ? nkMsg : "";
}
} // namespace utils
struct LoginResultHandlerImpl : auth_service_ILoginResultForm_ops
{
LoginResultHandler *handler;
};
nk_err_t OpenImpl(
struct auth_service_ILoginResultForm *self,
const auth_service_ILoginResultForm_Open_req *req,
const nk_arena *reqArena,
auth_service_ILoginResultForm_Open_res *res,
nk_arena *resArena)
{
auto impl = self != nullptr ?
static_cast<const LoginResultHandlerImpl *>(self->ops) :
nullptr;
if (impl == nullptr)
{
return NK_ENOENT;
}
auto userName = utils::GetArenaString(reqArena, &req->login.userName);
auto hexPassword = utils::GetArenaString(reqArena, &req->login.password);
auto oppositeOpenKey = utils::GetArenaString(reqArena, &req->login.cryptoB);
res->result =
impl->handler->OpenStream(userName, hexPassword, oppositeOpenKey);
return NK_EOK;
}
nk_err_t DisposeImpl(
struct auth_service_ILoginResultForm *self,
const auth_service_ILoginResultForm_Dispose_req *req,
const nk_arena *reqArr,
auth_service_ILoginResultForm_Dispose_res *res,
nk_arena *resArena)
{
auto impl = self != nullptr ?
static_cast<const LoginResultHandlerImpl *>(self->ops) :
nullptr;
if (impl == nullptr)
{
return NK_ENOENT;
}
impl->handler->Close();
return NK_EOK;
}
nk_err_t ReadImpl(
struct auth_service_ILoginResultForm *self,
const auth_service_ILoginResultForm_Read_req *req,
const nk_arena *reqArr,
auth_service_ILoginResultForm_Read_res *res,
nk_arena *resArena)
{
auto impl = self != nullptr ?
static_cast<const LoginResultHandlerImpl *>(self->ops) :
nullptr;
if (impl == nullptr)
{
return NK_ENOENT;
}
std::string htmlLine;
if (!impl->handler->ReadLine(htmlLine))
{
std::cerr << app::AppTag << __func__
<< " Error: Unable to read html line from file!" << std::endl;
}
nk_char_t *str =
nk_arena_alloc(nk_char_t, resArena, &res->line, htmlLine.length() + 1);
rtl_strncpy(str, htmlLine.c_str(), htmlLine.length());
return NK_EOK;
}
auth_service_ILoginResultForm *
LoginResultHandler::CreateImpl(ISecretDataPtr secret)
{
static LoginResultHandler reader(secret);
static LoginResultHandlerImpl ops {};
static auth_service_ILoginResultForm impl = {.ops = &ops};
ops.Open = OpenImpl;
ops.Read = ReadImpl;
ops.Dispose = DisposeImpl;
ops.handler = &reader;
return &impl;
}
LoginResultHandler::LoginResultHandler(ISecretDataPtr secret) : m_secret(secret)
{}
bool LoginResultHandler::OpenStream(
const std::string &userName,
const std::string &hexPasswordStr,
const std::string &cryptoBstr)
{
std::cout << app::AppTag << "Auth request: userName = " << userName
<< " hexPasswordStr = " << hexPasswordStr
<< " client open key = " << cryptoBstr
<< std::endl;
std::string password;
if (m_secret->IsInit())
{
uint64_t oppKey;
std::istringstream iss(cryptoBstr);
iss >> oppKey;
auto cryptoKey = m_secret->GetSecret(oppKey);
password = DecryptHexString(hexPasswordStr, cryptoKey);
}
AuthService auth;
m_isAuthentified = auth.Authentication(userName, password);
m_htmlFile.close();
auto fileName = m_isAuthentified ? consts::AuthResultOkHtmlFile :
consts::AuthResultErrHtmlFile;
m_htmlFile.open(fileName, std::ifstream::in);
if (!m_htmlFile.is_open())
{
std::cerr << app::AppTag << "Error: File '" << fileName << "' not found"
<< std::endl;
return 0;
}
return m_htmlFile.is_open();
}
bool LoginResultHandler::ReadLine(std::string &htmlLine)
{
try
{
html_helper::ReadHtmlLine(m_htmlFile, htmlLine);
}
catch (const std::exception &e)
{
std::cerr << app::AppTag << "Error: " << e.what() << std::endl;
return false;
}
return true;
}
void LoginResultHandler::Close()
{
m_htmlFile.close();
m_secret->Dispose();
}
bool LoginResultHandler::HexStrToNum(
const std::string &hexValueString, char &value)
{
char *p_end;
value = static_cast<char>(std::strtol(hexValueString.c_str(), &p_end, 16));
if (p_end == hexValueString.c_str())
{
return false;
}
return true;
}
std::string
LoginResultHandler::DecryptHexString(const std::string &input, long secret)
{
std::string strKey = std::to_string(secret);
while (strKey.length() < input.length())
{
strKey += strKey;
}
std::string result;
size_t j = 0;
for (size_t i = 0; i < input.length(); i += 2)
{
auto hexValue1String = input.substr(i, 2);
char value1;
if (!HexStrToNum(hexValue1String, value1))
{
return "";
}
char value2 = strKey[j++];
char xorValue = value1 ^ value2;
result += xorValue;
}
return result;
};
Page top