After reading several white papers on cryptography and runtime PE crypters, I decided to write my own. It's very simple and only for educational purposes.
Here is the GitHub repo: https://github.com/Jyang772/XOR_Crypter
I have two questions.
First, why do I have to keep changing my file permissions to start
every outputted .exe (File created by Builder.exe not the compiler)? It creates a file that is Shared. I have to right click it and select share with Nobody. Does this have something to do with the File Access and Security Rights? I am using CreateFile() and Readfile to read and write the input and output files.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
Second, I can't seem to get XOR encryption to work. It seems pretty
straight forward for what I have done. The byte sizes are the same. While I was investigating, I had the Builder and the Stub each output a file with the file data unencrypted. They are the same. Then I tried with the data encrypted. There is no doubt the data is encrypted with the cipher, however it shows up blank when it is decrypted by the stub later on. I'm confused.
Here is my XOR implementation:
fs = byte size
Rsize = byte size
Should be the same.
Builder:
char cipher[] ="penguin";
for (int i = 0; i < fs; i++)
{
FB[i] ^= cipher[i % strlen(cipher)]; // Simple Xor chiper
}
Stub:
char cipher[] = "penguin";
for (int i = 0; i < Rsize; i++)
{
RData[i] ^= cipher[i % strlen(cipher)];
}
If I were to comment out the encryption function in the Builder and Stub, the crypted file runs fine. Uhh, except with the permissions error.
I'm also trying to include a options menu where the user can select the encryption method used. Perhaps I might have done something wrong there? The Builder.exe adds one byte containing the user's choice to the end of FB buffer. Stub.exe reads that and determines which encryption method is used to decrypt the data.
First off, with XOR "encryption", your "encrypt" and "decrypt" functions should be the same:
void xor_crypt(const char *key, int key_len, char *data, int data_len)
{
for (int i = 0; i < data_len; i++)
data[i] ^= key[ i % key_len ];
}
You should be able to use this same function in both the "XOR Crypter" program as well as your "Stub" program.
It's not a very C++ style; ordinarily you'd use std::string or std::vector. For example:
void xor_crypt(const std::string &key, std::vector<char>& data)
{
for (size_t i = 0; i != data.size(); i++)
data[i] ^= key[ i % key.size() ];
}
Then in the program that calls this, you'd declare:
std::string key = "penguin";
and you'd read your file in like so:
std::vector<char> file_data; // With your current program, make this a global.
fs = GetFileSize(efile, NULL);
file_data.resize(fs); // set vector length equal to file size
// Note: Replace &( file_data[0] ) with file_data.data() if you have C++11 support
ReadFile(efile, (LPVOID)( &( file_data[0] )), fs, &bt, NULL);
if (fs != bt)
// error reading file: report it here.
Then you would simply encrypt with xor_crypt( key, file_data );. To write the XOR-crypted data to your resource, I believe you'd call your existing function with:
// replace &( file_data[0] ) with file_data.data() if C++11
WriteToResources(output, 1, (BYTE *)&( file_data[0] ), file_data.size() );
I suspect the real issue is with the Windows APIs you're using. Does LoadResource give you mutable data, or are you required to copy it? I don't know the Windows API, but I wouldn't be surprised if LoadResource gives you a read-only copy.
If you do need to make your own copy in order to modify the resource, then in your "Stub" program recovering the XOR-crypted resource should look something like this:
std::vector<char> RData;
void Resource(int id)
{
size_t Rsize;
HRSRC hResource = FindResource(NULL, MAKEINTRESOURCE(1), RT_RCDATA);
HGLOBAL temp = LoadResource(NULL, hResource);
Rsize = SizeofResource(NULL, hResource);
RData.resize(RSize);
memcpy( (void*)&(RData[0]), temp, RSize ); // replace &RData[0] with RData.data() if C++11
}
and the decryption in your "Stub" should just be xor_crypt( key, RData );.
I have one last thought. The biggest bug I see in your "Stub" program is this line:
switch (RData[strlen(RData)-1])
Once you've XOR-crypted your data, some of the bytes will become zero. The strlen() function will not return the index of the last byte in your RData as a result. And, there's a different, more subtle error: This returns the last byte of the string, not the last byte of the resource. I can't really see how this line was ever correct; rather, I suspect your program was working when encryption was disabled in spite of itself, by falling through to the default of the switch-case.
If you really intend to distinguish between different types of data based on the last byte of the resource payload, then you really should just use the size returned by the Windows API to find that byte.
If you switch to using vector<char> as I suggest above, then you can find that with RData.back(). Otherwise, if you continue using char *, then that byte would be RData[RSize - 1].
Depending on your content data, you write char option in allocated memory pointed by FB or after it (buffer overrun) in "C++ Builder/main.cpp" when calling strcat(FB, choice).
Fix: allocate enough space in FB for data + option char. As you are dealing with binary data you should not use string functions (ex: strcat).
FB = new char[fs + 1];
memcpy(FB +fs, option, 1); // copy the option at end
Related
I did a sample project to read a file into a buffer.
When I use the tellg() function it gives me a larger value than the
read function is actually read from the file. I think that there is a bug.
here is my code:
EDIT:
void read_file (const char* name, int *size , char*& buffer)
{
ifstream file;
file.open(name,ios::in|ios::binary);
*size = 0;
if (file.is_open())
{
// get length of file
file.seekg(0,std::ios_base::end);
int length = *size = file.tellg();
file.seekg(0,std::ios_base::beg);
// allocate buffer in size of file
buffer = new char[length];
// read
file.read(buffer,length);
cout << file.gcount() << endl;
}
file.close();
}
main:
void main()
{
int size = 0;
char* buffer = NULL;
read_file("File.txt",&size,buffer);
for (int i = 0; i < size; i++)
cout << buffer[i];
cout << endl;
}
tellg does not report the size of the file, nor the offset
from the beginning in bytes. It reports a token value which can
later be used to seek to the same place, and nothing more.
(It's not even guaranteed that you can convert the type to an
integral type.)
At least according to the language specification: in practice,
on Unix systems, the value returned will be the offset in bytes
from the beginning of the file, and under Windows, it will be
the offset from the beginning of the file for files opened in
binary mode. For Windows (and most non-Unix systems), in text
mode, there is no direct and immediate mapping between what
tellg returns and the number of bytes you must read to get to
that position. Under Windows, all you can really count on is
that the value will be no less than the number of bytes you have
to read (and in most real cases, won't be too much greater,
although it can be up to two times more).
If it is important to know exactly how many bytes you can read,
the only way of reliably doing so is by reading. You should be
able to do this with something like:
#include <limits>
file.ignore( std::numeric_limits<std::streamsize>::max() );
std::streamsize length = file.gcount();
file.clear(); // Since ignore will have set eof.
file.seekg( 0, std::ios_base::beg );
Finally, two other remarks concerning your code:
First, the line:
*buffer = new char[length];
shouldn't compile: you have declared buffer to be a char*,
so *buffer has type char, and is not a pointer. Given what
you seem to be doing, you probably want to declare buffer as
a char**. But a much better solution would be to declare it
as a std::vector<char>& or a std::string&. (That way, you
don't have to return the size as well, and you won't leak memory
if there is an exception.)
Second, the loop condition at the end is wrong. If you really
want to read one character at a time,
while ( file.get( buffer[i] ) ) {
++ i;
}
should do the trick. A better solution would probably be to
read blocks of data:
while ( file.read( buffer + i, N ) || file.gcount() != 0 ) {
i += file.gcount();
}
or even:
file.read( buffer, size );
size = file.gcount();
EDIT: I just noticed a third error: if you fail to open the
file, you don't tell the caller. At the very least, you should
set the size to 0 (but some sort of more precise error
handling is probably better).
In C++17 there are std::filesystem file_size methods and functions, so that can streamline the whole task.
std::filesystem::file_size - cppreference.com
std::filesystem::directory_entry::file_size - cppreference.com
With those functions/methods there's a chance not to open a file, but read cached data (especially with the std::filesystem::directory_entry::file_size method)
Those functions also require only directory read permissions and not file read permission (as tellg() does)
void read_file (int *size, char* name,char* buffer)
*buffer = new char[length];
These lines do look like a bug: you create an char array and save to buffer[0] char. Then you read a file to buffer, which is still uninitialized.
You need to pass buffer by pointer:
void read_file (int *size, char* name,char** buffer)
*buffer = new char[length];
Or by reference, which is the c++ way and is less error prone:
void read_file (int *size, char* name,char*& buffer)
buffer = new char[length];
...
fseek(fptr, 0L, SEEK_END);
filesz = ftell(fptr);
will do the file if file opened through fopen
using ifstream,
in.seekg(0,ifstream::end);
dilesz = in.tellg();
would do similar
I implemented simple file encryption/decryption with OpenSSL in C according to the instructions here. I do not need this to be truly secure (just want the files to not be readily readable on drive), the keys are hardcoded in the application and after reading the encrypted files from drive I decrypt them.
On first call, the decryptFileAsBytes function returns the correct decrypted file as byte vector. On the second call (within the same application run) the first 16 bytes of the result are garbage and the rest is correct. Does this have something to do with the size of the key (128 bits) I am using?
static bool decryptFileAsBytes(std::string filename, unsigned char *ckey, unsigned char *ivec, std::vector<unsigned char> &fileBytes)
{
std::ifstream ifs(filename, std::ios::binary | std::ios::ate);
if (ifs.fail())
return false;
std::ifstream::pos_type pos = ifs.tellg();
fileBytes.resize(pos);
ifs.close();
FILE *ifp;
if (fopen_s(&ifp, filename.c_str(), "rb") != NULL)
return false;
int bytesRead;
unsigned char indata[AES_BLOCK_SIZE];
unsigned char *writePtr = fileBytes.data();
/* data structure that contains the key itself */
AES_KEY key;
/* set the encryption key */
AES_set_encrypt_key(ckey, 128, &key);
/* set where on the 128 bit encrypted block to begin encryption*/
int num = 0;
while (1)
{
bytesRead = fread(indata, 1, AES_BLOCK_SIZE, ifp);
AES_cfb128_encrypt(indata, writePtr, bytesRead, &key, ivec, &num, AES_DECRYPT);
writePtr += bytesRead;
if (bytesRead < AES_BLOCK_SIZE)
break;
}
if (fclose(ifp) != NULL)
return false;
return true;
}
Alternatively to solving this, I welcome suggestions of a simple solution to the problem stated above ('encrypt' file on drive in a not bulletproof way so that it is not readily readable but the application can decrypt it).
The problem is likely that you're not retaining the original initialization vector for subsequent decryption operations.
As the AES encryption/decryption operations transpire, that memory is updated to continue with subsequent frames. If you instrument your code you'll see, with each encrypt/decrypt frame passing through the API, the ivec is changed.
If all you're doing this for is obfuscation (eg. you have a static key in your application) my suggestion is to do the following:
Don't pass the ivec into either the encryptor or decryptor.
Instead, generate a random ivec using RAND_bytes when encrypting. Store the ivec as the first block of data before continuing with the file content.
When decrypting, read the first block of data to prime your ivec.
Then, decrypt the remainder of the file as normal.
The benefits are:
Each encryption of a file will create a different byte representation, dependent on the initial random ivec. Eg. if you encrypt a file twice the resulting encrypted bytes will not be the same
You no longer have to use a static ivec from somewhere else in your code. The file contains it as the first block of data.
Just a suggestion. Unrelated, I prefer the EVP encryption interface, and suggest it worth a look.
Up to this point, I used to decrypt files (located on an USB stick) with AES as follows:
FILE * fp = fopen(filePath, "r");
vector<char> encryptedChars;
if (fp == NULL) {
//Could not open file
continue;
}
while(true) {
int nextEncryptedChar = fgetc(fp);
if (nextEncryptedChar == EOF) {
break;
}
encryptedChars.push_back(nextEncryptedChar);
}
fclose(fp);
char encryptedFileArray[encryptedChars.size()];
int encryptedByteCount = encryptedChars.size();
for (int x = 0; x < aantalChars; x++) {
encryptedFileArray[x] = encryptedChars[x];
}
encryptedChars.clear();
AES aes;
//Decrypt the message in-place
aes.setup(key, AES::KEY_128, AES::MODE_CBC, iv);
aes.decrypt(encryptedFileArray, sizeof(encryptedFileArray));
aes.clear();
This works perfectly for small files. At this point, I am opening a file from a USB stick and storing all characters into a vector and copying the vector to an array. I know that &encryptedChars[0] can be used as an array pointer as well and will save some memory.
Now I want to decrypt a file of 256Kb (as opposed to 1Kb). Copying the data into a source array will require at least 256Kb of RAM. I however only have 100Kb at my disposal and therefore, cannot create a source array containing the encrypted data.
So I tried to use the FILE * that fopen gives me as a FILE pointer, and created a new file on the same USB stick as a destination pointer. I was hoping that the decryption rounds would use the memory of the USB stick as opposed to available memory on the heap.
FILE * fp = fopen(encryptedFilePath, "r");
FILE * fpDecrypt = fopen(decryptedFilePath, "w+");
if (fp == NULL || fpDecrypt == NULL) {
//Could not open file!?
return;
}
AES aes;
//Decrypt the message in-place
aes.setup(key, AES::KEY_128, AES::MODE_CBC, iv);
aes.decrypt((const char*)fp, fpDecrypt, firmwareSize);
aes.clear();
Unfortunately, the system locks up (no idea why).
Does anybody know if I can pass a FILE * to a function that expects a const char * as source and a void * as a destination?
I am using the following library: https://os.mbed.com/users/neilt6/code/AES/docs/tip/AES_8h_source.html
Thanks!
A lot of crypto libraries provide "incremental" APIs that allow a stream of data to be en/decrypted piece by piece, without having to load the stream into memory. Unfortunately, it appears that the library you're using doesn't (or, at least, does not explicitly document it).
However, if you know how CBC mode encryption works, it's possible to roll your own. Basically, all you need to do is take the last AES block (i.e. the last 16 bytes) of the previous chunk of ciphertext and use it as the IV when decrypting (or encrypting) the next block, something like this:
char buffer[1024]; // this needs to be a multiple of 16 bytes!
char ivTemp[16];
while(true) {
int bytesRead = fread(buffer, 1, sizeof(buffer), inputFile);
// save last 16 bytes of ciphertext as IV for next block
if (bytesRead == sizeof(buffer)) memcpy(ivTemp, buffer + bytesRead - 16, 16);
// decrypt the message in-place
AES aes;
aes.setup(key, AES::KEY_128, AES::MODE_CBC, iv);
aes.decrypt(buffer, bytesRead);
aes.clear();
// write out decrypted data (todo: check for write errors!)
fwrite(buffer, 1, bytesRead, outputFile);
// use the saved last 16 bytes of ciphertext as IV for next block
if (bytesRead == sizeof(buffer)) memcpy(iv, ivTemp, 16);
if (bytesRead < sizeof(buffer)) break; // end of file (or read error)
}
Note that this code will overwrite the iv array. That should be OK, though, since you should never use the same IV twice anyway. (In fact, with CBC mode, the IV should be chosen by the encryptor at random, using a cryptographically secure RNG, and sent alongside the message. The usual way to do that is to simply prepend the IV to the message file.)
Also, the code above is somewhat less efficient than it needs to be, since it calls aes.setup() and thus re-runs the whole AES key expansion for each chunk. Unfortunately, I couldn't find any documented way to tell your crypto library to change the IV without re-running the setup.
However, looking at the implementation of your library, as linked by Sister Fister in the comments below, it looks like it's already replacing its internal copy of the IV with the last ciphertext block. Thus, it looks like all you really need to do is call aes.decrypt() for each block without a setup call in between, something like this:
char buffer[1024]; // this needs to be a multiple of 16 bytes!
AES aes;
aes.setup(key, AES::KEY_128, AES::MODE_CBC, iv);
while(true) {
int bytesRead = fread(buffer, 1, sizeof(buffer), inputFile);
// decrypt the chunk of data in-place (continuing from previous chunk)
aes.decrypt(buffer, bytesRead);
// write out decrypted data (todo: check for write errors!)
fwrite(buffer, 1, bytesRead, outputFile);
if (bytesRead < sizeof(buffer)) break; // end of file (or read error)
}
aes.clear();
Note that this code is relying on a feature of the crypto library that does not seem to be explicitly documented, namely that calling aes.decrypt() multiple times will cause the decryptions to be chained correctly. (That's actually a pretty reasonable thing to do, for CBC mode, but you can never be sure without reading the code or finding explicit documentation saying so.) You should make sure to have a comprehensive test suite for this, and to re-run the tests whenever you upgrade the library.
Also note that I haven't tested either of these examples, so there obviously could be bugs or typos. Also, the docs for your crypto library are somewhat sparse, so it's possible that it might not work exactly like I'm assuming it does. Please test anything based on this code throughly before using it!
In general, if something doesn't fit to memory, you can resort to:
Random accessing files. Use fseek to find the position and read or write what you need. Memory requirement minimal.
Processing in batches that will fit in to memory. Memory requirement is adjustable, but the algorithm must be suitable for this.
System virtual memory, which allows you to reserve as big blocks as your system can address, you have free disk space and your system settings. This is usually transparent depending on your system.
Other paged memory mechanisms.
Since AES encryption is made in blocks of 128 bits, and you're short of memory, you should probably use random access on your file.
I have my code which writes data into a text file. My problem is for some odd reason, it writes in Japanese! Obviously I cannot read Japanese, but how can I write it into a regular text format. Pretend the data[i].name and password have a char [10] value. And they already write in the file, the problem is the language it writes in.
// variables
FILE *streaming;
const int amount = 5;
profile data[5];
if (!(streaming = fopen("Profiles.txt", "r" )))
{
for (int i = 0; i < amount; i++)
{
data[i].name[0] = 0;
data[i].password[0] = 0;
}
streaming = fopen( "Profiles.txt", "wb" );
fwrite (data, sizeof(data), 1 , streaming);
fclose (streaming);
}
data[i].name[0] = 0; sets the first element of what I presume to be a character array to 0. It does absolutely nothing with the rest of the character array. Whatever random crap was in the rest of the character array is still there.
fwrite (data, sizeof(data), 1 , streaming); will mindlessly write the everything inside the array of profile structures, including all of the random crap after the first element of the name and password arrays inside each profile.
To completely clear the profiles, assuming there is nothing in profile that will respond badly to memset, try
memset(data, 0, sizeof(data));
Don't bother asking your doctor. Post your profile structure and we'll know for sure if memset is right for you.
this is my first post. i am currently taking a networking class and i am required to write a client program that can download all emails from imap.gmail.com:993 to text files. i am required to write this program using winsock and openssl. I was able to connect to the server and fetch the emails. For emails with small data, i had no problem receiving it. But for emails with large data such as an images that is base64-decoded, i was able to download only a part of it.
so my question is How can i tell the client to wait until it received all the data from the server?
Here is what i have done so far:
void fetchMail(SSL *sslConnection,int lowerLimit, int UpperLimit)
{
SYSTEMTIME lt;
ofstream outfile;
GetLocalTime(<);
char szFile[MAX_PATH + 1];
char szPath[MAX_PATH+1];
char message[BUFSIZE];
char result[BUFSIZE];
::GetModuleFileName( NULL, szPath, MAX_PATH );
// Change file name to current full path
LPCTSTR psz = strchr( szPath, '\\');
if( psz != NULL )
{
szPath[psz-szPath] = '\0';
}
char szMailBox[MAX_PATH+1];
memset( szMailBox, 0, sizeof(szMailBox));
wsprintf( szMailBox, "%s\\inbox", szPath );
// Create a folder to store emails
::CreateDirectory( szMailBox, NULL );
for(int i = lowerLimit; i < UpperLimit; ++i)
{
// Create a folder to store emails
memset( szFile, 0, sizeof(szFile));
memset( result, 0, sizeof(result));
memset( message, 0, sizeof(message));
::sprintf(szFile,"%s\\%d%d%d%d%d%d.txt", szMailBox, lt.wHour, lt.wMinute,lt.wMinute,lt.wSecond, lt.wMilliseconds,i);
string Result;//string which will contain the result
stringstream convert; // stringstream used for the conversion
const char * num;
convert << i;//add the value of Number to the characters in the stream
Result = convert.str();//set Result to the content of the stream
num = Result.c_str();
strcpy(result, "tag FETCH ");
strcat(result, num);
strcat(result, " (BODY[TEXT])\r\n");
int n = 0;
cout << "\nFETCHING : \n";
SSL_write(sslConnection, result, strlen(result));
outfile.open(szFile );
SSL_read(sslConnection, message, sizeof(message)-1);
outfile <<message ;
outfile.close();
}
}
First of all some points on your code:
You use strcpy, strcat and all those unchecked, unsafe C functions. You might easily get buffer overflows and other kinds of errors. Consider to use C++ strings, vectors, arrays.
You do a lot of different things in that function, on different levels of abstraction. AFAICS only the two SSL_* function calls are really about fetching that mail. Consider to break out some functions to improve readability.
Now to your problem: Googling a bit about SSL_read, you will see that it returns an int, denoting how many bytes were actually read. You should use that return value - not only for this issue but also for error handling. If the mail data is longer than your buffer, the function will read until the buffer is filled and return its size. You should continue to call the function until all bytes have been read.