Cerberus/commands.cpp
wheelchairy 118875234a upd
2025-01-28 22:33:54 +03:00

208 lines
6.2 KiB
C++

#include "commands.hpp"
#include "config.hpp"
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <iomanip>
#include <cstdio>
extern "C" {
#include "monocypher.h"
}
static const size_t NONCE_SIZE = 24;
static const size_t KEY_SIZE = 32;
static const size_t MAC_SIZE = 16;
static std::string toHex(const uint8_t* data, size_t len) {
std::ostringstream oss;
oss << std::hex;
for (size_t i=0;i<len;i++){
oss << std::setw(2)<<std::setfill('0')<<(int)data[i];
}
return oss.str();
}
static std::vector<uint8_t> fromHex(const std::string& hex) {
std::vector<uint8_t> data;
data.reserve(hex.size()/2);
for(size_t i=0;i<hex.size();i+=2){
uint8_t val=(uint8_t)std::stoi(hex.substr(i,2),nullptr,16);
data.push_back(val);
}
return data;
}
static void hexStrToKey(const std::string &hex, uint8_t outKey[32]) {
std::vector<uint8_t> buf=fromHex(hex);
if(buf.size()==32){
for(int i=0;i<32;i++) outKey[i]=buf[i];
}
}
static void handleNickCommand(const std::string &args, AppConfig &config) {
std::istringstream iss(args);
std::string sub;
iss >> sub;
if(sub=="set"){
std::string name;
std::getline(iss,name);
if(!name.empty() && name[0]==' ') name.erase(0,1);
config.nickname=name;
std::cout<<"[nick] set: "<<config.nickname<<"\n";
} else if(sub=="generatekey"){
FILE* f=fopen("/dev/urandom","rb");
if(!f)return;
fread(config.sharedSecret,1,KEY_SIZE,f);
fclose(f);
config.haveSharedSecret=true;
std::cout<<"[nick] 256-bit key generated: "<<toHex(config.sharedSecret,32)<<"\n";
}
}
static void handleWebCommand(const std::string &args, AppConfig &config);
static void handleSoundCommand(const std::string &args, AppConfig &config);
static void handleMakeTea(const std::string& input, AppConfig& config) {
std::istringstream iss(input);
std::string plaintext;
iss >> plaintext;
std::string keyHex;
iss >> keyHex;
uint8_t localKey[32];
bool useLocal=false;
if(!keyHex.empty()){
hexStrToKey(keyHex, localKey);
useLocal=true;
}
if(!config.haveSharedSecret && !useLocal){
FILE* f=fopen("/dev/urandom","rb");
if(!f)return;
fread(config.sharedSecret,1,KEY_SIZE,f);
fclose(f);
config.haveSharedSecret=true;
std::cout<<"[makeTea] No key found, random generated: "<<toHex(config.sharedSecret,32)<<"\n";
}
std::vector<uint8_t> nonce(NONCE_SIZE), mac(MAC_SIZE);
std::vector<uint8_t> ciphertext(plaintext.size());
{
FILE* f=fopen("/dev/urandom","rb");
fread(nonce.data(),1,NONCE_SIZE,f);
fclose(f);
}
const uint8_t* usedKey= useLocal? localKey : config.sharedSecret;
crypto_aead_lock(
ciphertext.data(),
mac.data(),
usedKey,
nonce.data(),
nullptr,0,
(const uint8_t*)plaintext.data(),
plaintext.size()
);
std::vector<uint8_t> out;
out.insert(out.end(),nonce.begin(),nonce.end());
out.insert(out.end(),mac.begin(),mac.end());
out.insert(out.end(),ciphertext.begin(),ciphertext.end());
std::cout<<"[makeTea] keyUsed="<<toHex(usedKey,32)<<"\n";
std::ostringstream oss;
for(auto &x: out){
oss<<std::hex<<std::setw(2)<<std::setfill('0')<<(int)x;
}
std::cout<<"[makeTea] encrypted: "<<oss.str()<<"\n";
}
static void handleDrinkTea(const std::string& input, AppConfig& config) {
std::istringstream iss(input);
std::string hexIn;
iss >> hexIn;
std::string keyHex;
iss >> keyHex;
uint8_t localKey[32];
bool useLocal=false;
if(!keyHex.empty()){
hexStrToKey(keyHex, localKey);
useLocal=true;
}
if(!config.haveSharedSecret && !useLocal) return;
auto data=fromHex(hexIn);
if(data.size()<NONCE_SIZE+MAC_SIZE) return;
std::vector<uint8_t> nonce(data.begin(), data.begin()+NONCE_SIZE);
std::vector<uint8_t> mac(data.begin()+NONCE_SIZE, data.begin()+NONCE_SIZE+MAC_SIZE);
std::vector<uint8_t> cipher(data.begin()+NONCE_SIZE+MAC_SIZE, data.end());
std::vector<uint8_t> plain(cipher.size());
const uint8_t* usedKey= useLocal? localKey : config.sharedSecret;
int rc=crypto_aead_unlock(
plain.data(),
mac.data(),
usedKey,
nonce.data(),
nullptr,0,
cipher.data(),
cipher.size()
);
if(rc!=0){
std::cerr<<"[drinkTea] MAC error\n";
return;
}
std::string s((char*)plain.data(),plain.size());
std::cout<<"[drinkTea] keyUsed="<<toHex(usedKey,32)<<"\n";
std::cout<<"[drinkTea] decrypted: "<<s<<"\n";
}
void processCommand(const std::string& input, AppConfig& config) {
if(input.rfind("nick ",0)==0){
handleNickCommand(input.substr(5), config);
return;
}
if(input.rfind("web ",0)==0){
handleWebCommand(input.substr(4), config);
return;
}
if(input.rfind("sound ",0)==0){
handleSoundCommand(input.substr(6), config);
return;
}
if(input.rfind("cerber maketea ",0)==0){
handleMakeTea(input.substr(15), config);
return;
}
if(input.rfind("cerber drinktea ",0)==0){
handleDrinkTea(input.substr(16), config);
return;
}
if(input=="exit"){
std::cout<<"[cli] exit\n";
exit(0);
}
std::cout<<"[cli] Unknown: "<<input<<"\n";
}
static void handleWebCommand(const std::string &args, AppConfig &config){
std::istringstream iss(args);
std::string cmd; iss>>cmd;
if(cmd=="start"){
extern void webServerStart(AppConfig&);
webServerStart(config);
} else if(cmd=="connect"){
std::string t,ip; iss>>t>>ip;
extern void webServerConnect(AppConfig&,const std::string&,const std::string&);
webServerConnect(config,t,ip);
} else if(cmd=="stop"){
extern void webServerStop(AppConfig&);
webServerStop(config);
}
}
static void handleSoundCommand(const std::string &args, AppConfig &config){
std::istringstream iss(args);
std::string cmd; iss>>cmd;
if(cmd=="find"){
extern void soundFind(AppConfig&);
soundFind(config);
} else if(cmd=="lose"){
extern void soundLose(AppConfig&);
soundLose(config);
}
}