208 lines
6.2 KiB
C++
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);
|
|
}
|
|
}
|