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.
Related
I have a simple program that encrypts files in a directory. I can iterate through and everything works perfectly. This is using pub/priv key pair. When decrypting one file at a time, it works as it should. However, if there are multiple files in a directory, or even if I put the filenames in a vector and fopen them for reading/writing respectively, it ONLY decrypts the LAST file in the vector/directory. How is this even possible? It fails on everyone of them on OpenFinal(). Here is the function and heart of the program. Everything else is solid. As stated, it works as a standalone program if I just decrypt one file manually or if there is just ONE file in the directory or vector.
Any help would be appreciated. This makes no sense at all. It seems like an implementation issue on their end.
void handleErrors(void)
{
// perror("Error: ");
ERR_print_errors_fp(stderr);
abort();
}
int envelope_open(EVP_PKEY *priv_key, unsigned char *ciphertext,
int ciphertext_len, unsigned char *encrypted_key,
int encrypted_key_len, unsigned char *iv,
unsigned char **plaintext, int *plaintext_len)
{
EVP_CIPHER_CTX *ctx;
int len = 0, ret = 0;
unsigned char *tmpptxt = NULL;
if((ctx = EVP_CIPHER_CTX_new()) == NULL)
return 0;
if ((tmpptxt = (unsigned char*)malloc(ciphertext_len)) == NULL)
{
printf("tmptxt error!\n");
handleErrors();
}
if(EVP_OpenInit(ctx, EVP_aes_256_cbc(), encrypted_key, encrypted_key_len,
iv, priv_key) != 1)
{
printf("OpenInit error\n");
handleErrors();
}
if(EVP_OpenUpdate(ctx, tmpptxt, &len, ciphertext, ciphertext_len) != 1)
{
printf("OpenUpdate error\n");
handleErrors();
}
*plaintext_len = len;
if(EVP_OpenFinal(ctx, tmpptxt + len, &len) != 1)
{
printf("OpenFinal error\n");
handleErrors();
}
*plaintext_len += len;
*plaintext = tmpptxt;
tmpptxt = NULL;
ret = 1;
err:
EVP_CIPHER_CTX_free(ctx);
free(tmpptxt);
return ret;
}
I was overwriting the key and iv returned from envelope_seal(). I looked over the fact it was unique. Each file must have this key and iv along with the private key and passphrase on the key to be able to decrypt a file. So this is definitely secure ... until someone cracks AES 256 of course.
I recently started a small side-project to recreate the Minecraft Server in C++ but I stumbled on a problem.
I need to use the AES/CFB8 Cipher according to this link with continuous updating (not finished and restarted every packet).
I surfed trough the internet to try to find a proper solution but could not figure out one that was actually working or it was using the command line interface.
Any help is welcomed !
Cipher.h
class Cipher {
public:
enum CipherType {
ENCRYPT,
DECRYPT
};
private:
EVP_CIPHER_CTX* ctx;
CipherType type;
bool hasFinished;
public:
Cipher(const char* key, const char* iv, CipherType type);
~Cipher();
int update(char* in, int inl, char* out);
int final(char* out);
int getMinimumBufLength(int size);
};
Cipher.cpp
Cipher::Cipher(const char* key, const char* iv, CipherType type) : type(type), hasFinished(false)
{
ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ctx);
if(type == CipherType::ENCRYPT)
EVP_EncryptInit_ex(ctx, EVP_aes_256_cfb8(), nullptr, (unsigned char*)key, (unsigned char*)iv);
else
EVP_DecryptInit_ex(ctx, EVP_aes_256_cfb8(), nullptr, (unsigned char*)key, (unsigned char*)iv);
}
Cipher::~Cipher()
{
EVP_CIPHER_CTX_free(ctx);
}
int Cipher::getMinimumBufLength(int size)
{
return type == CipherType::DECRYPT ? size : size + AES_BLOCK_SIZE * 2;
}
int Cipher::update(char* in, int inl, char* out)
{
int len;
EVP_CipherUpdate(ctx, (unsigned char*)out, &len, (unsigned char*)in, inl);
return len;
}
int Cipher::final(char* out)
{
int len;
EVP_EncryptFinal_ex(ctx, (unsigned char*)out, &len);
return len;
}
Cipher-test.cpp
TEST_CASE("Cipher AES/CFB8")
{
char* key = "AAAAAAAAAZEFRGUINJFKDFIVJ";
char* iv = "AUJVFEUB";
Cipher encryptionCipher(key, iv, Cipher::CipherType::ENCRYPT);
Cipher decryptionCipher(key, iv, Cipher::CipherType::DECRYPT);
std::string data = "Hello World ! This is some soon to be encrypted string !";
char encData[encryptionCipher.getMinimumBufLength(data.size() + 1)];
int outLen = encryptionCipher.update(data.data(), data.size() + 1, encData);
int fLen = encryptionCipher.final(encData + outLen);
CHECK(data != std::string(encData));
char decData[decryptionCipher.getMinimumBufLength(outLen + fLen)];
outLen = decryptionCipher.update(encData, outLen + fLen, decData);
decryptionCipher.final(decData + outLen);
CHECK(data == std::string(decData));
}
Thanks in advance
EDIT: I am just wondering if there was a need for supplementary code because of the "continuous" aspect of the Cipher.
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?
I have been asked to create a checksum algorithm for a file transfer, the C++ code I have been given is as follows:
// ChecksumTestTool.cpp : Defines the entry point for the console
application.
//
#include "stdafx.h"
#include <string>
#include <stdio.h>
#include <iostream>
unsigned long CalculateChecksum(FILE* pFile);
int main(int argc, char *argv[])
{
int result = 0;
//Get filename from command args
std::string fileName;
if (argc >= 1)
{
fileName = argv[0];
//Open file with read access
FILE* pFile = nullptr;
int error = fopen_s(&pFile, fileName.c_str(), "r");
if (error != 0 || pFile == nullptr)
{
printf("Failed to open file with error %d\r\n", error);
result = -1;
}
else
{
//Calculate the checksum
unsigned long checksum = CalculateChecksum(pFile);
printf("Calculated Checksum for %s is %lu (0x%04X)\r\n",
fileName.c_str(), checksum, checksum);
}
}
else
{
printf("Must enter filename on command line\r\n");
result = -1;
}
//Wait here so we can see result
printf("\r\nPress Any Key to Exit\r\n");
getchar();
return 0;
}
unsigned long CalculateChecksum(FILE* pFile)
{
unsigned long checksum = 0;
//TODO:: Calculate the checksum
return checksum;
}
I need to create the checksum at the point '//TODO:: Calculate the checksum'. The algorithm need to check whether the file transfers or not.
So far I have tried:
unsigned long CalculateChecksum(FILE* pFile)
{
unsigned long checksum = 0;
//TODO:: Calculate the checksum
unsigned long word = 0;
while (file.read(reinterpret_cast<char*>(&word), sizeof(word))); {
checksum += word;
}
if (file.gcount()); {
word &= (~0U >> ((sizeof(unsigned long) - file.gcount()) * 8));
checksum += word;
}
return checksum;
}
and I get errors saying 'file' is an undeclared identifier and that left '.gcount' must have class/struct/union
I have searched around for multiple checksums and this algorithm is the only one I found that works within this code
Some things:
you pass a variable called pFile to the function, within the function you use file.
You use if(expression);, therefore the part after the if will always be executed, as the if() has no influence whatsoever.
I didn't even consider whether the checksum function works, but when you do
if(term);
{
// Do something
}
the Do something will always be reached. It should rather be
if (term)
{
// Do something
}
so it will only do it if the term evaluates true
I have a problem, when i use http://slproweb.com/products/Win32OpenSSL.html , i try to Init Encryption, but always catch error like
"OpenSSL assertion failed, evp_enc.c(282)"
Can somebody help me with this matter?
My code:
bool do_encrypt(const char *in, unsigned char *out, int *outlen, unsigned char *key, unsigned char *iv)
{
int buflen, tmplen;
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_EncryptInit_ex(&ctx, EVP_rc4(), NULL, key, iv);
if(!EVP_EncryptUpdate(&ctx, out, &buflen, (unsigned char*)in, strlen(in))) // error here
{
return false;
}
if(!EVP_EncryptFinal_ex(&ctx, out + buflen, &tmplen))
{
return false;
}
buflen += tmplen;
*outlen = buflen;
EVP_CIPHER_CTX_cleanup(&ctx);
return true;
}
I use key for test {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, iv is NULL.
Code that uses this function above:
int WINAPI OwnSend(SOCKET s, const char FAR *buff, int len, int flags )
{
if(s == ServerSocket)
{
if(len > 0)
{
int outlen;
unsigned char EncryptBuffer[5500];
do_encrypt(buff, EncryptBuffer, &outlen, KeyTest, NULL);
buff = (const char *) EncryptBuffer;
return pTrampolineSend(s, buff, outlen, flags);
}
}
return pTrampolineSend(s, buff, len, flags);
}
Thanks!
The only assertion in EVP_EncryptUpdate is one that asserts that the buffer length is less than or equal to the block size of the encryption algorithm.
Instead of calling strlen(in) as the size of your input, try looping EVP_EncryptUpdate and each time you go through, make sure to limit the input size with:
int in_size_limit = EVP_CIPHER_CTX_block_size(&ctx);
While looping, be sure to increment the offset of the 2nd and 4th args by the number of bytes you've already encrypted:
if ( EVP_EncryptUpdate(&ctx,
out+encrypted_bytes,
&bytes_encrypted_this_call,
in+encrypted_bytes,
in_size_limit) != 1)
{
/* error */
}
else
{
encrypted_bytes += bytes_encrypted_this_call;
}