Initial commit
This commit is contained in:
28
client/Makefile
Normal file
28
client/Makefile
Normal file
@ -0,0 +1,28 @@
|
||||
# pq-ftp/client/Makefile
|
||||
CXX=g++
|
||||
CXXFLAGS=-std=c++17 -Wall
|
||||
# You must have liboqs installed locally for this to work
|
||||
# sudo ninja install from the liboqs build directory
|
||||
LDFLAGS=-loqs -lz -lcrypto
|
||||
|
||||
SRC_DIR=src
|
||||
BUILD_DIR=build
|
||||
BIN_DIR=bin
|
||||
TARGET=$(BIN_DIR)/client
|
||||
|
||||
SRCS=$(wildcard $(SRC_DIR)/*.cpp)
|
||||
OBJS=$(patsubst $(SRC_DIR)/%.cpp, $(BUILD_DIR)/%.o, $(SRCS))
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
@mkdir -p $(BIN_DIR)
|
||||
$(CXX) $(OBJS) -o $(TARGET) $(LDFLAGS)
|
||||
@echo "Client compiled successfully!"
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
|
||||
@mkdir -p $(BUILD_DIR)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR) $(BIN_DIR)
|
BIN
client/bin/client
Executable file
BIN
client/bin/client
Executable file
Binary file not shown.
BIN
client/build/client.o
Normal file
BIN
client/build/client.o
Normal file
Binary file not shown.
1
client/liboqs
Submodule
1
client/liboqs
Submodule
Submodule client/liboqs added at 94b421ebb8
170
client/src/client.cpp
Normal file
170
client/src/client.cpp
Normal file
@ -0,0 +1,170 @@
|
||||
// pq-ftp/client/src/client.cpp
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include <oqs/oqs.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#define SERVER_IP "127.0.0.1"
|
||||
#define PORT 2121
|
||||
#define BUFFER_SIZE 4096
|
||||
#define PQC_ALGORITHM "Kyber768"
|
||||
|
||||
// Data compression function
|
||||
std::vector<uint8_t> compress_data(const std::vector<uint8_t>& data) {
|
||||
if (data.empty()) return {};
|
||||
|
||||
uLongf compressed_size = compressBound(data.size());
|
||||
std::vector<uint8_t> compressed_data(compressed_size);
|
||||
|
||||
if (compress(compressed_data.data(), &compressed_size, data.data(), data.size()) != Z_OK) {
|
||||
std::cerr << "Compression failed!" << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
compressed_data.resize(compressed_size);
|
||||
return compressed_data;
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
int sock = 0;
|
||||
struct sockaddr_in serv_addr;
|
||||
|
||||
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
std::cerr << "Socket creation error" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_port = htons(PORT);
|
||||
|
||||
if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {
|
||||
std::cerr << "Invalid address/ Address not supported" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
|
||||
std::cerr << "Connection Failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "Connected to server. Performing PQC key exchange..." << std::endl;
|
||||
|
||||
// 1. PQC Key Exchange
|
||||
OQS_KEM *kem = NULL;
|
||||
uint8_t *public_key = NULL;
|
||||
uint8_t *ciphertext = NULL;
|
||||
uint8_t *shared_secret_client = NULL;
|
||||
|
||||
kem = OQS_KEM_new(PQC_ALGORITHM);
|
||||
if (kem == NULL) {
|
||||
std::cerr << "Error: OQS_KEM_new failed." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public_key = new uint8_t[kem->length_public_key];
|
||||
ciphertext = new uint8_t[kem->length_ciphertext];
|
||||
shared_secret_client = new uint8_t[kem->length_shared_secret];
|
||||
|
||||
// Receive public key from server
|
||||
recv(sock, public_key, kem->length_public_key, 0);
|
||||
|
||||
// Encapsulate to generate ciphertext and our shared secret
|
||||
if (OQS_KEM_encaps(kem, ciphertext, shared_secret_client, public_key) != OQS_SUCCESS) {
|
||||
std::cerr << "Error: OQS_KEM_encaps failed." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Send ciphertext to server
|
||||
send(sock, ciphertext, kem->length_ciphertext, 0);
|
||||
|
||||
std::cout << "PQC key exchange successful." << std::endl;
|
||||
// NOTE: The shared_secret_client should be identical to the server's.
|
||||
|
||||
// 2. Authentication
|
||||
std::cout << "Authenticating..." << std::endl;
|
||||
std::string user = "user";
|
||||
std::string pass = "pass";
|
||||
send(sock, user.c_str(), user.length() + 1, 0);
|
||||
send(sock, pass.c_str(), pass.length() + 1, 0);
|
||||
|
||||
char auth_status[10] = {0};
|
||||
recv(sock, auth_status, sizeof(auth_status), 0);
|
||||
if (std::string(auth_status) != "OK") {
|
||||
std::cerr << "Authentication failed. Server responded: " << auth_status << std::endl;
|
||||
return -1;
|
||||
}
|
||||
std::cout << "Authentication successful!" << std::endl;
|
||||
std::cout << "Commands: put <filepath>, get <filename>, exit" << std::endl;
|
||||
|
||||
// 3. Command Loop
|
||||
for (std::string line; std::cout << "> " && std::getline(std::cin, line);) {
|
||||
if (line.empty()) continue;
|
||||
if (line == "exit") break;
|
||||
|
||||
std::stringstream ss(line);
|
||||
std::string command, filepath;
|
||||
ss >> command >> filepath;
|
||||
|
||||
if (command == "put") {
|
||||
std::ifstream file(filepath, std::ios::binary | std::ios::ate);
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "Error: Could not open file " << filepath << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get file size
|
||||
std::streamsize size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
// Read file into a vector
|
||||
std::vector<char> buffer(size);
|
||||
if (!file.read(buffer.data(), size)) {
|
||||
std::cerr << "Error reading file." << std::endl;
|
||||
continue;
|
||||
}
|
||||
file.close();
|
||||
|
||||
// Convert char vector to uint8_t vector for compression
|
||||
std::vector<uint8_t> data(buffer.begin(), buffer.end());
|
||||
|
||||
// Compress the data
|
||||
std::vector<uint8_t> compressed_data = compress_data(data);
|
||||
std::cout << "Original size: " << data.size() << " bytes, Compressed size: " << compressed_data.size() << " bytes." << std::endl;
|
||||
|
||||
// Send command and filename
|
||||
std::string put_command = "put " + filepath.substr(filepath.find_last_of("/\\") + 1);
|
||||
send(sock, put_command.c_str(), put_command.length() + 1, 0);
|
||||
|
||||
// Send file size
|
||||
uint64_t compressed_size = compressed_data.size();
|
||||
send(sock, &compressed_size, sizeof(compressed_size), 0);
|
||||
|
||||
// Send file data
|
||||
send(sock, compressed_data.data(), compressed_data.size(), 0);
|
||||
|
||||
std::cout << "File uploaded successfully." << std::endl;
|
||||
|
||||
} else if (command == "get") {
|
||||
std::cout << "GET command is not implemented in this example." << std::endl;
|
||||
} else {
|
||||
std::cout << "Unknown command: " << command << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
OQS_KEM_free(kem);
|
||||
delete[] public_key;
|
||||
delete[] ciphertext;
|
||||
delete[] shared_secret_client;
|
||||
close(sock);
|
||||
|
||||
return 0;
|
||||
}
|
1
client/testfile.txt
Normal file
1
client/testfile.txt
Normal file
@ -0,0 +1 @@
|
||||
This is a post-quantum test file. This is a post-quantum test file.
|
Reference in New Issue
Block a user