I have a file which is read in as binary. It has some basic plain text at the top and image data after. Due to a process I cannot control I need to ensure that a certain string of characters is not present in the plain text representation of the data. Meaning that if you opened the image data as plain text and the character sequence was present that is a problem. My thought was to read in the data, convert to hex, and replace the the instances of that sequence. The process would then be reversed to restore the file.
std::ifstream stream;
std::stringstream ss;
if (stream.bad())
do.something();
length = stream.rdbuf()->pubseekoff(0, std::ios_base::end);
data = new char[length];
stream.rdbuf()->pubseekoff(0, std::ios_base::beg);
stream.read(data, length);
stream.close();
ss << std::hex;
for (int i = 0; i < length; ++i)
ss << std::setw(2) << std::setfill('0') << (int)data[i];
const std::string& tmp = ss.str();
const char* cstr = tmp.c_str();
CString hexStr(cstr);
This reads the top portion of the file fine but introduces 'FF' characters into the rest of the data. My c++ isn't great so I'm looking for some help as to why and how to correctly do this. The rest looks like:
hexStr.Replace(character sequence to replace, replacement);
std::ofstream datafile(pathToFile, std::ios_base::binary | std::ios_base::out);
char buf[3];
buf[2] = 0;
std::stringstream input(hexStr.GetString());
input.flags(std::ios_base::hex);
while (input)
{
input >> buf[0] >> buf[1];
long val = strtol(buf, nullptr, 16);
datafile << static_cast<unsigned char>(val & 0xff);
}
Related
I never thought I would have to turn to SO to solve this.
Alright so for more insight I am making my own encryption program.
I'm not trying to make it good or anything it's just a personal project.
What this program is doing is that it's flipping certain bits in every single byte of the character making it unreadable.
However every time I run the program and decrypt I get weird characters on the output. These characters seem to match the amount of lines as following:
^^ text that I want to encrypt
^^ after encrypting. (a lot of the text got cut off)
^^ after decrypting. there's 10 null character corresponding to the amount of newlines. there also seems to be another weird '�' character. Where are these bytes coming from??
I've tried a lot of stuff. Here is my code if anyone needs it (it's compiled with default flags):
#include <iostream>
#include <fstream>
#include <cstring>
#include <string>
#define ENCRYPTFILE "Encrypted.oskar"
typedef unsigned char BYTE;
char saltFunc(BYTE salt, char chr) {
for(int i = 0; i < 8; i++) {
if((salt >> i) & 1U) {
chr ^= 1UL << i;
}
}
return chr;
}
int main () {
std::ofstream encryptFile(ENCRYPTFILE, std::ifstream::in);
std::ifstream inputFile(ENCRYPTFILE, std::ifstream::in);
unsigned int length;
unsigned int lineLength;
BYTE salt = 0b00000001;
std::string line;
std::cin.unsetf(std::ios::dec);
std::cin.unsetf(std::ios::hex);
std::cin.unsetf(std::ios::oct);
//std::cout << "input salt in hex with a prefix 0x so for example. 0xA2" << std::endl;
//std::cin >> std::hex >> salt;
inputFile.seekg(0, inputFile.end);
length = inputFile.tellg();
inputFile.seekg(0, inputFile.beg);
std::cout << lineLength << std::endl;
char* fileBuffer = new char[length];
char* encryptFileBuffer = new char[length];
memset(fileBuffer, 0, length);
memset(encryptFileBuffer, 0, length);
while (inputFile.good()) { // just get file length in bytes.
static int i = 0;
fileBuffer[i] = inputFile.get();
i++;
}
while (std::getline(inputFile, line))
++lineLength;
inputFile.clear();
encryptFile.clear();
std::cout << "file size: " << length << std::endl;
for(int i = 0; i < length; i++) {
encryptFileBuffer[i] = saltFunc(salt, fileBuffer[i]);
encryptFile << encryptFileBuffer[i];
}
inputFile.close();
encryptFile.close();
delete[] encryptFileBuffer;
delete[] fileBuffer;
return 0;
}
The problem is that you are measuring the length of the file in bytes, which, for text files, is not the same as the length in characters. But you are then reading it as characters, so you end up reading too many characters and then writing extra garbage after then end in the output file.
Since you are getting one extra character per line, it is likely you are running on Windows, where line ending characters are two bytes in the file. That's where the extra incorrect length you are seeing is coming from.
For encryption/decryption what you probably want to do is read and write the file in binary mode, so you are reading and writing bytes not characters. You do this by adding std::ios::binary into the flags when opening the file(s):
std::ofstream encryptFile(ENCRYPTFILE, std::ifstream::in | std::ios::binary);
std::ifstream inputFile(ENCRYPTFILE, std::ifstream::in | std::ios::binary);
I am trying to read a bitmap ("sample.bmp") with fstream in C++. Every char
of the file should be printed as a decimal and hexadecimal number. But the problem is, that at the 60th character or so the decimal numbers become negative. This is the code snippet I use:
//edit: code fixed
void bitmap::printHeader(std::string filename){
std::ifstream bmpFile;
std::vector<char> line;
util func;
bmpFile.open(filename, std::ios::binary | std::ios::in);
bmpFile.seekg(0, std::ios::end);
std::streampos length = bmpFile.tellg();
bmpFile.seekg(0, std::ios::beg);
line.resize(length);
bmpFile.read(&line[0], length);
for (int i = 0; i < line.size(); i++){
std::cout << (int)(UINT8)line[i] << std::endl;
func.dec2hex((int)(UINT8)line[i]);
}
bmpFile.close();
}
The first 60 characters are converted right. After that I get numbers from 0 to -255 which are not representing the right chararcter.
I followed a tutorial on stephan-brumme website for XOR encryption (unfortunately I cannot include URL because I do not have enough reputation). What I want to do is following: read the content of example.txt file and decrypt the text that it includes. For example, this is the content of example.txt:
\xe7\xfb\xe0\xe0\xe7
This, when decrypted using password "password" should return "hello". This is the code I got:
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
std::string decode(const std::string& input)
{
const size_t passwordLength = 9;
static const char password[passwordLength] = "password";
std::string result = input;
for (size_t i = 0; i < input.length(); i++)
result[i] ^= ~password[i % passwordLength];
return result;
}
int main(int argc, char* argv[])
{
string line;
ifstream myfile ("example.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
cout << decode(line);
}
myfile.close();
}
return 0;
}
And this is the result of running the application:
click for image
As you can see, the decryption was not successful. Now, if I make it so it doesn't read the .txt, but directly decrypts the text, like this:
cout << decode("\xe7\xfb\xe0\xe0\xe7");
It works perfectly:
click for image
What am I doing wrong here?
Many thanks in advance! :)
Character XOR by same character is zero, so the result may include zero. std::string doesn't like that because zero terminates the string.
You also can use std::vector<char> instead of std::string for the actual encoding/decoding. You would have to change the decode function to handle vector<char>
And read/write the file in binary.
Edit: Using std::string only, and std::string decode(const std::string& input)
int main()
{
std::string line = "hello";
{
line = decode(line);
std::ofstream myfile("example.txt", std::ios::binary);
myfile.write(line.data(), line.size());
//Edit 2 *************
//std::cout << std::hex;
//for (char c : line)
// std::cout << "\\x" << (0xff & c);
//*************
//This will make sure width is always 2
//For example, it will print "\x01\x02" instead of "\x1\x2"
std::cout << std::hex << std::setfill('0');
for (char c : line)
std::cout << "\\x" << std::setw(2) << (0xff & c);
std::cout << std::endl;
}
{
std::ifstream myfile("example.txt", std::ios::binary | std::ios::ate);
int filesize = (int)myfile.tellg();
line.resize(filesize);
myfile.seekg(0);
myfile.read(&line[0], filesize);
line = decode(line);
std::cout << line << std::endl;
}
return 0;
}
I bet example.txt contains the characters '\', 'x', 'e', '7' etc. You have to read those, process all the backslash escapes, and then feed it to decode.
\xe7 is a common way of representing a single character with hex value E7. (Which is quite likely to be the single character 'ç' depending on your character set). If you want to store (encrypted) readable text, I suggest dropping the \x, and having the file contain lines like "e7fbe0e0e7". Then
- read each line into a string.
- Convert each pair of characters from a hex number into an integer, and store the result in a char.
- Store that char in the string.
- Then xor decrypt the string.
Alternatively, ensure the file contains the actual binary characters you need it to.
Also beware that you are XOR-ing with the terminating nul byte of the password. Did you mean to do that?
I am currently working my way through teaching myself how to work with files in c++, and I am having a good bit of difficulty extracting binary information from files.
My code:
std::string targetFile = "simplehashingfile.txt";
const char* filename = targetFile.c_str();
std::ifstream file;
file.open( filename, std::ios::binary | std::ios::in );
file.seekg(0, std::ios::end); // go to end of file
std::streamsize size = file.tellg(); // get size of file
std::vector<char> buffer(size); // create vector of file size bytes
file.read(buffer.data(), size); // read file into buffer vector
int totalread = file.gcount();
// Check that data was read
std::cout<<"total read: " << totalread << std::endl;
// check buffer:
std::cout<<"from buffer vector: "<<std::endl;
for (int i=0; i<size; i++){
std::cout << buffer[i] << std::endl;
}
std::cout<<"\n\n";
The "simplehashingfile.txt" file only contains 50 bytes of normal text. The size is correctly determined to be 50 bytes, but gcount returns 0 chars read, and the buffer output is (understandably from the gcount) a 50 line list of nothing.
For the life of me I cannot figure out where I went wrong! I made this test code earlier:
// Writing binary to file
std::ofstream ofile;
ofile.open("testbinary", std::ios::out | std::ios::binary);
uint32_t bytes4 = 0x7FFFFFFF; // max 32-bit value
uint32_t bytes8 = 0x12345678; // some 32-bit value
ofile.write( (char*)&bytes4 , 4 );
ofile.write( (char*)&bytes8, 4 );
ofile.close();
// Reading from file
std::ifstream ifile;
ifile.open("testbinary", std::ios::out | std::ios::binary);
uint32_t reading; // variable to read data
uint32_t reading2;
ifile.read( (char*)&reading, 4 );
ifile.read( (char*)&reading2, 4 );
std::cout << "The file contains: " << std::hex << reading << std::endl;
std::cout<<"next 4 bytes: "<< std::hex << reading2 << std::endl;
And that test code wrote and read perfectly. Any idea what I am doing wrong? Thank you to anyone who can point me in the right direction!
You never reset the file back to the beginning when you read from it
std::streamsize size = file.tellg(); //<- goes to the end of the file
std::vector<char> buffer(size); // create vector of file size bytes
file.read(buffer.data(), size); //<- now we read from the end of the file which will read nothing
int totalread = file.gcount();
You need to call seekg() again and reset the file pointer back to the beginning. To do that use
fille.seekg(0, std::ios::beg);
before
file.read(buffer.data(), size);
It would be worth to return to the begin of the file, before trying to read:
file.seekg(0, std::ios::beg)
I think the problem is that you do a seek to the end to get the file size, but don't seek back to the beginning before trying to read the file.
I have a program that reads the hex of a file, modifies it, and stores the modified hex in a std::string.
For example, how would I write this to a file
std::string wut="b6306edf953a6ac8d17d70bda3e93f2a3816eac333d1ac78";
and get its value
.0n..:j..}p...?*8...3..x
in the outputted file?
I'd prefer not to use sprintf, but I guess if it's necessary, I'll do what I must.
If I understand your question correctly you want the text converted to it's numeric equivalent and then written to file. Given the hint you provided in your question it looks like this should be done byte by byte. Below is one way to achieve this. Note the need to convert each byte from a string to an integer value.
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <ios>
std::string wut = "b6306edf953a6ac8d17d70bda3e93f2a3816eac333d1ac78";
int main()
{
std::ofstream datafile("c:\\temp\\temp1.dat", std::ios_base::binary | std::ios_base::out);
char buf[3];
buf[2] = 0;
std::stringstream input(wut);
input.flags(std::ios_base::hex);
while (input)
{
input >> buf[0] >> buf[1];
long val = strtol(buf, nullptr, 16);
datafile << static_cast<unsigned char>(val & 0xff);
}
}
The answer of #Peter R will lead to an output which is not 100% equal, due to the stringstream interpreting more than one '0's in a row in an unintended way.
Example: If we want to write the hex value "00000000", the stringstream would output " 000000".
The solution below works in every case, no matter how many zeros are contained in the hex string:
// Input
std::string hex = "180f00005e2c3415"; // (or longer)
std::basic_string<uint8_t> bytes;
// Iterate over every pair of hex values in the input string (e.g. "18", "0f", ...)
for (size_t i = 0; i < hex.length(); i += 2)
{
uint16_t byte;
// Get current pair and store in nextbyte
std::string nextbyte = hex.substr(i, 2);
// Put the pair into an istringstream and stream it through std::hex for
// conversion into an integer value.
// This will calculate the byte value of your string-represented hex value.
std::istringstream(nextbyte) >> std::hex >> byte;
// As the stream above does not work with uint8 directly,
// we have to cast it now.
// As every pair can have a maximum value of "ff",
// which is "11111111" (8 bits), we will not lose any information during this cast.
// This line adds the current byte value to our final byte "array".
bytes.push_back(static_cast<uint8_t>(byte));
}
// we are now generating a string obj from our bytes-"array"
// this string object contains the non-human-readable binary byte values
// therefore, simply reading it would yield a String like ".0n..:j..}p...?*8...3..x"
// however, this is very useful to output it directly into a binary file like shown below
std::string result(begin(bytes), end(bytes));
Then you can simply write this string to a file like this:
std::ofstream output_file("filename", std::ios::binary | std::ios::out);
if (output_file.is_open())
{
output_file << result;
output_file.close();
}
else
{
std::cout << "Error could not create file." << std::endl;
}