Browse Source

Fix segfault in KeyA encryption demo and improve robustness

- Corrected file mismatch: write/read now consistently use `lic.enc`
  (was writing lic.enc but reading hashes.enc → caused empty read + crash).
- Added bounds checks in `extract_size()` to prevent out-of-bounds access
  when encrypted data is too short.
- Standardized size header encoding/decoding to little-endian for consistency.
- Fixed shadowing of `decrypted_hashes` inside try-block.
- Added braces in `read_hashes_from_memory` to avoid always-pushing empty lines.
- Construct decrypted string using explicit size to handle embedded NULs safely.
- Added error handling for failed file I/O (read/write).
- Improved logging to show clear error causes.
- General defensive programming to prevent future segmentation faults.
master
mht 1 month ago
parent
commit
29c49461a9
  1. 134
      Ne-code.cpp

134
Ne-code.cpp

@ -1,5 +1,6 @@
//
// Created by mht on 20.04.25.
// Revised by assistant to fix segfaults and robustness issues
// Created from original code: mht 20.04.25
//
#include <fstream>
#include <vector>
@ -11,27 +12,37 @@
using namespace std;
// Helper to pad data to 16 bytes
// Helper to pad data to 16 bytes (only if needed)
void pad_data(vector<unsigned char>& data)
{
size_t pad_len = 16 - (data.size() % 16);
if (pad_len < 16) {
data.insert(data.end(), pad_len, 0); // simple zero padding
size_t rem = data.size() % 16;
if (rem != 0) {
size_t pad_len = 16 - rem;
data.insert(data.end(), pad_len, 0); // zero padding
}
}
// Read file into vector
// Read file into vector (with simple error handling)
vector<unsigned char> read_file(const string& filename)
{
ifstream file(filename, ios::binary);
if (!file) {
cerr << "Failed to open file for reading: " << filename << endl;
return {};
}
return vector<unsigned char>((istreambuf_iterator<char>(file)), istreambuf_iterator<char>());
}
// Write vector into file
void write_file(const string& filename, const vector<unsigned char>& data)
// Write vector into file (with simple error handling)
bool write_file(const string& filename, const vector<unsigned char>& data)
{
ofstream file(filename, ios::binary);
if (!file) {
cerr << "Failed to open file for writing: " << filename << endl;
return false;
}
file.write(reinterpret_cast<const char*>(data.data()), data.size());
return true;
}
// Encrypt buffer using KeyA
@ -90,46 +101,63 @@ int decrypt_buffer(vector<unsigned char>& data, unsigned char* kp, unsigned char
return 0;
}
// Save size as first 8 bytes (uint64_t) of encrypted file
// Save size as first 8 bytes (uint64_t) of encrypted file -- little endian
void prepend_size(vector<unsigned char>& data, uint64_t size)
{
vector<unsigned char> result(8);
for (int i = 0; i < 8; ++i) {
result[i] = (size >> (i * 8)) & 0xFF;
result[i] = static_cast<unsigned char>((size >> (i * 8)) & 0xFF);
}
result.insert(result.end(), data.begin(), data.end());
data = result;
data.swap(result);
}
// Extract original size from first 8 bytes
uint64_t extract_size(vector<unsigned char>& data)
// Extract original size from first 8 bytes (little endian) and remove header.
// Returns pair(success, size). On failure (not enough bytes) returns {false,0}.
pair<bool,uint64_t> extract_size(vector<unsigned char>& data)
{
if (data.size() < 8) {
cerr << "Encrypted data too short to contain size header (need 8 bytes)." << endl;
return {false, 0};
}
uint64_t size = 0;
for (int i = 7; i >= 0; --i) {
size = (size << 8) | data[i];
// reconstruct little-endian
for (int i = 0; i < 8; ++i) {
size |= (static_cast<uint64_t>(data[i]) << (i * 8));
}
// remove header
data.erase(data.begin(), data.begin() + 8);
return size;
return {true, size};
}
// Save list of hashes into a text file
void save_hashes_to_file(const vector<string>& hashes, const string& filename)
{
ofstream file(filename);
if (!file) {
cerr << "Failed to open " << filename << " for writing." << endl;
return;
}
for (const auto& hash : hashes) {
file << hash << "\n";
}
}
// Read hashes from decrypted data
// Read hashes from decrypted data (handles embedded NULs correctly)
vector<string> read_hashes_from_memory(const vector<unsigned char>& data)
{
cout << "entered read_hashes_from_memory" << endl;
vector<string> hashes;
istringstream iss(string(data.begin(), data.end()));
// construct a string with explicit size to handle binary / NULs
string s(reinterpret_cast<const char*>(data.data()), data.size());
cout << "data size: " << data.size() << endl;
istringstream iss(s);
string line;
while (getline(iss, line)) {
if (!line.empty())
if (!line.empty()) {
cout << "readed hash: " << line << endl;
hashes.push_back(line);
}
}
return hashes;
}
@ -171,20 +199,27 @@ int main()
"0092d1a3a78bab2b85abc55d5a851c3c351d0dacd402d77ad57b6d3f08836262bc7dff8b958368cddedd3aa8246ec4919f77c325210cabeadd2dfde5ce8d0412",
"0485a2fd8aceaddfeb45f4072f64637bec8ab5962e088c4f8f0a46196d6b80c1a2924e1d43fa530b2183e5240507115a3db8d49aae9d100195a6ba1eb8f1adcf",
"ec23e51688c082584821a20038510a818c58a0201dbb7ee133d0b11dfc6456a2ad1de4dd944e8083e378af4e58362b5c3ecf3f242493e0cfc1c1cde58e7fc8f1"
};
save_hashes_to_file(hashes, "hashes.txt");
cout << "Hashes saved to 'hashes.txt'." << endl;
// Step 2: Encrypt the hashes file
vector<unsigned char> hash_data = read_file("hashes.txt");
if (hash_data.empty()) {
cerr << "hashes.txt is empty or could not be read. Aborting encryption." << endl;
return 1;
}
uint64_t original_size = hash_data.size(); // Save original size
pad_data(hash_data); // pad to multiple of 16
if (encrypt_buffer(hash_data, kp, kr, kw) == 0) {
prepend_size(hash_data, original_size); // Put size in front
write_file("lic.enc", hash_data);
if (!write_file("lic.enc", hash_data)) {
cerr << "Failed to write lic.enc" << endl;
return 1;
}
cout << "Encryption successful. Encrypted file saved as 'lic.enc'." << endl;
} else {
cout << "Encryption failed." << endl;
@ -192,24 +227,55 @@ int main()
}
// Step 3: Later... Decrypt and check for input hash
vector<unsigned char> enc_data = read_file("hashes.enc");
uint64_t saved_size = extract_size(enc_data);
// NOTE: read the correct file 'lic.enc' (was 'hashes.enc' in original -> bug)
vector<unsigned char> enc_data = read_file("lic.enc");
if (enc_data.empty()) {
cerr << "Failed to read 'lic.enc' or file empty." << endl;
return 1;
}
cout << "read 'lic.enc' successful" << endl;
if (decrypt_buffer(enc_data, kp, kr, kw) == 0) {
enc_data.resize(saved_size); // trim padding
vector<string> decrypted_hashes = read_hashes_from_memory(enc_data);
// extract original size
auto [ok, saved_size] = extract_size(enc_data);
if (!ok) {
cerr << "Failed to extract size header from encrypted file." << endl;
return 1;
}
vector<string> decrypted_hashes; // will be filled below
string input_hash;
cout << "Enter a hash to search for: ";
cin >> input_hash;
try {
if (decrypt_buffer(enc_data, kp, kr, kw) == 0) {
if (saved_size > enc_data.size()) {
cerr << "Saved original_size is larger than decrypted data. Adjusting to available size." << endl;
saved_size = enc_data.size();
}
enc_data.resize(saved_size); // trim padding
try {
// fill the outer decrypted_hashes (do NOT shadow)
decrypted_hashes = read_hashes_from_memory(enc_data);
cout << "decryption of 'lic.enc' successful" << endl;
}
catch (exception &e) {
cout << "Parsing decrypted payload failed: " << e.what() << endl;
return 1;
}
if (hash_exists(input_hash, decrypted_hashes)) {
cout << "Hash FOUND in list." << endl;
string input_hash;
cout << "Enter a hash to search for: ";
cin >> input_hash;
if (hash_exists(input_hash, decrypted_hashes)) {
cout << "Hash FOUND in list." << endl;
} else {
cout << "Hash NOT FOUND." << endl;
}
} else {
cout << "Hash NOT FOUND." << endl;
cout << "Decryption failed." << endl;
return 1;
}
} else {
cout << "Decryption failed." << endl;
} catch (exception &e) {
cout << "Failed to decrypt buffer: " << e.what() << endl;
return 1;
}

Loading…
Cancel
Save