Unclear pointer defect in program - c++

Im trying to build modified example of usage of DES CBC EDE on openssl. Im using gcc version 4.4.6 (Buildroot 2012.02) compiling for arm (not my choise of compiler) on ubuntu 10.04. Here is a problem: when pointer declaration is uncommented - everything is normal. Test message deciphers. But when pointer declaration gets commented - test message shows only 2 first letters after deciphering. I just can not understand what could do a declaration of an unused pointer. Here is code:
#include <openssl/des.h>
#include <cstring>
#define BUFSIZE 512
using namespace std;
int main(int argc, char *argv[]) {
unsigned char in[BUFSIZE] = {};
unsigned char out[BUFSIZE] = {};
unsigned char back[BUFSIZE] = {};
unsigned char *strangePointer = &out[0]; // what is wrong with it?
int len;
DES_cblock key1, key2, key3;
DES_cblock ivsetup = {0xE1, 0xE2, 0xE3, 0xD4, 0xD5, 0xC6, 0xC7, 0xA8};
DES_cblock ivecLocal;
DES_key_schedule ks1, ks2, ks3;
const char* key = "0A0A0B0B0C0C0A0A0B0B0C0C";
memcpy(&key1,key,8);
memcpy(&key2,key + 8,8);
memcpy(&key2,key + 16,8);
DES_set_odd_parity(&key1);
DES_set_odd_parity(&key2);
DES_set_odd_parity(&key3);
DES_set_key((C_Block *)key1, &ks1);
DES_set_key((C_Block *)key2, &ks2);
DES_set_key((C_Block *)key3, &ks3);
const char* message = "Now is the time for all men to stand up and be counted";
/* 64 bytes of plaintext */
len = strlen(message);
memcpy(in,message,len);
printf("Plaintext: [%s]\n", in);
memcpy(ivecLocal, ivsetup, sizeof(ivsetup));
DES_ede3_cbc_encrypt(in, out, len, &ks1, &ks2, &ks3, &ivecLocal, DES_ENCRYPT);
int lenout = 0;
while(out[lenout] != '\0') ++lenout;
memcpy(ivecLocal, ivsetup, sizeof(ivsetup));
DES_ede3_cbc_encrypt(out, back, lenout, &ks1, &ks2, &ks3, &ivecLocal, DES_DECRYPT);
printf("Decrypted Text: [%s]\n", back);
return 0;
}

You have several things incorrect in your code. I'll start with the simple answer first:
Your third key isn't even populated with key data. It is random data on the local activation stack.
memcpy(&key1,key,8);
memcpy(&key2,key + 8,8);
memcpy(&key2,key + 16,8); // <<=== NOTE still key2
Oh, copy-paste, ye are a cruel and heartless wench. Anyway, by removing the variable you're commenting out, this key is moving further up (or down, depending on your implementation) the stack in memory, and the result is a different value . But the bottom line, you're using indeterminate data for your third key.
But that isn't the entire problem. That change in key exposes another issue, you're output length calculation, which is also flat-wrong. This:
int lenout = 0;
while(out[lenout] != '\0') ++lenout;
assumes the length of the output cipher can be found by searching for a 0-byte. The DES algorithm can easily emit such a byte anywhere in an encryption block. This is plain wrong. The size of the output of a DES_ede3_cbc_encrypt encryption operation is always a multiple of the block size, which for DES is 8 bytes (not coincidentally the size of a DES_cblock), The correct calculation of your output buffer size is:
int lenout = ((len + sizeof(DES_cblock) - 1)/sizeof(DES_cblock))*sizeof(DES_cblock);
which may seem like a helluva lot, but in the end all this does is round up to the nearest multiple of the block length. Further, you don't even need the input buffer. The API will do the calculation for you if you simply pass your input data message and its true length. But I leave that for you to finish (hint: just remove input and pass message).
the result is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/des.h>
#define BUFSIZE 512
int main(int argc, char *argv[])
{
unsigned char in[BUFSIZE] = {};
unsigned char out[BUFSIZE] = {};
unsigned char back[BUFSIZE] = {};
int len;
DES_cblock key1, key2, key3;
DES_cblock ivsetup = {0xE1, 0xE2, 0xE3, 0xD4, 0xD5, 0xC6, 0xC7, 0xA8};
DES_cblock ivecLocal;
DES_key_schedule ks1, ks2, ks3;
const char* key = "0A0A0B0B0C0C0A0A0B0B0C0C";
memcpy(&key1,key,8);
memcpy(&key2,key + 8,8);
memcpy(&key3,key + 16,8);
DES_set_odd_parity(&key1);
DES_set_odd_parity(&key2);
DES_set_odd_parity(&key3);
DES_set_key(&key1, &ks1);
DES_set_key(&key2, &ks2);
DES_set_key(&key3, &ks3);
const char* message = "Now is the time for all men to stand up and be counted";
len = strlen(message);
memcpy(in,message,len);
printf("Plaintext: [%s]\n", in);
memcpy(ivecLocal, ivsetup, sizeof(ivsetup));
DES_ede3_cbc_encrypt(in, out, len, &ks1, &ks2, &ks3, &ivecLocal, DES_ENCRYPT);
int lenout = ((len + sizeof(DES_cblock) - 1)/sizeof(DES_cblock))*sizeof(DES_cblock);
memcpy(ivecLocal, ivsetup, sizeof(ivsetup));
DES_ede3_cbc_encrypt(out, back, lenout, &ks1, &ks2, &ks3, &ivecLocal, DES_DECRYPT);
printf("Decrypted Text: [%s]\n", back);
return 0;
}
Output
Plaintext: [Now is the time for all men to stand up and be counted]
Decrypted Text: [Now is the time for all men to stand up and be counted]

You are most probably experiencing a buffer overflow. The declaration of len comes after back on the stack. If back overflows, then len will be overwritten. Adding another variable (strangePointer) in between adds a gap on the stack that stops len getting overwritten.
Probably increasing BUFSIZE should solve your issue.

Related

Stack level too deep error in ruby native extension, how to reduce stack level?

I have a Ruby on Rails api which handles a simple API call and returns some encrypted data. The encryption is done in C++, using the ruby native C api. (reference here).
The native part works fine when compiled and linked as a standalone program, and also when used with ruby in IRB.
However, when I use it from within the Rails API, I sometimes get a "Stack level too deep" error.
The error seems to occur or not depending on the size of the data processed.
According to this answer, the stack 'level' is actually stack space, so it would make sense that if I have more data to process, then I have more data in the stack, so it fills up quicker etc...
I had initially left all my variables in the stack, for simplicity and to avoid forgetting to free allocated memory. Seeing this error, I switched to a dynamical allocation approach. However contrarily to what I was expecting, the Stack level too deep error occurs for even smaller data size.
data_controller.rb
def load_data data_path, width
authorize!
encrypted = NativeDataProtector.encrypt(data_path, get_key(), get_iv())
return [ encrypted, "application/octet-stream" ]
end
native_encryptor.cpp
VALUE encrypt_n(VALUE _self, VALUE data_path, VALUE key, VALUE salt){
DataProtector protector;
string *b64 = protector.encrypt(StringValueCStr(data_path), \
StringValueCStr(key), \
StringValueCStr(salt));
VALUE ret = rb_str_new(b64->c_str(), b64->length());
delete(b64);
return ret;
}
extern "C" void Init_data_protector() {
VALUE mod = rb_define_module("NativeDataProtector");
rb_define_module_function(mod, "encrypt", (VALUE(*)(ANYARGS))encrypt_n, 3);
}
encrypt.h
#include <ruby.h>
#include "extconf.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <list>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
class DataProtector {
private :
int pad_cleartext(vector<unsigned char> *cleartext);
vector<unsigned char> *read_data(string path);
int aes_encrypt(vector<unsigned char> *plaintext, string key,
string iv, unsigned char *ciphertext);
string to_b64(unsigned char* in);
void handleErrors(void);
public :
string *encrypt(string data_path, string key, string salt);
};
encrypt.cpp
string *DataProtector::encrypt(string data_path, string key, string salt) {
vector<unsigned char> *cleartext = readData(data_path);
int length = pad_cleartext(cleartext);
unsigned char* output = new unsigned char[length + 16];
int ciphertext_len;
// encrypt
string *encrypted = new string("");
ciphertext_len = aes_encrypt(&((*cleartext), key, iv, output);
(*encrypted) += to_b64(output);
delete(cleartext);
delete(output);
return encrypted;
}
int DataProtector::aes_encrypt(vector<unsigned char> *plaintext, string key,
string iv, unsigned char *ciphertext)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
/* Initialise the encryption operation. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
* In this example we are using 256 bit AES (i.e. a 256 bit key). The
* IV size for *most* modes is the same as the block size. For AES this
* is 128 bits */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, (const unsigned char *)key.c_str(), (const unsigned char *)iv.c_str()))
handleErrors();
/* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, reinterpret_cast<unsigned char*>(plaintext->data()), plaintext->size()))
handleErrors();
ciphertext_len = len;
/* Finalise the encryption. Further ciphertext bytes may be written at
* this stage.
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
ciphertext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int DataProtector::pad_cleartext(vector<unsigned char> *in) {
// padds to length multiple of 16
int nb_blocks = in->size() / 16 + ((in->size()%16 == 0)? 1:1);
int size = nb_blocks*16;
for (unsigned int i=in->size(); i<size; i++) {
unsigned char c = '0';
in->push_back(c);
}
return size;
}
vector<unsigned char> *DataProtector::read_data(string path) {
streampos size;
ifstream file(path, ios::binary);
file.seekg(0, ios::end);
size = file.tellg();
file.seekg(0, ios::beg);
vector<unsigned char> *data = new vector<unsigned char>(fileSize);
file.read((char*) &data[0], size);
return data;
}
void DataProtector::handleErrors(void) {
ERR_print_errors_fp(stderr);
abort();
}
(the actual encryption is from here)
The error stack trace I get :
SystemStackError (stack level too deep):
app/controllers/data_controller.rb:41:in `encrypt'
app/controllers/data_controller.rb:41:in `load_data'
app/controllers/data_controller.rb:15:in `show'
Is Believe that the reason for this error is too much data allocated on the stack, and not a recursion issue. However, I don't understand why switching to heap allocation did not improve anything.
I can imagine 2 solutions :
cutting up the data in ruby and calling the native method several times with less data.
increasing the ruby stack size.
However both these solutions are unideal for my project, for performance/resource issues.
Is there any other way I can reduce the usage of the stack by my program ?

mbstowcs_s function retsize sometimes return input length + 1

I'm using VisualStdio 2010 on Windows 7.
I want to decrypt password using function and display result of decryption as TCHAR*.
Implementation here,
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
char* _decrypt_password_v1(const char* strPassword);
char Hash_v1(const char chhash, int nIndex);
#define VIT_PASSWORD _decrypt_password_v1("OOWIEJFOISJDFNPPAJ")
char* _decrypt_password_v1(const char* strPassword)
{
unsigned int i = 0;
char* strDecrypt = (char*)malloc(strlen(strPassword) + 1);
memset(strDecrypt, 0x00, strlen(strPassword) + 1);
int nLen = strlen(strPassword) -1;
for (int i = 0; i < nLen; i++)
{
strDecrypt[i] = Hash_v1(strPassword[nLen - i], nLen - 1);
}
strDecrypt[i] = NULL;
return strDecrypt;
}
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR szPassword[MAX_PATH] = {0};
int nLen = strlen(VIT_PASSWORD);
_tprintf(_T("Input Password Len : %d\n"), nLen);
size_t outSize;
mbstowcs_s(&outSize, szPassword, strlen(VIT_PASSWORD), VIT_PASSWORD, strlen(VIT_PASSWORD));
_tprintf(_T("Password : %s\n"), szPassword);
return 0;
}
If I run this code, I will get an error
Debug Assertion Failed!
File: f:\dd\vctools\crt_bld\self_x86\crt\src\mbstowcs.c
Line: 283
Expression: retsize <= sizeInWords
So, I increased parameter 3 of mbstowcs_s tostrlen(VIT_PASSWORD) + 1.
Corrected code:
mbstowcs_s(&outSize, szPassword, strlen(VIT_PASSWORD) + 1, VIT_PASSWORD, strlen(VIT_PASSWORD));
Then no crash and run correctly, but sizeInWords is strlen(VIT_PASSWORD), not strlen(VIT_PASSWORD) + 1.
If I use mbstowcs instead, there's no error. like this mbstowcs(szPassword, VIT_PASSWORD, strlen(VIT_PASSWORD));
Why this happens? If the answer is not clear, I have to modify this part of my entire code in this way.
I need concrete answers.
The third parameter to mbtowcs_s should be the size of the buffer pointed to by the second parameter in wchar_ts, so in your case it should be MAX_PATH.
The point of mbtowcs_s is to make sure you don't write more characters to the destination than you have space for. That's what the third parameter is for: to tell it how much space you have. In this case, if VIT_PASSWORD has no non-ASCII characters in it, the destination will need the same number of wchar_ts to hold the converted string. So if VIT_PASSWORD is 4 characters long, plus the nul terminator, then mbtowcs_s's third parameter will need to be at least 5 to successfully convert the string (4 characters plus the nul-terminator). The problem is that strlen(VIT_PASSWORD) will return 4, not 5 since it doesn't count the nul-terminator.

How to encrypt a message to Blowfish using OpenSSL?

I need to get the Blowfish encryption with OpenSSL library. But something does not work.
What am I doing wrong? I'm trying to do it this way:
#include <iostream>
#include <openssl/blowfish.h>
#include "OpenSSL_Base64.h"
#include "Base64.h"
using namespace std;
int main()
{
unsigned char ciphertext[BF_BLOCK];
unsigned char plaintext[BF_BLOCK];
// blowfish key
const unsigned char *key = (const unsigned char*)"topsecret";
//unsigned char key_data[10] = "topsecret";
BF_KEY bfKey;
BF_set_key(&bfKey, 10, key);
/* Open SSL's Blowfish ECB encrypt/decrypt function only handles 8 bytes of data */
char a_str[] = "8 Bytes";//{8, ,B,y,t,e,s,\0}
char *arr_ptr = &a_str[0];
//unsigned char* data_to_encrypt = (unsigned char*)"8 Bytes"; // 7 + \0
BF_ecb_encrypt((unsigned char*)arr_ptr, ciphertext, &bfKey, BF_ENCRYPT);
unsigned char* ret = new unsigned char[BF_BLOCK + 1];
strcpy((char*)ret, (char*)ciphertext);
ret[BF_BLOCK + 1] = '\0';
char* base_enc = OpenSSL_Base64::Base64Encode((char*)ret, strlen((char*)ret));
cout << base_enc << endl;
cin.get();
return 0;
}
But I get the wrong output:
fy7maf+FhmbM
I checked with it:
http://sladex.org/blowfish.js/
It should be: fEcC5/EKDVY=
Base64:
http://pastebin.com/wNLZQxQT
The problem is that ret may contain a null byte, encryption is 8-bit byte based, not character based and will contain values fromthe full range 0-255. strlen will terminate on the first null byte it finds giving a length that is smaller then the full length of the encrypted data.
Note: When using encryption pay strice attention to providing the exact correct length parameters and data, do not rely on padding. (The exception is input data to encryption functions that support data padding such as PKCS#7 (née PKCS#5) padding.

How to use salsa20 (or ChaCha)?

Assume that we have a large file which can be read in chunks of 1024 bytes or so, how can I encrypt and decrypt each chunk using Salsa or Chacha 20?
Also, where would I specify the number of rounds (i.e. 8, 12, or 20)?
So far, I haven't been able to figure it out by looking at the eSTREAM test package :(
I've downloaded the following files via eSTREAM and the Salsa20 homepage:
chacha.c
ecrypt-config.h
ecrypt-machine.h
ecrypt-portable.h
ecrypt-sync.h
And I see the comments in encrypt-sync.h talk about calling functions in this order:
ECRYPT_keysetup();
ECRYPT_ivsetup();
ECRYPT_encrypt_bytes();
But I have absolutely no idea exactly what I'm supposed to be supplying as parameters to make this work...
Here's my best attempt so far, starting with one small string of plaintext (my C is rusty... it's possible I've made some basic mistake, though I can't see it):
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "ecrypt-sync.h"
#define CHUNKSIZE 1024
void getRandomBytes(u8 **str, u32 len);
void showData(u8 *data, u8 *header);
int main(int argc, char** argv)
{
char plaintext[CHUNKSIZE] = "THIS IS A TEST";
ECRYPT_ctx ctx;
u8 *key, *IV, *ciphertext, *result;
/*
Don't use random values till we get it working with zeroes at least
getRandomBytes(&key, ECRYPT_MAXKEYSIZE/8);
getRandomBytes(&IV, ECRYPT_MAXIVSIZE/8);
*/
key = (u8 *)calloc((size_t)ECRYPT_MAXKEYSIZE/8, sizeof(u8));
IV = (u8 *)calloc((size_t)ECRYPT_MAXIVSIZE/8, sizeof(u8));
printf("Encrypting [%s] using random %d bit key and %d bit IV:\n", plaintext, ECRYPT_MAXKEYSIZE, ECRYPT_MAXIVSIZE);
ECRYPT_init();
ECRYPT_keysetup(&ctx, key, ECRYPT_MAXKEYSIZE, ECRYPT_MAXIVSIZE);
ECRYPT_ivsetup(&ctx, IV);
ciphertext = (u8 *)calloc((size_t)CHUNKSIZE, sizeof(u8));
ECRYPT_encrypt_bytes(&ctx, plaintext, ciphertext, CHUNKSIZE);
//showData(ciphertext, "CIPHERTEXT");
result = (u8 *)calloc((size_t)CHUNKSIZE, sizeof(u8));
ECRYPT_decrypt_bytes(&ctx, ciphertext, result, CHUNKSIZE);
printf("And now decrypting back: [%s]\n", result);
return 0;
}
void showData(u8 *data, u8 *header) {
printf("\n-----BEGIN %s-----\n%s\n-----END %s-----\n", header, data, header);
}
void getRandomBytes(u8 **str, u32 len) {
int fd = open("/dev/random", O_RDONLY);
char *ptr = malloc((size_t) + 1);
read(fd, ptr, len);
close(fd);
ptr[len] = '\0';
*str = ptr;
}
Results are like:
Encrypting [THIS IS A TEST] using random 256 bit key and 64 bit IV:
And now decrypting back: [(bunch of random characters)]
Where it should be:
And now decrypting back: [THIS IS A TEST]
Feel free to provide your solution in either C or C++
Thank you!
If you are going to use Salsa20 in real code and you are asking questions like this, you probably want to use the NaCl library with nice friendly C++ wrappers.
See The NaCl website.
To answer your actual question: you need to set the IV up again for the decryption operation. The IV consists of your nonce and a block offset. The encrypt/decrypt functions increment the offset, giving your code a different IV for the encryption and decryption functions.

memcpy - int variable to BYTE

I am trying to create a data packet, using memcpy. I expect to see the output in pOutBuffer, whose first four bytes will have 999, followed by 111 followed by 12; But currently i am getting some garbage.
The problem is that instead of copying the value, it copies the address, I think. How can i copy these values in to a contiguous memory so that i can write it to disk and can retrieve the data at the receiving end with my defined format?
Thanks.
#include "stdafx.h"
#include "windows.h"
typedef struct
{
int Begin;
int End;
int Size;
}PACKET;
void AddBuffer(PACKET* pPacket, BYTE* pOutBuffer)
{
memcpy(pOutBuffer, &pPacket->Begin, sizeof(int));
memcpy(pOutBuffer+sizeof(int), &pPacket->End, sizeof(int));
memcpy(pOutBuffer+sizeof(int)+sizeof(int), &pPacket->Size, sizeof(int));
}
int _tmain(int argc, _TCHAR* argv[])
{
PACKET* pPacket = new PACKET;
pPacket->Begin = 999;
pPacket->End = 111;
pPacket->Size = 12;
BYTE* pOutBuffer = new BYTE [pPacket->Size];
AddBuffer(pPacket, pOutBuffer);
//Write pOutBuffer on to the disk
//WriteFile(vhFileToWrite,(BYTE*)pOutBuffer,pPacket.Size,&vRetFileSize,NULL);
//Delete pOutBuffer
return 0;
}
Source sample has been updated. It now builds ok
Your code works correctly. On a little-endian machine with sizeof(int)==4, the number 999 will be stored as the four bytes 0xe7, 0x03, 0x00, 0x00.
You said you saw the character 'ç': That is because you are trying to view the array as a string, and ç has the character code 0xe7, which is indeed the first byte written. If you view it as an array (either using Visual Studio's memory view, or by typing pOutBuffer,12 in the watch window), you will see the correct byte values.