upd
This commit is contained in:
parent
7ed2435811
commit
118875234a
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*.o
|
||||||
|
cerberus
|
48
Makefile
48
Makefile
@ -1,42 +1,38 @@
|
|||||||
CC = clang
|
CC = clang
|
||||||
CXX = clang++
|
CXX = clang++
|
||||||
|
CFLAGS = -O2 -Wall -I./libs -pthread
|
||||||
CFLAGS = -O2 -Wall -I./libs
|
CXXFLAGS = -std=c++17 -O2 -Wall -I./libs -pthread
|
||||||
CXXFLAGS = -std=c++17 -O2 -Wall -I./libs
|
|
||||||
|
|
||||||
UNAME_S := $(shell uname -s)
|
UNAME_S := $(shell uname -s)
|
||||||
BREW_PREFIX := $(shell brew --prefix portaudio 2>/dev/null)
|
BREW_PREFIX := $(shell brew --prefix portaudio 2>/dev/null)
|
||||||
|
|
||||||
|
ifneq ($(UNAME_S),)
|
||||||
ifeq ($(UNAME_S),Darwin)
|
ifeq ($(UNAME_S),Darwin)
|
||||||
ifneq ($(BREW_PREFIX),)
|
ifneq ($(BREW_PREFIX),)
|
||||||
CFLAGS += -I$(BREW_PREFIX)/include
|
CFLAGS += -I$(BREW_PREFIX)/include
|
||||||
CXXFLAGS += -I$(BREW_PREFIX)/include
|
CXXFLAGS += -I$(BREW_PREFIX)/include
|
||||||
LIBS += -L$(BREW_PREFIX)/lib -lportaudio
|
LIBS += -L$(BREW_PREFIX)/lib -lportaudio
|
||||||
else
|
|
||||||
$(warning [Makefile] PortAudio не найдена через Homebrew. Установите её: brew install portaudio)
|
|
||||||
endif
|
|
||||||
else ifeq ($(UNAME_S),Linux)
|
|
||||||
HAVE_PKG := $(shell pkg-config --exists portaudio-2.0 && echo yes || echo no)
|
|
||||||
ifeq ($(HAVE_PKG),yes)
|
|
||||||
PORTAUDIO_CFLAGS := $(shell pkg-config --cflags portaudio-2.0)
|
|
||||||
PORTAUDIO_LIBS := $(shell pkg-config --libs portaudio-2.0)
|
|
||||||
CFLAGS += $(PORTAUDIO_CFLAGS)
|
|
||||||
CXXFLAGS += $(PORTAUDIO_CFLAGS)
|
|
||||||
LIBS += $(PORTAUDIO_LIBS)
|
|
||||||
else
|
|
||||||
$(warning [Makefile] portaudio-2.0 не найдена через pkg-config. Использую -lportaudio)
|
|
||||||
LIBS += -lportaudio
|
|
||||||
endif
|
|
||||||
else
|
else
|
||||||
$(warning [Makefile] Unsupported OS: $(UNAME_S))
|
$(warning PortAudio not found via brew)
|
||||||
|
endif
|
||||||
|
else ifeq ($(UNAME_S),Linux)
|
||||||
|
HAVE_PKG := $(shell pkg-config --exists portaudio-2.0 && echo yes || echo no)
|
||||||
|
ifeq ($(HAVE_PKG),yes)
|
||||||
|
PORTAUDIO_CFLAGS := $(shell pkg-config --cflags portaudio-2.0)
|
||||||
|
PORTAUDIO_LIBS := $(shell pkg-config --libs portaudio-2.0)
|
||||||
|
CFLAGS += $(PORTAUDIO_CFLAGS)
|
||||||
|
CXXFLAGS += $(PORTAUDIO_CFLAGS)
|
||||||
|
LIBS += $(PORTAUDIO_LIBS)
|
||||||
|
else
|
||||||
|
$(warning portaudio-2.0 not found, using -lportaudio)
|
||||||
|
LIBS += -lportaudio
|
||||||
|
endif
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SRCS_CPP = main.cpp commands.cpp cli.cpp webserver.cpp sound.cpp bfsk.cpp x25519_handshake.cpp
|
SRCS_CPP = main.cpp commands.cpp cli.cpp webserver.cpp sound.cpp bfsk.cpp x25519_handshake.cpp
|
||||||
SRCS_C = libs/monocypher.c libs/linenoise.c
|
SRCS_C = libs/monocypher.c libs/linenoise.c
|
||||||
|
|
||||||
OBJS_CPP = $(SRCS_CPP:.cpp=.o)
|
OBJS_CPP = $(SRCS_CPP:.cpp=.o)
|
||||||
OBJS_C = $(SRCS_C:.c=.o)
|
OBJS_C = $(SRCS_C:.c=.o)
|
||||||
|
|
||||||
TARGET = cerberus
|
TARGET = cerberus
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
105
bfsk.cpp
105
bfsk.cpp
@ -1,78 +1,53 @@
|
|||||||
#include "bfsk.hpp"
|
#include "bfsk.hpp"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
std::vector<float> bfskModulate(const std::vector<unsigned char> &data) {
|
std::vector<float> bfskModulate(const std::vector<uint8_t> &data){
|
||||||
int samplesPerBit = (int)((double)SAMPLE_RATE / BFSK_BAUD);
|
int spb=(int)(SAMPLE_RATE/BFSK_BAUD);
|
||||||
size_t totalBits = data.size() * 8;
|
size_t tb=data.size()*8;
|
||||||
size_t totalSamples = totalBits * samplesPerBit;
|
size_t ts=tb*spb;
|
||||||
std::vector<float> out(totalSamples * 2, 0.0f);
|
std::vector<float> out(ts*2,0.0f);
|
||||||
|
double phase0=0.0,phase1=0.0;
|
||||||
double phase0 = 0.0;
|
double inc0=2.0*M_PI*BFSK_FREQ0/(double)SAMPLE_RATE;
|
||||||
double phase1 = 0.0;
|
double inc1=2.0*M_PI*BFSK_FREQ1/(double)SAMPLE_RATE;
|
||||||
double inc0 = 2.0 * M_PI * BFSK_FREQ0 / (double)SAMPLE_RATE;
|
size_t idx=0;
|
||||||
double inc1 = 2.0 * M_PI * BFSK_FREQ1 / (double)SAMPLE_RATE;
|
for(auto byteVal:data){
|
||||||
|
for(int b=0;b<8;b++){
|
||||||
size_t sampleIndex = 0;
|
int bit=(byteVal>>b)&1;
|
||||||
|
for(int s=0;s<spb;s++){
|
||||||
for (auto byteVal : data) {
|
float val=bit? sinf((float)phase1): sinf((float)phase0);
|
||||||
for (int b = 0; b < 8; b++) {
|
if(bit) phase1+=inc1; else phase0+=inc0;
|
||||||
int bit = (byteVal >> b) & 1;
|
out[idx*2+0]=val*0.3f;
|
||||||
for (int s = 0; s < samplesPerBit; s++) {
|
out[idx*2+1]=val*0.3f;
|
||||||
float val;
|
idx++;
|
||||||
if (bit == 0) {
|
|
||||||
val = sinf((float)phase0);
|
|
||||||
phase0 += inc0;
|
|
||||||
} else {
|
|
||||||
val = sinf((float)phase1);
|
|
||||||
phase1 += inc1;
|
|
||||||
}
|
|
||||||
out[sampleIndex*2 + 0] = val * 0.3f;
|
|
||||||
out[sampleIndex*2 + 1] = val * 0.3f;
|
|
||||||
sampleIndex++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned char> bfskDemodulate(const std::vector<float> &monoData) {
|
std::vector<uint8_t> bfskDemodulate(const std::vector<float> &monoData){
|
||||||
int samplesPerBit = (int)((double)SAMPLE_RATE / BFSK_BAUD);
|
int spb=(int)(SAMPLE_RATE/BFSK_BAUD);
|
||||||
size_t totalBits = monoData.size() / samplesPerBit;
|
size_t tb=monoData.size()/spb;
|
||||||
size_t totalBytes = totalBits / 8;
|
size_t tbytes=tb/8;
|
||||||
|
std::vector<uint8_t> res(tbytes,0);
|
||||||
double inc0 = 2.0 * M_PI * BFSK_FREQ0 / (double)SAMPLE_RATE;
|
double inc0=2.0*M_PI*BFSK_FREQ0/(double)SAMPLE_RATE;
|
||||||
double inc1 = 2.0 * M_PI * BFSK_FREQ1 / (double)SAMPLE_RATE;
|
double inc1=2.0*M_PI*BFSK_FREQ1/(double)SAMPLE_RATE;
|
||||||
|
size_t bitIdx=0;
|
||||||
std::vector<unsigned char> result(totalBytes, 0);
|
for(size_t b=0;b<tb;b++){
|
||||||
|
double sum0=0.0,sum1=0.0;
|
||||||
size_t bitIndex = 0;
|
double ph0=0.0,ph1=0.0;
|
||||||
for (size_t b = 0; b < totalBits; b++) {
|
size_t st=b*spb;
|
||||||
double sum0 = 0.0;
|
for(int s=0;s<spb;s++){
|
||||||
double sum1 = 0.0;
|
float sample=monoData[st+s];
|
||||||
double phase0 = 0.0;
|
float r0=sinf((float)ph0), r1=sinf((float)ph1);
|
||||||
double phase1 = 0.0;
|
sum0+=sample*r0; sum1+=sample*r1;
|
||||||
|
ph0+=inc0; ph1+=inc1;
|
||||||
size_t startSample = b * samplesPerBit;
|
|
||||||
for (int s = 0; s < samplesPerBit; s++) {
|
|
||||||
float sample = monoData[startSample + s];
|
|
||||||
float ref0 = sinf((float)phase0);
|
|
||||||
float ref1 = sinf((float)phase1);
|
|
||||||
sum0 += sample * ref0;
|
|
||||||
sum1 += sample * ref1;
|
|
||||||
phase0 += inc0;
|
|
||||||
phase1 += inc1;
|
|
||||||
}
|
}
|
||||||
|
int bit=(std::fabs(sum1)>std::fabs(sum0))?1:0;
|
||||||
int bit = (std::fabs(sum1) > std::fabs(sum0)) ? 1 : 0;
|
size_t bytePos=bitIdx/8; int bitPos=bitIdx%8;
|
||||||
size_t bytePos = bitIndex / 8;
|
if(bytePos<res.size()) res[bytePos]|=(bit<<bitPos);
|
||||||
int bitPos = bitIndex % 8;
|
bitIdx++;
|
||||||
if (bytePos < result.size()) {
|
|
||||||
result[bytePos] |= (bit << bitPos);
|
|
||||||
}
|
|
||||||
bitIndex++;
|
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
14
bfsk.hpp
14
bfsk.hpp
@ -1,11 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
constexpr double BFSK_FREQ0 = 1000.0;
|
constexpr double BFSK_FREQ0=1000.0;
|
||||||
constexpr double BFSK_FREQ1 = 2000.0;
|
constexpr double BFSK_FREQ1=2000.0;
|
||||||
constexpr double BFSK_BAUD = 100.0;
|
constexpr double BFSK_BAUD=100.0;
|
||||||
constexpr int SAMPLE_RATE = 44100;
|
constexpr int SAMPLE_RATE=44100;
|
||||||
|
|
||||||
std::vector<float> bfskModulate(const std::vector<unsigned char> &data);
|
std::vector<float> bfskModulate(const std::vector<uint8_t> &data);
|
||||||
|
std::vector<uint8_t> bfskDemodulate(const std::vector<float> &monoData);
|
||||||
std::vector<unsigned char> bfskDemodulate(const std::vector<float> &monoData);
|
|
||||||
|
66
cli.cpp
66
cli.cpp
@ -1,60 +1,58 @@
|
|||||||
#include "cli.hpp"
|
#include "cli.hpp"
|
||||||
#include "commands.hpp"
|
#include "commands.hpp"
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "libs/linenoise.h"
|
#include "libs/linenoise.h"
|
||||||
|
|
||||||
#define CLR_RESET "\x1b[0m"
|
static const char* asciiArt =
|
||||||
#define CLR_CYAN "\x1b[36m"
|
" (`-') _ (`-') <-.(`-') (`-') _ (`-') (`-').->\n"
|
||||||
|
" _ ( OO).-/<-.(OO ) __( OO) ( OO).-/<-.(OO ) .-> ( OO)_ \n"
|
||||||
|
" \\-,-----.(,------.,------,)'-'---.\\ (,------.,------,),--.(,--. (_)--\\_) \n"
|
||||||
|
" | .--./ | .---'| /`. '| .-. (/ | .---'| /`. '| | |(`-')/ _ / \n"
|
||||||
|
" /_) (`-')(| '--. | |_.' || '-' `.)(| '--. | |_.' || | |(OO )\\_..`--. \n"
|
||||||
|
" || |OO ) | .--' | . .'| /`'. | | .--' | . .'| | | | \\.-._) \\\n"
|
||||||
|
"(_' '--'\\ | `---.| |\\ \\ | '--' / | `---.| |\\ \\ \\ '-'(_ .'\\ /\n"
|
||||||
|
" `-----' `------'`--' '--'`------' `------'`--' '--' `-----' `-----'\n";
|
||||||
|
|
||||||
static void completionCallback(const char *input, linenoiseCompletions *completions) {
|
static void completionCallback(const char *input, linenoiseCompletions *lc) {
|
||||||
if (strncmp(input, "nick", 4) == 0) {
|
if(strncmp(input,"nick ",5)==0) linenoiseAddCompletion(lc,"nick set ");
|
||||||
linenoiseAddCompletion(completions, "nick set ");
|
else if(strncmp(input,"nick g",6)==0) linenoiseAddCompletion(lc,"nick generatekey");
|
||||||
linenoiseAddCompletion(completions, "nick generatekey");
|
else if(strncmp(input,"web s",5)==0) linenoiseAddCompletion(lc,"web start");
|
||||||
}
|
else if(strncmp(input,"web c",5)==0) linenoiseAddCompletion(lc,"web connect pm 127.0.0.1");
|
||||||
else if (strncmp(input, "web", 3) == 0) {
|
else if(strncmp(input,"web s",5)==0) linenoiseAddCompletion(lc,"web stop");
|
||||||
linenoiseAddCompletion(completions, "web start");
|
else if(strncmp(input,"sound f",7)==0) linenoiseAddCompletion(lc,"sound find");
|
||||||
linenoiseAddCompletion(completions, "web connect pm 127.0.0.1");
|
else if(strncmp(input,"sound l",7)==0) linenoiseAddCompletion(lc,"sound lose");
|
||||||
linenoiseAddCompletion(completions, "web stop");
|
else if(strncmp(input,"cerber ma",9)==0) linenoiseAddCompletion(lc,"cerber maketea <text> [key]");
|
||||||
}
|
else if(strncmp(input,"cerber dr",9)==0) linenoiseAddCompletion(lc,"cerber drinktea <hex> [key]");
|
||||||
else if (strncmp(input, "sound", 5) == 0) {
|
else if(strncmp(input,"exit",4)==0) linenoiseAddCompletion(lc,"exit");
|
||||||
linenoiseAddCompletion(completions, "sound find");
|
|
||||||
linenoiseAddCompletion(completions, "sound lose");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void runCLI(AppConfig &config) {
|
void runCLI(AppConfig &config) {
|
||||||
linenoiseHistoryLoad("history.txt");
|
linenoiseHistoryLoad("history.txt");
|
||||||
|
|
||||||
linenoiseSetCompletionCallback(completionCallback);
|
linenoiseSetCompletionCallback(completionCallback);
|
||||||
|
|
||||||
std::cout << CLR_CYAN "Cerberus BFSK Demo (linenoise + color)\n"
|
std::cout << asciiArt << "\n"
|
||||||
<< "Доступные команды:\n"
|
<< CLR_CYAN << "Cerberus BFSK:\n"
|
||||||
<< " nick set <usernick>\n"
|
<< " nick set <usernick>\n"
|
||||||
<< " nick generatekey\n"
|
<< " nick generatekey\n"
|
||||||
<< " web start / web connect pm|server <ip> / web stop\n"
|
<< " web start/connect/stop\n"
|
||||||
<< " sound find / sound lose\n"
|
<< " sound find/lose\n"
|
||||||
<< " exit\n\n" CLR_RESET;
|
<< " cerber maketea <text> [hexKey]\n"
|
||||||
|
<< " cerber drinktea <hex> [hexKey]\n"
|
||||||
|
<< " exit\n"
|
||||||
|
<< CLR_RESET;
|
||||||
|
|
||||||
while (true) {
|
while(true){
|
||||||
char *line = linenoise(CLR_CYAN ">_ " CLR_RESET);
|
char* line = linenoise(">_ ");
|
||||||
if (!line) {
|
if(!line) break;
|
||||||
std::cout << "\n[cli] EOF/Ctrl+C - выходим.\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
std::string input(line);
|
std::string input(line);
|
||||||
free(line);
|
free(line);
|
||||||
|
if(!input.empty()){
|
||||||
if (!input.empty()) {
|
|
||||||
linenoiseHistoryAdd(input.c_str());
|
linenoiseHistoryAdd(input.c_str());
|
||||||
linenoiseHistorySave("history.txt");
|
linenoiseHistorySave("history.txt");
|
||||||
|
|
||||||
processCommand(input, config);
|
processCommand(input, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1
cli.hpp
1
cli.hpp
@ -1,5 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
|
||||||
void runCLI(AppConfig &config);
|
void runCLI(AppConfig &config);
|
||||||
|
284
commands.cpp
284
commands.cpp
@ -1,113 +1,207 @@
|
|||||||
#include "commands.hpp"
|
#include "commands.hpp"
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
#include "webserver.hpp"
|
|
||||||
#include "sound.hpp"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <string>
|
||||||
#include <iterator>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
extern "C" {
|
||||||
static std::vector<std::string> splitTokens(const std::string &line) {
|
#include "monocypher.h"
|
||||||
std::istringstream iss(line);
|
|
||||||
return { std::istream_iterator<std::string>(iss),
|
|
||||||
std::istream_iterator<std::string>() };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void generateKey(AppConfig &config) {
|
static const size_t NONCE_SIZE = 24;
|
||||||
config.key.resize(32);
|
static const size_t KEY_SIZE = 32;
|
||||||
FILE* f = fopen("/dev/urandom", "rb");
|
static const size_t MAC_SIZE = 16;
|
||||||
if (!f) {
|
|
||||||
std::cerr << CLR_RED "[nick] Не удалось открыть /dev/urandom\n" CLR_RESET;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
fread(config.key.data(), 1, 32, f);
|
std::string s((char*)plain.data(),plain.size());
|
||||||
fclose(f);
|
std::cout<<"[drinkTea] keyUsed="<<toHex(usedKey,32)<<"\n";
|
||||||
|
std::cout<<"[drinkTea] decrypted: "<<s<<"\n";
|
||||||
std::cout << CLR_GREEN "[nick] 256-битный ключ сгенерирован!\n" CLR_RESET;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void processCommand(const std::string &input, AppConfig &config) {
|
void processCommand(const std::string& input, AppConfig& config) {
|
||||||
if (input.empty()) return;
|
if(input.rfind("nick ",0)==0){
|
||||||
|
handleNickCommand(input.substr(5), config);
|
||||||
auto tokens = splitTokens(input);
|
return;
|
||||||
if (tokens.empty()) return;
|
|
||||||
|
|
||||||
std::string cmd = tokens[0];
|
|
||||||
|
|
||||||
if (cmd == "nick") {
|
|
||||||
if (tokens.size() < 2) {
|
|
||||||
std::cout << CLR_YELLOW "[nick] Доступно: set <name>, generatekey\n" CLR_RESET;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::string sub = tokens[1];
|
|
||||||
if (sub == "set") {
|
|
||||||
if (tokens.size() < 3) {
|
|
||||||
std::cout << CLR_YELLOW "[nick] Использование: nick set <usernick>\n" CLR_RESET;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::string newNick;
|
|
||||||
for (size_t i = 2; i < tokens.size(); i++) {
|
|
||||||
if (i > 2) newNick += " ";
|
|
||||||
newNick += tokens[i];
|
|
||||||
}
|
|
||||||
config.nickname = newNick;
|
|
||||||
std::cout << CLR_GREEN "[nick] Установлен ник: " << newNick << "\n" CLR_RESET;
|
|
||||||
}
|
|
||||||
else if (sub == "generatekey") {
|
|
||||||
generateKey(config);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
std::cout << CLR_YELLOW "[nick] Неизвестная подкоманда: " << sub << "\n" CLR_RESET;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (cmd == "web") {
|
if(input.rfind("web ",0)==0){
|
||||||
if (tokens.size() < 2) {
|
handleWebCommand(input.substr(4), config);
|
||||||
std::cout << CLR_YELLOW "[web] Доступно: start, connect pm|server <ip>, stop\n" CLR_RESET;
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::string sub = tokens[1];
|
|
||||||
if (sub == "start") {
|
|
||||||
webServerStart(config);
|
|
||||||
}
|
|
||||||
else if (sub == "connect") {
|
|
||||||
if (tokens.size() < 4) {
|
|
||||||
std::cout << CLR_YELLOW "[web] Использование: web connect <pm|server> <ip>\n" CLR_RESET;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::string ctype = tokens[2];
|
|
||||||
std::string ip = tokens[3];
|
|
||||||
webServerConnect(config, ctype, ip);
|
|
||||||
}
|
|
||||||
else if (sub == "stop") {
|
|
||||||
webServerStop(config);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
std::cout << CLR_YELLOW "[web] Неизвестная подкоманда: " << sub << "\n" CLR_RESET;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (cmd == "sound") {
|
if(input.rfind("sound ",0)==0){
|
||||||
if (tokens.size() < 2) {
|
handleSoundCommand(input.substr(6), config);
|
||||||
std::cout << CLR_YELLOW "[sound] Доступно: find, lose\n" CLR_RESET;
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::string sub = tokens[1];
|
|
||||||
if (sub == "find") {
|
|
||||||
soundFind(config);
|
|
||||||
}
|
|
||||||
else if (sub == "lose") {
|
|
||||||
soundLose(config);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
std::cout << CLR_YELLOW "[sound] Неизвестная подкоманда: " << sub << "\n" CLR_RESET;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (cmd == "exit") {
|
if(input.rfind("cerber maketea ",0)==0){
|
||||||
std::cout << CLR_CYAN "[cli] Завершаем работу по команде 'exit'\n" CLR_RESET;
|
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);
|
exit(0);
|
||||||
}
|
}
|
||||||
else {
|
std::cout<<"[cli] Unknown: "<<input<<"\n";
|
||||||
std::cout << CLR_RED "Неизвестная команда: " << cmd << CLR_RESET << "\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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "config.hpp"
|
|
||||||
|
|
||||||
void processCommand(const std::string &input, AppConfig &config);
|
struct AppConfig;
|
||||||
|
void processCommand(const std::string& input, AppConfig& config);
|
||||||
|
BIN
commands.o
BIN
commands.o
Binary file not shown.
32
config.hpp
32
config.hpp
@ -1,30 +1,22 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#define CLR_RESET "\x1b[0m"
|
#define CLR_RESET "\x1b[0m"
|
||||||
#define CLR_BOLD "\x1b[1m"
|
#define CLR_BOLD "\x1b[1m"
|
||||||
#define CLR_RED "\x1b[31m"
|
#define CLR_RED "\x1b[31m"
|
||||||
#define CLR_GREEN "\x1b[32m"
|
#define CLR_GREEN "\x1b[32m"
|
||||||
#define CLR_YELLOW "\x1b[33m"
|
#define CLR_YELLOW "\x1b[33m"
|
||||||
#define CLR_BLUE "\x1b[34m"
|
#define CLR_BLUE "\x1b[34m"
|
||||||
#define CLR_MAGENTA "\x1b[35m"
|
#define CLR_CYAN "\x1b[36m"
|
||||||
#define CLR_CYAN "\x1b[36m"
|
|
||||||
#define CLR_WHITE "\x1b[37m"
|
|
||||||
|
|
||||||
struct AppConfig {
|
struct AppConfig {
|
||||||
std::string nickname = "noname";
|
std::string nickname;
|
||||||
|
bool webServerRunning;
|
||||||
std::vector<unsigned char> key;
|
bool soundExchangeActive;
|
||||||
|
|
||||||
bool webServerRunning = false;
|
|
||||||
bool soundExchangeActive = false;
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t ephemeralSec[32];
|
uint8_t ephemeralSec[32];
|
||||||
uint8_t ephemeralPub[32];
|
uint8_t ephemeralPub[32];
|
||||||
|
|
||||||
uint8_t sharedSecret[32];
|
uint8_t sharedSecret[32];
|
||||||
bool haveSharedSecret = false;
|
bool haveSharedSecret;
|
||||||
|
AppConfig(): nickname("noname"), webServerRunning(false), soundExchangeActive(false), haveSharedSecret(false) {}
|
||||||
};
|
};
|
||||||
|
56
history.txt
56
history.txt
@ -13,3 +13,59 @@ web find
|
|||||||
web find
|
web find
|
||||||
sound find
|
sound find
|
||||||
exit
|
exit
|
||||||
|
sound find
|
||||||
|
sound lose
|
||||||
|
exit
|
||||||
|
ls
|
||||||
|
help
|
||||||
|
sound
|
||||||
|
nick set
|
||||||
|
nick set platon
|
||||||
|
nick generatekey
|
||||||
|
cerber maketea
|
||||||
|
cerber maketea aboba
|
||||||
|
cerber drinktea fa93d14d8702e215e805098b5ab58c518bf082c6e882bc6952674750b600000000000000000000005167bc15e8
|
||||||
|
sound find
|
||||||
|
sound find
|
||||||
|
sound lose
|
||||||
|
exirt
|
||||||
|
exit
|
||||||
|
sound find
|
||||||
|
sound lose
|
||||||
|
exit
|
||||||
|
nick set platon
|
||||||
|
nick generatekey
|
||||||
|
nick maketea textual
|
||||||
|
cerber maketea xuy
|
||||||
|
cerber drinktea 60551f937ad549d2aa2492e05ba684acc67a90f95ab713bcdce90200000000000000000000000000a86932
|
||||||
|
nick generatekey
|
||||||
|
cerber maketea mother
|
||||||
|
cerber drinktea a13f5ea8ff23673d45c7e43f690752e9d48360a00a576554b80829668888a1e3bcbec311c5c8afad373e62289c57
|
||||||
|
nick set Alice
|
||||||
|
nick generatekey
|
||||||
|
cerber maketea Hi
|
||||||
|
nick set Bob
|
||||||
|
nick generatekey
|
||||||
|
cerber drinktea 930bd444ebfb9794517067f83a0c50ec678ed8b2632ba7c69201f76b62a43b395457eba05939b7c78ca6
|
||||||
|
exit
|
||||||
|
nick generatekey
|
||||||
|
cerber maketea hi
|
||||||
|
cerber drinktea 1d5068faafb248389fc305fef3df85d9bd2cbc93f552cfe77a7521ed4a1cbf27c985dc48865f45e13b05
|
||||||
|
nick set bob
|
||||||
|
nick generatekey
|
||||||
|
cerber drinktea 1d5068faafb248389fc305fef3df85d9bd2cbc93f552cfe77a7521ed4a1cbf27c985dc48865f45e13b05
|
||||||
|
nick set noname
|
||||||
|
nick generatekey
|
||||||
|
cerber drinktea 1d5068faafb248389fc305fef3df85d9bd2cbc93f552cfe77a7521ed4a1cbf27c985dc48865f45e13b05
|
||||||
|
Ńexit
|
||||||
|
exit
|
||||||
|
nick generatekey
|
||||||
|
exit
|
||||||
|
cerber maketea pidor
|
||||||
|
cerber drinktea 4c2f53f936e6d576e54e5a0ae88c9e87441fc77d852c0461b5cfb8a14358c929407a181a2f65ea93528f741057
|
||||||
|
exit
|
||||||
|
nick generatekey
|
||||||
|
cerber maketea penis 424cbf882606a41382aad5ce96d24688e04c7adf6cceca8d57bcb6a83a02adcb
|
||||||
|
cerber drinktea 209a9ef75a9a84434bb9ec84cd71c6fc0b6024da3f9ea550b4bb868f5efed3400cb06f4623a904618cb9317f35 keyUsed=424cbf882606a41382aad5ce96d24688e04c7adf6cceca8d57bcb6a83a02adcb
|
||||||
|
cerber drinktea 209a9ef75a9a84434bb9ec84cd71c6fc0b6024da3f9ea550b4bb868f5efed3400cb06f4623a904618cb9317f35 424cbf882606a41382aad5ce96d24688e04c7adf6cceca8d57bcb6a83a02adcb
|
||||||
|
exit
|
||||||
|
205
sound.cpp
205
sound.cpp
@ -1,180 +1,95 @@
|
|||||||
|
|
||||||
#include "sound.hpp"
|
#include "sound.hpp"
|
||||||
#include "bfsk.hpp"
|
#include "bfsk.hpp"
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
#include "x25519_handshake.hpp"
|
#include "x25519_handshake.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#include <portaudio.h>
|
#include <portaudio.h>
|
||||||
|
|
||||||
extern "C" {
|
constexpr int CAPTURE_SECONDS=3;
|
||||||
#include "monocypher.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr int CAPTURE_SECONDS = 3;
|
|
||||||
|
|
||||||
static std::atomic<bool> gSoundActive{false};
|
static std::atomic<bool> gSoundActive{false};
|
||||||
static std::thread gSoundThread;
|
static std::thread gSoundThread;
|
||||||
|
|
||||||
static std::vector<float> gInputBuffer;
|
static std::vector<float> gInputBuffer;
|
||||||
static size_t gWritePos = 0;
|
static size_t gWritePos=0;
|
||||||
|
|
||||||
static std::vector<float> gOutputBuffer;
|
static std::vector<float> gOutputBuffer;
|
||||||
static size_t gReadPos = 0;
|
static size_t gReadPos=0;
|
||||||
|
|
||||||
static int audioCallback(const void *input,
|
static int audioCallback(const void *input,void *output,unsigned long frameCount,const PaStreamCallbackTimeInfo*,PaStreamCallbackFlags,void*){
|
||||||
void *output,
|
const float *in=(const float*)input;
|
||||||
unsigned long frameCount,
|
float *out=(float*)output;
|
||||||
const PaStreamCallbackTimeInfo* timeInfo,
|
for(unsigned long i=0;i<frameCount;i++){
|
||||||
PaStreamCallbackFlags statusFlags,
|
if(gWritePos<gInputBuffer.size()){
|
||||||
void *userData)
|
gInputBuffer[gWritePos++]=in?in[i]:0.0f;
|
||||||
{
|
|
||||||
(void)timeInfo; (void)statusFlags; (void)userData;
|
|
||||||
const float *in = static_cast<const float*>(input);
|
|
||||||
float *out = static_cast<float*>(output);
|
|
||||||
|
|
||||||
for (unsigned long i = 0; i < frameCount; i++) {
|
|
||||||
if (gWritePos < gInputBuffer.size()) {
|
|
||||||
gInputBuffer[gWritePos++] = in ? in[i] : 0.0f;
|
|
||||||
}
|
}
|
||||||
|
float sample=0.0f;
|
||||||
float sample = 0.0f;
|
if(gReadPos<gOutputBuffer.size()){
|
||||||
if (gReadPos < gOutputBuffer.size()) {
|
sample=gOutputBuffer[gReadPos++];
|
||||||
sample = gOutputBuffer[gReadPos++];
|
|
||||||
}
|
}
|
||||||
out[i*2 + 0] = sample;
|
out[i*2+0]=sample;
|
||||||
out[i*2 + 1] = sample;
|
out[i*2+1]=sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
return paContinue;
|
return paContinue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void soundThreadFunc(AppConfig config) {
|
static void soundThreadFunc(AppConfig config){
|
||||||
PaError err = Pa_Initialize();
|
PaError err=Pa_Initialize();
|
||||||
if (err != paNoError) {
|
if(err!=paNoError)return;
|
||||||
std::cerr << CLR_RED "[sound] Pa_Initialize error: " << Pa_GetErrorText(err) << CLR_RESET "\n";
|
PaStreamParameters inParams,outParams;
|
||||||
return;
|
inParams.device=Pa_GetDefaultInputDevice();
|
||||||
}
|
if(inParams.device==paNoDevice){Pa_Terminate();return;}
|
||||||
|
inParams.channelCount=1;
|
||||||
PaStreamParameters inParams, outParams;
|
inParams.sampleFormat=paFloat32;
|
||||||
|
inParams.suggestedLatency=Pa_GetDeviceInfo(inParams.device)->defaultLowInputLatency;
|
||||||
inParams.device = Pa_GetDefaultInputDevice();
|
inParams.hostApiSpecificStreamInfo=nullptr;
|
||||||
if (inParams.device == paNoDevice) {
|
outParams.device=Pa_GetDefaultOutputDevice();
|
||||||
std::cerr << CLR_RED "[sound] Нет устройства ввода.\n" CLR_RESET;
|
if(outParams.device==paNoDevice){Pa_Terminate();return;}
|
||||||
Pa_Terminate();
|
outParams.channelCount=2;
|
||||||
return;
|
outParams.sampleFormat=paFloat32;
|
||||||
}
|
outParams.suggestedLatency=Pa_GetDeviceInfo(outParams.device)->defaultLowOutputLatency;
|
||||||
inParams.channelCount = 1;
|
outParams.hostApiSpecificStreamInfo=nullptr;
|
||||||
inParams.sampleFormat = paFloat32;
|
PaStream* stream=nullptr;
|
||||||
inParams.suggestedLatency = Pa_GetDeviceInfo(inParams.device)->defaultLowInputLatency;
|
err=Pa_OpenStream(&stream,&inParams,&outParams,SAMPLE_RATE,256,paNoFlag,audioCallback,nullptr);
|
||||||
inParams.hostApiSpecificStreamInfo = nullptr;
|
if(err!=paNoError){Pa_Terminate();return;}
|
||||||
|
err=Pa_StartStream(stream);
|
||||||
outParams.device = Pa_GetDefaultOutputDevice();
|
if(err!=paNoError){Pa_CloseStream(stream);Pa_Terminate();return;}
|
||||||
if (outParams.device == paNoDevice) {
|
Pa_Sleep(CAPTURE_SECONDS*1000);
|
||||||
std::cerr << CLR_RED "[sound] Нет устройства вывода.\n" CLR_RESET;
|
|
||||||
Pa_Terminate();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
outParams.channelCount = 2;
|
|
||||||
outParams.sampleFormat = paFloat32;
|
|
||||||
outParams.suggestedLatency = Pa_GetDeviceInfo(outParams.device)->defaultLowOutputLatency;
|
|
||||||
outParams.hostApiSpecificStreamInfo = nullptr;
|
|
||||||
|
|
||||||
PaStream *stream = nullptr;
|
|
||||||
|
|
||||||
err = Pa_OpenStream(&stream,
|
|
||||||
&inParams,
|
|
||||||
&outParams,
|
|
||||||
SAMPLE_RATE,
|
|
||||||
256,
|
|
||||||
paNoFlag,
|
|
||||||
audioCallback,
|
|
||||||
nullptr);
|
|
||||||
if (err != paNoError) {
|
|
||||||
std::cerr << CLR_RED "[sound] Pa_OpenStream error: " << Pa_GetErrorText(err) << CLR_RESET "\n";
|
|
||||||
Pa_Terminate();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = Pa_StartStream(stream);
|
|
||||||
if (err != paNoError) {
|
|
||||||
std::cerr << CLR_RED "[sound] Pa_StartStream error: " << Pa_GetErrorText(err) << CLR_RESET "\n";
|
|
||||||
Pa_CloseStream(stream);
|
|
||||||
Pa_Terminate();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << CLR_BLUE "[sound] Старт записи/воспроизведения (3 сек)...\n" CLR_RESET;
|
|
||||||
Pa_Sleep(CAPTURE_SECONDS * 1000);
|
|
||||||
|
|
||||||
Pa_StopStream(stream);
|
Pa_StopStream(stream);
|
||||||
Pa_CloseStream(stream);
|
Pa_CloseStream(stream);
|
||||||
Pa_Terminate();
|
Pa_Terminate();
|
||||||
|
auto received=bfskDemodulate(gInputBuffer);
|
||||||
std::cout << CLR_BLUE "[sound] Остановка аудиопотока...\n" CLR_RESET;
|
if(!received.empty()){
|
||||||
|
if(received.size()>=33 && received[0]=='E'){
|
||||||
auto received = bfskDemodulate(gInputBuffer);
|
|
||||||
if (!received.empty()) {
|
|
||||||
if (received.size() >= 33 && received[0] == 'E') {
|
|
||||||
uint8_t otherPub[32];
|
uint8_t otherPub[32];
|
||||||
std::memcpy(otherPub, received.data() + 1, 32);
|
for(int i=0;i<32;i++){
|
||||||
|
otherPub[i]=received[1+i];
|
||||||
x25519ComputeShared(config, otherPub);
|
}
|
||||||
std::cout << CLR_GREEN "[x25519] Общий сеансовый ключ вычислен!\n" CLR_RESET;
|
x25519ComputeShared(config,otherPub);
|
||||||
} else {
|
|
||||||
std::cout << CLR_YELLOW "[sound] Получены " << received.size()
|
|
||||||
<< " байт, но не формат 'E' + 32 байта.\n" CLR_RESET;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
std::cout << CLR_YELLOW "[sound] Ничего не демодулировано.\n" CLR_RESET;
|
|
||||||
}
|
}
|
||||||
|
gSoundActive=false;
|
||||||
gSoundActive = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundFind(AppConfig &config) {
|
void soundFind(AppConfig &config){
|
||||||
if (config.soundExchangeActive) {
|
if(config.soundExchangeActive)return;
|
||||||
std::cout << CLR_YELLOW "[sound] Уже идёт процесс.\n" CLR_RESET;
|
config.soundExchangeActive=true;
|
||||||
return;
|
gSoundActive=true;
|
||||||
}
|
|
||||||
config.soundExchangeActive = true;
|
|
||||||
gSoundActive = true;
|
|
||||||
|
|
||||||
x25519GenerateEphemeral(config);
|
x25519GenerateEphemeral(config);
|
||||||
|
std::vector<uint8_t> packet;packet.push_back('E');
|
||||||
std::vector<unsigned char> packet;
|
packet.insert(packet.end(),config.ephemeralPub,config.ephemeralPub+32);
|
||||||
packet.push_back('E');
|
gOutputBuffer=bfskModulate(packet);
|
||||||
packet.insert(packet.end(), config.ephemeralPub, config.ephemeralPub + 32);
|
gReadPos=0;
|
||||||
|
|
||||||
gOutputBuffer = bfskModulate(packet);
|
|
||||||
gReadPos = 0;
|
|
||||||
|
|
||||||
gInputBuffer.clear();
|
gInputBuffer.clear();
|
||||||
gInputBuffer.resize(SAMPLE_RATE * CAPTURE_SECONDS, 0.0f);
|
gInputBuffer.resize(SAMPLE_RATE*CAPTURE_SECONDS,0.0f);
|
||||||
gWritePos = 0;
|
gWritePos=0;
|
||||||
|
gSoundThread=std::thread(soundThreadFunc,config);
|
||||||
gSoundThread = std::thread(soundThreadFunc, config);
|
|
||||||
|
|
||||||
std::cout << CLR_GREEN "[sound] Отправляем свой публичный ключ X25519 и слушаем!\n" CLR_RESET;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundLose(AppConfig &config) {
|
void soundLose(AppConfig &config){
|
||||||
if (!config.soundExchangeActive) {
|
if(!config.soundExchangeActive)return;
|
||||||
std::cout << CLR_YELLOW "[sound] Процесс не активен.\n" CLR_RESET;
|
config.soundExchangeActive=false;
|
||||||
return;
|
if(gSoundActive)gSoundActive=false;
|
||||||
}
|
if(gSoundThread.joinable())gSoundThread.join();
|
||||||
config.soundExchangeActive = false;
|
|
||||||
|
|
||||||
if (gSoundActive) {
|
|
||||||
gSoundActive = false;
|
|
||||||
}
|
|
||||||
if (gSoundThread.joinable()) {
|
|
||||||
gSoundThread.join();
|
|
||||||
}
|
|
||||||
std::cout << CLR_GREEN "[sound] Процесс остановлен.\n" CLR_RESET;
|
|
||||||
}
|
}
|
||||||
|
@ -2,5 +2,4 @@
|
|||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
|
||||||
void soundFind(AppConfig &config);
|
void soundFind(AppConfig &config);
|
||||||
|
|
||||||
void soundLose(AppConfig &config);
|
void soundLose(AppConfig &config);
|
||||||
|
@ -1,66 +1,40 @@
|
|||||||
#include "webserver.hpp"
|
#include "webserver.hpp"
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
#include "libs/httplib.h"
|
#include "libs/httplib.h"
|
||||||
|
|
||||||
static std::atomic<bool> g_serverRunning{false};
|
static std::atomic<bool> g_serverRunning{false};
|
||||||
static std::thread g_serverThread;
|
static std::thread g_serverThread;
|
||||||
|
|
||||||
static void serverThreadFunc() {
|
static void serverThreadFunc(){
|
||||||
httplib::Server svr;
|
httplib::Server svr;
|
||||||
svr.Get("/", [](const httplib::Request&, httplib::Response &res){
|
svr.Get("/",[](const httplib::Request&,httplib::Response &res){
|
||||||
res.set_content("Hello from Cerberus BFSK!", "text/plain");
|
res.set_content("Hello from Cerberus BFSK!","text/plain");
|
||||||
});
|
});
|
||||||
|
if(!svr.listen("0.0.0.0",8080)){}
|
||||||
if (!svr.listen("0.0.0.0", 8080)) {
|
g_serverRunning=false;
|
||||||
std::cerr << CLR_RED "[web] Ошибка listen(8080). Возможно, порт занят.\n" CLR_RESET;
|
|
||||||
}
|
|
||||||
g_serverRunning = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void webServerStart(AppConfig &config) {
|
void webServerStart(AppConfig &config){
|
||||||
if (config.webServerRunning) {
|
if(config.webServerRunning)return;
|
||||||
std::cout << CLR_YELLOW "[web] Сервер уже запущен.\n" CLR_RESET;
|
g_serverRunning=true;
|
||||||
return;
|
g_serverThread=std::thread(serverThreadFunc);
|
||||||
}
|
config.webServerRunning=true;
|
||||||
g_serverRunning = true;
|
|
||||||
g_serverThread = std::thread(serverThreadFunc);
|
|
||||||
|
|
||||||
config.webServerRunning = true;
|
|
||||||
std::cout << CLR_GREEN "[web] Сервер запущен на порту 8080.\n" CLR_RESET;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void webServerConnect(AppConfig &config, const std::string &type, const std::string &ip) {
|
void webServerConnect(AppConfig &config,const std::string &type,const std::string &ip){
|
||||||
if (!config.webServerRunning) {
|
if(!config.webServerRunning)return;
|
||||||
std::cout << CLR_YELLOW "[web] Сначала запустите сервер (web start)\n" CLR_RESET;
|
httplib::Client cli(ip.c_str(),8080);
|
||||||
return;
|
if(auto res=cli.Get("/")){
|
||||||
}
|
if(res->status==200){}
|
||||||
httplib::Client cli(ip.c_str(), 8080);
|
|
||||||
if (auto res = cli.Get("/")) {
|
|
||||||
if (res->status == 200) {
|
|
||||||
std::cout << CLR_CYAN "[web] Ответ от " << ip << ": " << res->body << CLR_RESET "\n";
|
|
||||||
} else {
|
|
||||||
std::cout << CLR_YELLOW "[web] Подключились, статус: " << res->status << CLR_RESET "\n";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std::cout << CLR_RED "[web] Не удалось подключиться к " << ip << ":8080.\n" CLR_RESET;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void webServerStop(AppConfig &config) {
|
void webServerStop(AppConfig &config){
|
||||||
if (!config.webServerRunning) {
|
if(!config.webServerRunning)return;
|
||||||
std::cout << CLR_YELLOW "[web] Сервер не запущен.\n" CLR_RESET;
|
if(g_serverThread.joinable())g_serverThread.detach();
|
||||||
return;
|
g_serverRunning=false;
|
||||||
}
|
config.webServerRunning=false;
|
||||||
g_serverRunning = false;
|
|
||||||
if (g_serverThread.joinable()) {
|
|
||||||
g_serverThread.detach();
|
|
||||||
}
|
|
||||||
|
|
||||||
config.webServerRunning = false;
|
|
||||||
std::cout << CLR_GREEN "[web] Сервер остановлен (демо).\n" CLR_RESET;
|
|
||||||
}
|
}
|
||||||
|
@ -3,5 +3,5 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
void webServerStart(AppConfig &config);
|
void webServerStart(AppConfig &config);
|
||||||
void webServerConnect(AppConfig &config, const std::string &type, const std::string &ip);
|
void webServerConnect(AppConfig &config,const std::string &type,const std::string &ip);
|
||||||
void webServerStop(AppConfig &config);
|
void webServerStop(AppConfig &config);
|
||||||
|
BIN
webserver.o
BIN
webserver.o
Binary file not shown.
@ -1,38 +1,25 @@
|
|||||||
#include "x25519_handshake.hpp"
|
#include "x25519_handshake.hpp"
|
||||||
#include "config.hpp"
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
#include <cstring> // Для std::memcpy и std::memset
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
// Подключаем Monocypher
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "monocypher.h"
|
#include "monocypher.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
void x25519GenerateEphemeral(AppConfig &config) {
|
void x25519GenerateEphemeral(AppConfig &config){
|
||||||
FILE* f = fopen("/dev/urandom", "rb");
|
FILE* f=fopen("/dev/urandom","rb");
|
||||||
if (!f) {
|
if(!f)return;
|
||||||
std::cerr << CLR_RED "[x25519] Не удалось открыть /dev/urandom\n" CLR_RESET;
|
fread(config.ephemeralSec,1,32,f);
|
||||||
return;
|
|
||||||
}
|
|
||||||
size_t read = fread(config.ephemeralSec, 1, 32, f);
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
if (read != 32) {
|
crypto_x25519_public_key(config.ephemeralPub,config.ephemeralSec);
|
||||||
std::cerr << CLR_RED "[x25519] Не удалось прочитать 32 байта из /dev/urandom\n" CLR_RESET;
|
std::memset(config.sharedSecret,0,32);
|
||||||
return;
|
config.haveSharedSecret=false;
|
||||||
}
|
|
||||||
|
|
||||||
crypto_x25519_public_key(config.ephemeralPub, config.ephemeralSec);
|
|
||||||
|
|
||||||
std::memset(config.sharedSecret, 0, 32);
|
|
||||||
config.haveSharedSecret = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void x25519ComputeShared(AppConfig &config, const uint8_t otherPub[32]) {
|
void x25519ComputeShared(AppConfig &config,const uint8_t otherPub[32]){
|
||||||
uint8_t shared[32];
|
uint8_t shared[32];
|
||||||
crypto_x25519(shared, config.ephemeralSec, otherPub);
|
crypto_x25519(shared,config.ephemeralSec,otherPub);
|
||||||
std::memcpy(config.sharedSecret, shared, 32);
|
std::memcpy(config.sharedSecret,shared,32);
|
||||||
|
config.haveSharedSecret=true;
|
||||||
config.haveSharedSecret = true;
|
std::cout<<CLR_GREEN<<"[x25519] key computed!\n"<<CLR_RESET;
|
||||||
std::cout << CLR_GREEN "[x25519] Общий сеансовый ключ вычислен!\n" CLR_RESET;
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
|
||||||
void x25519GenerateEphemeral(AppConfig &config);
|
void x25519GenerateEphemeral(AppConfig &config);
|
||||||
|
void x25519ComputeShared(AppConfig &config,const uint8_t otherPub[32]);
|
||||||
void x25519ComputeShared(AppConfig &config, const uint8_t otherPub[32]);
|
|
||||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user