Weird characters appear at the end of file when encrypting it - c++

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);

Related

How to read any kind of files as binary and edit it as you want (like compress it) with c++?

I'm trying to figure out a way to manipulate the binary code of any file in the computer in goal to apply a compress/decompress algorithm in c++ .
I have been searching about that for long time and all i found was how to read a .bin file :
#include <iostream>
#include <fstream>
using namespace std;
int main (){
streampos size;
char * memblock;
ifstream file ("name.bin", ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = file.tellg();
memblock = new char[size];
file.seekg (0, ios::beg);
file.read (memblock, size);
for(int i = 0 ; i < size ; i++){
cout << memblock[i] ;
}
file.close();
cout << "\n\n the entire file content is in memory";
delete[] memblock;
}
else cout << "Unable to open file";
return 0;
}
I just wanna those bytes without ASCII translation, other words i wanna all the file as binary not what is inside it
<< is overloaded for char types to output the ASCII formated character. The data (the ones and zeros) in your memblock array are accurately read in as binary. It's just the way you're displaying them that is ASCII. Instead of a char[] for memblock, make it a uint8_t[]. Then, when you output, do
std::cout << std::hex << std::fill('0') << std::setw(2) << memblock[i];
^ ^ ^
| | |
| | sets the width of the next output
| sets the fill character (default is space)
tells the stream to output all numbers in hexadecimal
You'll have to #include <iomanip> for the stream format manipulators hex, fill, and setw to work.
Note that setw will only be set on the stream for the next output operation, while hex and fill will be set until explicitly set otherwise. That said, you only need to set these two manipulators once, probably outside your loop. Then when you're finished, you can set them back like:
std::cout << std::dec << std::fill(' ');
See https://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt2 for the list of overloaded operator<< functions for char and char arrays.
The answer was simpler than we thought :
include bitset
for(int i = 0 ; i < size ; i++){
//changing the value of "memblock[i]" to binary byte per byte with for loop
//and of course using bitset
bitset<8> test (memblock[i]);
cout << test ;
}

C++ show bitmap in hex

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.

C++ XOR encryption - decryption issue

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?

Reading a single character from a file returns special characters?

Using fstreams I'm attempting to read single characters from a specified location in a file and append them onto a string. For some reason, reading in these characters returns special characters. I've tried numerous things, but the more curious thing that I found while debugging was that changing the initial value of the char temp; will cause the whole string to change to that value.
int Class::numbers(int number, string& buffer) {
char temp;
if (number < 0 || buffer.length() > size) {
exit(0);
}
string fname = name + ".txt";
int start = number * size;
ifstream readin(fname.c_str());
readin.open(fname.c_str(), ios::in)
readin.seekg(start);
for (int i = 0; i < size; ++i) {
readin.get(temp);
buffer += temp;
}
cout << buffer << endl;
readin.close();
return 0;
}
Here is an example screenshot of the special characters being outputted: http://i.imgur.com/6HCI7TT.png
Could the issue be where I'm starting using seekg? It seems to start in the appropriate position. Another thing I've considered is that maybe I'm reading some invalid place into the stream and it's just giving me junk characters from memory.
Any thoughts?
WORKING SOLUTION:
int Class::numbers(int number, string& buffer) {
char temp;
if (number < 0 || buffer.length() > size) {
exit(0);
}
string fname = name + ".txt";
int start = number * size;
ifstream readin(fname.c_str());
readin.open(fname.c_str(), ios::in)
readin.seekg(start);
for (int i = 0; i < size; ++i) {
readin.get(temp);
buffer += temp;
}
cout << buffer << endl;
readin.close();
return 0;
}
Here is the working solution. In my program I had already had this file name open, so opening it twice was likely to cause issues I suppose. I will do some further testing on this in my own time.
For ASCII characters with a numeric value greater than 127, the actual character rendered on screen depends on the code page of the system you are currently using.
What is likely happening is that you are not getting a single "character" as you think you are.
First, to debug this, use your existing code to just open and print out an entire text file. Is your program capable of doing this? If not, it's likely that the "text" file you are opening isn't using ASCII, but possibly UTF or some other form of encoding. That means when you read a "character" (8-bits most likely), you're just reading half of a 16-bit "wide character", and the result is meaningless to you.
For example, the gedit application will automatically render "Hello World" on screen as I'd expect, regardless of character encoding. However, in a hex editor, a UTF8 encoded file looks like:
UTF8 Raw text:
0000000: 4865 6c6c 6f20 776f 726c 642e 0a Hello world..
While UTF16 looks like:
0000000: fffe 4800 6500 6c00 6c00 6f00 2000 7700 ..H.e.l.l.o. .w.
0000010: 6f00 7200 6c00 6400 2e00 0a00 o.r.l.d.....
This is what your program sees. C/C++ expect ASCII encoding by default. If you want to handle other encodings, it's up to your program to accomodate it manually or by using a third-party library.
Also, you aren't testing to see if you've exceeded the length of the file. You could just be grabbing random garbage.
Using a simple text file just containing the string "Hello World", can your program do this:
Code Listing
// read a file into memory
#include <iostream> // std::cout
#include <fstream> // std::ifstream
#include <string.h>
int main () {
std::ifstream is ("test.txt", std::ifstream::binary);
if (is) {
// get length of file:
is.seekg (0, is.end);
int length = is.tellg();
is.seekg (0, is.beg);
// allocate memory:
char * buffer = new char [length];
// read data as a block:
is.read (buffer,length);
// print content:
std::cout.write (buffer,length);
std::cout << std::endl;
// repeat at arbitrary locations:
for (int i = 0; i < length; i++ )
{
memset(buffer, 0x00, length);
is.seekg (i, is.beg);
is.read(buffer, length-i);
// print content:
std::cout.write (buffer,length);
std::cout << std::endl;
}
is.close();
delete[] buffer;
}
return 0;
}
Sample Output
Hello World
Hello World
ello World
llo World
lo World
o World
World
World
orld
rld
ld
d

C++ checksum reading nonexistent newline

I am doing a very basic checksum on files by reading the input file into a character array, and then iterating over that array and adding each character into the checksum. The problem is that when I do this all of my checksums are 10 too high (10 is the ascii decimal value for the newline character).
How is it newline characters are being inserted into my code, when I know for a fact there is no newline character in my text? Even a single line text file gets a newline character added in!
#include <iostream>
#include <fstream>
int main () {
int fileLength = 0;
std::ifstream inputFile;
char charArray[10000];
int checkSumValue = 0;
// open file in binary
inputFile.open("/Path/To/File", std::ios::binary);
// get file length, then return to beginning of file
inputFile.seekg(0, std::ios_base::end);
fileLength = inputFile.tellg();
inputFile.seekg(0, std::ios_base::beg);
// read all data from file into char array
inputFile.read(charArray, fileLength);
// iterate over char array, adding ascii decimal value to checksum
for (int num = 0; num <= fileLength; num++) {
std::cout << "Checksum value before iteration " << num << " is "
<< checkSumValue << std::endl;
checkSumValue += static_cast<int>(charArray[num]);
}
// properly close out the input file
inputFile.close();
inputFile.clear(std::ios_base::goodbit);
std::cout << "The checksum value is: " << checkSumValue << std::endl;
std::cout << "The file length is: " << fileLength << std::endl;
return 0;
}
Your problem is here:
num <= fileLength
It should be:
num < fileLength
For example. If the length is 1. Then the only valid character is charArray[0]
Also note. Doing this:
inputFile.read(charArray, fileLength);
is dangerious as fileLength may be larger than the size of the array.
A better solution would be to use a vector (as it dynamically sizes)
std::vector<char> charArray(fileLength);
inputFile.read(&charArray[0], fileLength);
But do you really need to copy the data into an array? Why not just do the sum on the fly.
size_t checkSumValue = std::accumulate(std::istreambuf_iterator<char>(fileLength),
std::istreambuf_iterator<char>(),
size_t(0)
);
Martin was also correct - you should be (num < fileLength) in all cases.
The other possibility is that you created your file in an editor and it's artificially added a spurious newline for you. That's common. Try dumping your file in a hex editor. I just ran your program (with the <= removed) and it works fine.