OpenSSL - How to determine the right length of an rsa encrypted string? - c++

I use OpenSSL to encryt a string. After that I want to encode the encrypted string with base64 algorithm also using OpenSSL. So I found the following code snipped: ( bit.ly/adUSEw )
char *base64(const unsigned char *input, int length) {
BIO *bmem, *b64;
BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64());
bmem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bmem);
BIO_write(b64, input, length);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr);
char *buff = (char*)malloc(bptr->length);
memcpy(buff, bptr->data, bptr->length - 1);
buff[bptr->length - 1] = 0;
BIO_free_all(b64);
return buff;
}
int main(int argc, char **argv) {
char *message = "TEST";
char *encryptedString = Encrypt(message);
if (encryptedString == NULL) {
return 0;
}
else {
char *output = base64(encryptedString, strlen(encryptedString));
cout << output << endl;
} }
I noticed that strlen(encryptedString) isn't working properly in this case. Sometimes it returns the right lenght but mostly not. So whats is the proper way to determine the correct lenght?

The size of the encrypted message is exactly the size of the modulus in the private key. You have to get the information from there.
You cannot use strlen because
the buffer with the encrypted message is likely not null-terminated, and
the encrypted message may contain (and will likely contain) null bytes.

Related

AES-CBC and SHA-512 hash Encryption with C++ produces odd output

EDIT
This question has been half answered through comments. I was successful in getting the encryption with both AES and SHA to work successfully. The problem with SHA was simple - I was hashing in Java with uppercase hex and C++ with lowercase. AES was successful after changing the type from string to unsigned char and using memcpy instead of strcpy.. I'm still interested in understanding why, after encryption, the result contained the original message in plaintext alongside the binary data - regardless of the type that I was using.
I am currently working on a project in C++ that requires encryption. Normally, I would use Java for this task, however, due to software requirements I have chose C++. After creating an Encryption class with the openssl library, I ran a simple test with AES-CBC 256. The test was a Hello World message encrypted by a hex string key and IV followed by the encrypted result being decrypted. The output below shows the results.
After encryption the binary data contains the original string in plain text as well as the hex value present in the encrypted hex string. After decryption the original hex value for the message is shown in the output as if the process worked.
I am also having problems with creating a SHA-512 hash. Creating a hash in Java differs from the one created in C++. Creating a SHA-256 Hmac hash, however, produces the same output in both languages.
Below is the C++ code I am using in the encryption class.
std::string Encryption::AES::cbc256(const char* data, ssize_t len, const char* key, const char* iv, bool encrypt) {
std::string keyStr = key;
std::string ivStr = iv;
std::string dataStr = data;
std::string _keyStr = Encryption::Utils::fromHex(keyStr.c_str(), 64);
std::string _ivStr = Encryption::Utils::fromHex(ivStr.c_str(), 32);
std::string _dataStr = Encryption::Utils::fromHex(dataStr.c_str(), dataStr.size());
size_t inputLength = len;
char aes_input[_dataStr.size()];
char aes_key[32];
memset(aes_input, 0, _dataStr.size());
memset(aes_key, 0, sizeof(aes_key));
strcpy(aes_input, _dataStr.c_str());
strcpy(aes_key, _keyStr.c_str());
char aes_iv[16];
memset(aes_iv, 0x00, AES_BLOCK_SIZE);
strcpy(aes_iv, _ivStr.c_str());
const size_t encLength = ((inputLength + AES_BLOCK_SIZE) / AES_BLOCK_SIZE);
if(encrypt) {
char res[inputLength];
AES_KEY enc_key;
AES_set_encrypt_key((unsigned char*) aes_key, 256, &enc_key);
AES_cbc_encrypt((unsigned char*) aes_input, (unsigned char *) res, inputLength, &enc_key, (unsigned char *) aes_iv, AES_ENCRYPT);
return Encryption::Utils::toHex((unsigned char *) res, strlen(res));
} else {
char res[inputLength];
AES_KEY enc_key;
AES_set_decrypt_key((unsigned char*) aes_key, 256, &enc_key);
AES_cbc_encrypt((unsigned char*) aes_input, (unsigned char *) res, inputLength, &enc_key, (unsigned char *) aes_iv, AES_DECRYPT);
return Encryption::Utils::toHex((unsigned char *) res, strlen(res));
}
}
std::string Encryption::SHA::hash512(const char *source) {
std::string input = source;
unsigned char hash[64];
SHA512_CTX sha512;
SHA512_Init(&sha512);
SHA512_Update(&sha512, input.c_str(), input.size());
SHA512_Final(hash, &sha512);
std::stringstream ss;
for(int i=0; i<sizeof(hash); i++) {
ss << std::hex << std::setw(2) << std::setfill('0') << (int) hash[i];
}
return ss.str();
}
std::string Encryption::Utils::fromHex(const char* source, ssize_t size) {
int _size = size / 2;
char* dest = new char[_size];
std::string input = source;
int x=0;
int i;
for(i=0;i<_size; i++) {
std::string ret = "";
for(int y=0; y<2; y++) {
ret += input.at(x);
x++;
}
std::stringstream ss;
ss << std::hex << ret;
unsigned int j;
ss >> j;
dest[i] = (char) static_cast<int>(j);
}
return std::string(dest);
}
Can anyone explain to me, or offer their help, as to why I am getting the output I am getting?

How to make a hashed password like the crypt function does?

I want to generate a hashed password manually using openssl API according to the wiki of crypt, but the program result is not same with the result from crypt function, is there something wrong?
int main() {
const char *salt = "123456";
const char *password = "123456";
unsigned char hashedPasswd[SHA512_DIGEST_LENGTH];
SHA512_CTX context;
if (!SHA512_Init(&context)) return -1;
if (!SHA512_Update(&context, (unsigned char *) salt, strlen(salt))) return -1;
if (!SHA512_Update(&context, (unsigned char *) password, strlen(password))) return -1;
if (!SHA512_Final(hashedPasswd, &context)) return -1;
std::string base64Data = base64_encode(hashedPasswd, sizeof(hashedPasswd));
printf("my result: %s\n", base64Data.c_str());
char *hashedPassword = crypt("123456", "$6$123456");
printf("crypt result: %s\n", hashedPassword);
return 0;
}
My Result:
PXeFkSq39sRSVXsSaxLWUUWDt45I8tw9mgcY8GE3B/r3VylOko0q727qPChy+uibqcFuCy6w67ruaQ3AyHHeDg==
Crypt Result:
$6$123456$37mxvJGRzjWxgD3HYl.bKq4aUXrcYV8mk0pxmqg8ARv3t9ke5ZM/NBbwTkx1FDcnLhrOX3jQc6L/NKAohhQJn/
The part of hashed is quite different.

Base64 encode a XXTEA encrypted string error

I would like to secure my data so I try to encrypt it with XXTEA. I do this way:
inputString -> XXTEA encrypt -> outputString
outputString -> XXTEA decrypt -> inputString
Everything is encrypt and decrypt ok. But when I try to make a base64 encode the output after XXTEA encrypt it and base64 decode it before XXTEA decrypt, the result is wrong:
input -> XXTEA encrypt -> base64 encode -> output
output -> base64 decode -> XXTEA decrypt != input
When I test with http://www.tools4noobs.com/online_tools/xxtea_encrypt/ and http://www.tools4noobs.com/online_tools/xxtea_decrypt/
My example's input string is hello and its final result is bjz/S2f3Xkxr08hu
But when I test with my code (see below), the final result is bjz/Sw==
Here is my encryption code:
std::string ProjectUtils::encrypt_data_xxtea(std::string input, std::string secret) {
//Encrypt with XXTEA
xxtea_long retLength = 0;
unsigned char data[input.length()];
strncpy((char*)data, input.c_str(), sizeof(data));
xxtea_long dataLength = (xxtea_long) sizeof(data);
unsigned char key[secret.length()];
strncpy((char*)key, secret.c_str(), sizeof(key));
xxtea_long keyLength = (xxtea_long) sizeof(key);
unsigned char *encryptedData = xxtea_encrypt(data, dataLength, key, keyLength, &retLength);
//Encode base64
char* out = NULL;
base64Encode(encryptedData, sizeof(encryptedData), &out);
CCLOG("xxtea encrypted data: %s", out);
return out;
}
Here is my decryption code:
char* ProjectUtils::decrypt_data_xxtea(std::string input, std::string secret) {
//Decode base64
unsigned char* output = NULL;
base64Decode((unsigned char*)input.c_str(), (unsigned int)strlen(input.c_str()), &output);
xxtea_long dataLength = (xxtea_long) sizeof(output);
xxtea_long retLength = 0;
unsigned char key[secret.length()];
strncpy((char*)key, secret.c_str(), sizeof(key));
xxtea_long keyLength = (xxtea_long) sizeof(key);
//Decrypt with XXTEA
char *decryptedData = reinterpret_cast<char*>(xxtea_decrypt(output, dataLength, key, keyLength, &retLength));
CCLOG("xxtea decrypted data: %s", decryptedData);
return decryptedData;
}
Do you know what is wrong with my code? Any help would be appreciated!
Thanks very much.
here is full working code on cocos2d-x 3.4
std::string UserProfile::encryptString(std::string input, std::string secret) {
//Encrypt with XXTEA
xxtea_long retLength = 0;
unsigned char data[input.length()];
strncpy((char*)data, input.c_str(), sizeof(data));
xxtea_long dataLength = (xxtea_long) sizeof(data);
unsigned char key[secret.length()];
strncpy((char*)key, secret.c_str(), sizeof(key));
xxtea_long keyLength = (xxtea_long) sizeof(key);
unsigned const char *encryptedData = reinterpret_cast<unsigned const char*>(xxtea_encrypt(data, dataLength, key, keyLength, &retLength));
char* out = NULL;
cocos2d::base64Encode(encryptedData, retLength, &out); // use real length returned by xxtea_encrypt
CCLOG("xxtea encrypted data: [%s][%s]", encryptedData, out);
std::string outStr(out); // make string object
CCLOG("xxtea encrypted data: [%s][%s]", encryptedData, outStr.c_str());
setStr(KEY, outStr); // function that store value in user defaults
std::string revertStr = getStr(KEY); // get string value back
CCLOG("xxtea revertStr: [%s]", revertStr.c_str());
unsigned char* output = NULL;
int outLength = cocos2d::base64Decode((unsigned char*)revertStr.c_str(), (unsigned int)strlen(revertStr.c_str()), &output); // get real length of decoded string
char *decryptedData = reinterpret_cast<char*>(xxtea_decrypt(output, outLength, key, keyLength, &retLength)); // use it
CCLOG("xxtea decrypted data: %s", decryptedData); // string the same as original for me
return "";
}
thanks for your code, it works for me)
I have replaced length of base64 string by actual retLength
base64Encode(encryptedData, retLength, &out);
and back, get actual size as well
int outLength = cocos2d::base64Decode((unsigned char*)revertStr.c_str(), (unsigned int)strlen(revertStr.c_str()), &output);
char *decryptedData = reinterpret_cast<char*>(xxtea_decrypt(output, outLength, key, keyLength, &retLength));

Why does my OpenSSL C++ code create binary encryption output?

I'm trying to encrypt a file using AES from OpenSSL and then write the output to a file. But I'm getting messy outputs, sometimes decipherable and sometimes not.
The main code is based from here: https://github.com/shanet/Crypto-Example/blob/master/crypto-example.cpp
Here's the code:
int Crypt::__aesEncrypt(const unsigned char *msg, size_t msgLen, unsigned char **encMsg) {
EVP_CIPHER_CTX *aesEncryptCtx = (EVP_CIPHER_CTX*)malloc(sizeof(EVP_CIPHER_CTX));
EVP_CIPHER_CTX_init(aesEncryptCtx);
unsigned char *aesKey = (unsigned char*)malloc(AES_KEYLEN/8);
unsigned char *aesIV = (unsigned char*)malloc(AES_KEYLEN/8);
unsigned char *aesPass = (unsigned char*)malloc(AES_KEYLEN/8);
unsigned char *aesSalt = (unsigned char*)malloc(8);
if(RAND_bytes(aesPass, AES_KEYLEN/8) == 0) {
return FAILURE;
}
if(RAND_bytes(aesSalt, 8) == 0) {
return FAILURE;
}
if(EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), aesSalt, aesPass, AES_KEYLEN/8, AES_ROUNDS, aesKey, aesIV) == 0) {
return FAILURE;
}
strncpy((char*)aesKey, (const char*)"B374A26A71490437AA024E4FADD5B4AA", AES_KEYLEN/8);
strncpy((char*)aesIV, (const char*)"7E892875A52C59A3B588306B13C31FBD", AES_KEYLEN/16);
size_t blockLen = 0;
size_t encMsgLen = 0;
*encMsg = (unsigned char*)malloc(msgLen + AES_BLOCK_SIZE);
if(encMsg == NULL) return FAILURE;
if(!EVP_EncryptInit_ex(aesEncryptCtx, EVP_aes_256_cbc(), NULL, aesKey, aesIV)) {
return FAILURE;
}
if(!EVP_EncryptUpdate(aesEncryptCtx, *encMsg, (int*)&blockLen, (unsigned char*)msg, msgLen)) {
return FAILURE;
}
encMsgLen += blockLen;
if(!EVP_EncryptFinal_ex(aesEncryptCtx, *encMsg + encMsgLen, (int*)&blockLen)) {
return FAILURE;
}
EVP_CIPHER_CTX_cleanup(aesEncryptCtx);
free(aesEncryptCtx);
free(aesKey);
free(aesIV);
return encMsgLen + blockLen;
}
Im calling like this:
unsigned char *encMsg = NULL;
__aesEncrypt((const unsigned char*)decrypted_string.c_str(), decrypted_string.size(), &encMsg);
std::stringstream ss;
ss << encMsg;
//write ss to file...
Thanks.
I'm actually the author of the example you've based your code off of. As WhozCraig pointed out in the comments above, you are using a stringstream to write the encrypted message to a file. The problem with this is that encrypted messages are not regular ASCII strings. They are binary data (values greater than 127, hence the need for an unsigned char array) and binary data cannot be treated the same as ASCII strings.
I'm not much of a C++ person, so I would write the data to a file the C way with fwrite, but if you want to do it the C++ way, I think you're looking for ifstream rather than stringstream.
Side note, I'm betting this is just for debugging, but I'll point it out anyway just to make sure: Hardcoding your AES key and IV (strncpy((char*)aesKey, (const char*)"B374A26A71490437AA024E4FADD5B4AA", AES_KEYLEN/8)) completely defeats the purpose of encryption. If you want to avoid the PBKDF (EVP_BytesToKey) you can just use RAND_Bytes to get random data for your AES key.

Openssl AES crypt C++ function. After decode I have only 16 characters from the primary string

I've tried to make a program which will be encrypt strings by AES encryption. After looking at stackoverflow and many other forums I end up with this. But there are some problems with the code:
1.Sometimes encryption works sometimes not(for 20 tries, 2 failed). How to fix it? It's related to ivec or maybe textLength?
2.After encryption and decryption I have only 16 first characters of my primary
string.After this I have some random characters. It is possible to decrypt all my string or I have to cut to 16 characters pieces?
3.I need to fuse some chars so I made this:
char ivec[16];
for(int i=0;i<16;i++)
{
ivec[i]=iveccreate[i];
}
But after all char ivec[16] have 55 characters. Any idea why?
4.After function AES_cbc_encrypt my ivec changed to some totally diffrent char. Is there any way to stop this(I want to reduce size of the code)?
I will be very greatful for the answers to the 1-4 questions.
MKAROL
PS:I come from Poland so my English is not so good. Sorry.
Valiable code:
#include <string.h>
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <openssl/aes.h>
#include <time.h>
#include <stdlib.h>
#include <vector>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/rand.h>
using namespace std;
string AESencode(string Text,string Key);
void AESdecode(string in,string Key);
char *encode(unsigned char *input, int length);
char *decode(unsigned char *input,int lenght);
void main
{
string out=AESencode("String,which I want to encrypt.\0","encryptionkey");
AESdecode(out,"encryptionkey");
return 0;
}
string AESencode(string Text,string Key)
{
//Creating 16 random ive
srand((unsigned int) time(NULL));
unsigned char ive[16];
for(int i=0; i<16; i++){
ive[i] = (unsigned char) rand();
}
//I'm losing null by encode ive
char *iveccreate=encode(ive,16);
//Copying 16 first chars from iveccreate(16 random letters,numbers)
char ivec[16];
for(int i=0;i<16;i++)
{
ivec[i]=iveccreate[i];
}
//Saving ivec,because I need to fuse ivec with output later
//and after encode I lose orginal ivec
char* ivec1=decode((unsigned char*)iveccreate,strlen((const char*)iveccreate));
// Round up to AES_BLOCK_SIZE
size_t textLength = ((Text.length() / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;
//If necessary adding null to the Key(full 32 bytes)
if(Klucz.length() < 32){
Key.append(32 - Key.length(), '\0');
}
//Creating space for the output
unsigned char *aesoutput = new unsigned char[textLength];
//Create and set AESkey
AES_KEY *aesKey = new AES_KEY;
AES_set_encrypt_key((unsigned char*)Key.c_str(), 256, aesKey);
//Encrypting
AES_cbc_encrypt((unsigned char*)Text.c_str(), aesoutput, Text.length()+ 1, aesKey, (unsigned char*)ivec, AES_ENCRYPT);
//Fusing ivec with aesoutput
char wyjsciowy[strlen((const char*)Wyjscie)+16];
for(int i=0;i<16;i++){
fuse[i]=ivec1[i];
}
for(int i=0;i<strlen((const char*)Wyjscie);i++) {
fuse[i+16]=aesouput[i];
}
//Encode the fuse
char* out=encode((unsigned char*)wyjsciowy,strlen(wyjsciowy));
//Saving chars to string
string mychar((char*)out);
//Creating normal string from the base64 encode output
//String is 65 chars, new line, 65 chars
//so I'm looking for the number of not 65, ending chars of the string
int res=mychar.length()%65;
string allstr;
//Fuse strings without new line charater
for(int i=0;i<(mychar.length()-res);i+=65)
{
allstr+=mychar.substr(i,64);
}
//Fuse string with the ending string.If res==0 it will add nothing.
allstr+=mychar.substr((mychar.length()-res),res);
//Returnig string
return allstr;
}
//Base64 encode function
char *encode(unsigned char *input, int length)
{
BIO *bmem, *b64;
BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64());
bmem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bmem);
BIO_write(b64, input, length);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr);
char *buff = (char *)malloc(bptr->length+1);
memcpy(buff, bptr->data, bptr->length);
buff[bptr->length] = 0;
BIO_free_all(b64);
return buff;
}
//Base64 decode function
char *decode(unsigned char *input, int length)
{
BIO *b64, *bmem;
char *buffer = (char *)malloc(length);
memset(buffer, 0, length);
b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bmem = BIO_new_mem_buf(input, length);
bmem = BIO_push(b64, bmem);
BIO_read(bmem, buffer, length);
BIO_free_all(bmem);
return buffer;
}
void AESdecode(string in,string Key)
{
//Decode the input string with Base64
char* dec=decode((unsigned char*)in.c_str(),in.length());
//Getting ivec
unsigned char ivec[16];
{
//Getting first 16 bytes from dec
unsigned char preivec[16];
for(int i=0;i<16; i++){
preivec[i] = dec[i];
}
//Encode these 16 bytes
char *ppiv=encode(preivec,16);
//Now we have 25 chars text
//And ivec is only fist 16
for(int i=0;i<25; i++){
ivec[i] = ppiv[i];
}
}
//Getting aesouput bytes
char data[strlen(dec)-16];
for(int i=16;i<(strlen(dec));i++){
data[i-16]=dec[i];
}
//If necessary adding null to the Key(full 32 bytes)
if(Key.length()< 32){
Key.append(32-Key.length(),'\0');
}
//Creating space for the output
unsigned char *output = new unsigned char[strlen(data)];
//Create and set new AESkey
AES_KEY *aesKey = new AES_KEY;
AES_set_decrypt_key((unsigned char*)Key.c_str(), 256, aesKey);
// key length is in bits, so 32 * 8 = 256
//Deccrypting
AES_cbc_encrypt((unsigned char*)data, output, strlen(data), aesKey,ivec, AES_DECRYPT);
//And there should be full primary string
cout<<"OUTPUT: "<<output<<endl;
}
AES keys are fixed length byte arrays, not variable length strings. When you call AES_set_decrypt_key(), you give it a 13 character long string, with an added null byte, so 14 bytes that we know of. Then the function will use the (32-14) -> 18 remaining bytes for its key. What is the content of these 18 bytes is mostly the result of luck
I suspect that this is your problem.