I am working on client-server communications and am stuck on making sure that both sides come up with the same encrypted token value. Cannot figure out why they are different. The keys and initialization vectors along with the message itself are all the same.
Here is the function that does encryption in client code:
int main()
{
try
{
std::string message = "HelloWorld";
while ((message.size() & 0xf) != 0xf)
message += " ";
size_t inputslength = message.length();
unsigned char aes_input[inputslength];
memset(aes_input, 0, inputslength/8);
strcpy((char*) aes_input, message.c_str());
unsigned char iv[] = {'0','f','9','3','8','7','b','3','f','9','4','b','f','0','6','f'};
unsigned char aes_key[] = {'Z','T','k','0','Y','T','U','5','Y','j','N','h','M','j','k','4','N','G','I','3','N','m','I','x','N','W','E','x','N','z','d','i'};
// buffers for encryption and decryption
const size_t encslength = ((inputslength + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
unsigned char enc_out[encslength];
unsigned char dec_out[inputslength];
memset(enc_out, 0, sizeof(enc_out));
memset(dec_out, 0, sizeof(dec_out));
AES_KEY enc_key, dec_key;
AES_set_encrypt_key(aes_key, AES_KEYLENGTH, &enc_key);
AES_cbc_encrypt(aes_input, enc_out, inputslength, &enc_key, iv, AES_ENCRYPT);
AES_set_decrypt_key(aes_key, AES_KEYLENGTH, &dec_key);
AES_cbc_encrypt(enc_out, dec_out, encslength, &dec_key, iv, AES_DECRYPT);
printf("original:\t");
hex_print(aes_input, sizeof(aes_input));
printf("encrypt:\t");
hex_print(enc_out, sizeof(enc_out));
printf("decrypt:\t");
hex_print(dec_out, sizeof(dec_out));
std::stringstream ss;
for(int i = 0; i < encslength; i++)
{
ss << enc_out[i];
}
return 0;
}
}
Output
original: 48 65 6C 6C 6F 57 6F 72 6C 64 20 20 20 20 20
encrypt: 72 70 A2 0D FB A1 65 15 17 97 6E 5D 36 23 E2 FA
decrypt: 0A 73 F7 52 AC C1 68 54 1D CA 7A 1F 70 33 F4
Meanwhile.. on the server:
function encryptToken(token)
{
const iv = '0f9387b3f94bf06f';
const key = 'ZTk0YTU5YjNhMjk4NGI3NmIxNWExNzdi';
console.log("key len: " + key.length);
const encrypt = (value) => {
const cipher = crypto.createCipheriv('AES-256-CBC', key, iv);
let encrypted = cipher.update(value, 'utf8', 'hex');
encrypted += cipher.final('hex');
return encrypted;
};
console.log('Encrypteddd value: ', encrypt('HelloWorld'));
}
Output
Encrypteddd value: 0c491f8c5256b9744550688fc54926e8
Before trying CBC-256 for encryption, I tried the simpler encryption mode, ECB-128 and it all comes down to the same problem. Different encryption tokens produced on client and server side which results in not being able to decrypt what comes from the server side. Any brainstorming tips will help please. I am running out of ideas, thanks.
Update 12.26 -
After taking advice on the init vector and array length on client side.. here is my updated code with output:
int main()
{
try
{
std::string message = "HelloWorld";
while ((message.size() & 0xf) != 0xf)
message += " ";
size_t inputslength = message.length();
unsigned char aes_input[inputslength+1];
memset(aes_input, 0, inputslength/8);
strcpy((char*) aes_input, message.c_str());
unsigned char iv[] = {0x0f, 0x93, 0x87, 0xb3, 0xf9, 0x4b, 0xf0, 0x6f};
unsigned char aes_key[] = {'Z','T','k','0','Y','T','U','5','Y','j','N','h','M','j','k','4','N','G','I','3','N','m','I','x','N','W','E','x','N','z','d','i'};
// buffers for encryption and decryption
const size_t encslength = ((inputslength + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
unsigned char enc_out[encslength];
unsigned char dec_out[inputslength];
memset(enc_out, 0, sizeof(enc_out));
memset(dec_out, 0, sizeof(dec_out));
AES_KEY enc_key, dec_key;
AES_set_encrypt_key(aes_key, AES_KEYLENGTH, &enc_key);
AES_cbc_encrypt(aes_input, enc_out, inputslength, &enc_key, iv, AES_ENCRYPT);
AES_set_decrypt_key(aes_key, AES_KEYLENGTH, &dec_key);
AES_cbc_encrypt(enc_out, dec_out, encslength, &dec_key, iv, AES_DECRYPT);
printf("original:\t");
hex_print(aes_input, sizeof(aes_input));
printf("encrypt:\t");
hex_print(enc_out, sizeof(enc_out));
printf("decrypt:\t");
hex_print(dec_out, sizeof(dec_out));
std::stringstream ss;
for(int i = 0; i < encslength; i++)
{
ss << enc_out[i];
}
return 0;
}
}
//Output:
original: 48 65 6C 6C 6F 57 6F 72 6C 64 00
encrypt: 54 CD 98 20 59 D9 7B 2D D4 23 ED EC D0 13 97 59
Nodejs code has not changed and this remains the output:
Encrypteddd value: 0c491f8c5256b9744550688fc54926e8
So, here's the deal. Every call to AES_cbc_encrypt will change the value of the initialization vector. They do that so that you can chain calls to AES_*_encrypt and handle messages larger than one block. But because the encryption call changes the value of iv, the decryption call is getting a different initialization vector.
One (terrible) solution would be to make two vectors:
unsigned char iv_encrypt[] = { /* stuff */ };
unsigned char iv_decrypt[] = { /* same stuff */ };
That way you'd be passing the same data to each AES_cbc_encrypt call. That would at least show that you can decrypt to the original data. A better, flexible way to achieve your end would be to use a clone of your initialization vector for each call. Something like:
unsigned char iv[] = { /* stuff */ };
unsigned char *tmp_iv = static_cast<unsigned char*>( malloc( sizeof( iv ) ) );
...
memcpy( tmp_iv, iv, sizeof(iv) );
AES_cbc_encrypt(aes_input, enc_out, inputslength, &enc_key, tmp_iv, AES_ENCRYPT);
...
memcpy( tmp_iv, iv, sizeof(iv) );
AES_cbc_encrypt(enc_out, dec_out, inputslength, &dec_key, tmp_iv, AES_DECRYPT);
Related
I'm trying to implement AES using CBC for my application. However the data I'm getting out is different every time I run it. I have been trying to identify the problems using a debugger, but I don't really understand what exactly I'm looking for.
My implementation looks like;
#define AES_KEYLENGTH 256
void NetworkHandler::SendEncryptedPacket(std::vector<std::uint8_t>& data)
{
std::string keyString = "AC3CF1B84D7C946640447DE9670E18BE8A45F49A286FC4D8404DD729491064E4";
std::string ivString = "5D4FB5A040DE76B316794BAC89FC3A48";
printf("noncrypted data: %s\n", data.data());
size_t inputLen = data.size();
size_t encLen = ((inputLen + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
std::vector<std::uint8_t> encOut(encLen);
// Zero out memory for iv & key
std::uint8_t iv[AES_BLOCK_SIZE];
std::uint8_t key[AES_KEYLENGTH];
memset(iv, 0x00, AES_BLOCK_SIZE);
memset(key, 0x00, AES_KEYLENGTH);
std::copy(keyString.begin(), keyString.end(), key);
std::copy(ivString.begin(), ivString.end(), iv);
AES_KEY encKey;
AES_set_encrypt_key(key, AES_KEYLENGTH, &encKey);
AES_cbc_encrypt(data.data(), encOut.data(), encLen, &encKey, iv, AES_ENCRYPT);
printf("encrypted data: %s\n", encOut.data());
SendPacket(encOut);
}
I initially tried to follow the an implemented example found here; AES 256-cbc encryption C++ using OpenSSL.
But looks like I came short.
I came up with this solution.
I'm not sure if it's 100% correct, but I'm getting the same ciphertext each time.
std::vector<std::uint8_t> HexToBytes(const std::string& hexString) {
std::vector<std::uint8_t> byteArray;
for (std::size_t i = 0; i < hexString.size(); i += 2) {
std::string hexByte = hexString.substr(i, 2);
std::uint8_t byte = std::stoi(hexByte, nullptr, 16);
byteArray.push_back(byte);
}
return byteArray;
}
#define AES_KEYLENGTH 256
void NetworkHandler::SendEncryptedPacket(std::vector<std::uint8_t>& data)
{
std::string keyString = "FE7F64F9B5592EDFC84CA5B07DE0901F0671EDB6105FDD5D7C5006C2C10F4ADB";
std::string ivString = "95E060482AD77FB9714DF74150753A37";
printf("noncrypted data: %s\n", data.data());
std::vector<std::uint8_t> encOut(data.size());
auto keyBytes = HexToBytes(keyString);
auto ivBytes = HexToBytes(ivString);
// Zero out memory for iv & key
std::uint8_t iv[AES_BLOCK_SIZE];
std::uint8_t key[AES_KEYLENGTH];
memset(iv, 0x00, AES_BLOCK_SIZE);
memset(key, 0x00, AES_KEYLENGTH);
std::copy(keyBytes.begin(), keyBytes.end(), key);
std::copy(ivBytes.begin(), ivBytes.end(), iv);
AES_KEY encKey;
AES_set_encrypt_key(key, AES_KEYLENGTH, &encKey);
AES_cbc_encrypt(data.data(), encOut.data(), data.size(), &encKey, iv, AES_ENCRYPT);
printf("encrypted data: %s\n", encOut.data());
SendPacket(encOut);
}
I tried the following C implementation of Openssl EVP function for AES-128-CBC encryption but the results I am getting are incorrect compared to the command line OpenSSL result.
I referenced the code on the site below.
https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption
C code implementation of AES-128-CBC:
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>
void handleErrors(void)
{
ERR_print_errors_fp(stderr);
abort();
}
int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
unsigned char *iv, unsigned char *ciphertext)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
handleErrors();
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
handleErrors();
ciphertext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
unsigned char *iv, unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
handleErrors();
if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
handleErrors();
plaintext_len = len;
if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
handleErrors();
plaintext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return plaintext_len;
}
int main (void)
{
/* A 128 bit key */
unsigned char *key = (unsigned char *)"A[u#AD22ZAWm/3=E";
/* A 128 bit IV */
unsigned char *iv = (unsigned char *)"0";
/* Message to be encrypted */
unsigned char *plaintext =
(unsigned char *)"The quick brown fox jumps over the lazy dog";
/*
* Buffer for ciphertext. Ensure the buffer is long enough for the
* ciphertext which may be longer than the plaintext, depending on the
* algorithm and mode.
*/
unsigned char ciphertext[128];
/* Buffer for the decrypted text */
unsigned char decryptedtext[128];
int decryptedtext_len, ciphertext_len;
/* Encrypt the plaintext */
ciphertext_len = encrypt (plaintext, strlen ((char *)plaintext), key, iv,
ciphertext);
/* Do something useful with the ciphertext here */
printf("Ciphertext is:\n");
BIO_dump_fp (stdout, (const char *)ciphertext, ciphertext_len);
/* Decrypt the ciphertext */
decryptedtext_len = decrypt(ciphertext, ciphertext_len, key, iv,
decryptedtext);
/* Add a NULL terminator. We are expecting printable text */
decryptedtext[decryptedtext_len] = '\0';
/* Show the decrypted text */
printf("Decrypted text is:\n");
printf("%s\n", decryptedtext);
return 0;
}
Output:
Ciphertext is:
0000 - 4f 21 68 b5 e9 90 b8 82-71 f2 d2 cd 60 2e fd f1 O!h.....q...`...
0010 - 48 10 d0 e4 f2 58 86 96-22 fa a5 d2 b6 9a 66 87 H....X..".....f.
0020 - e8 e6 bd 9e 73 ad 1e 0e-ec 0a f0 8b 11 83 9d 04 ....s...........
Decrypted text is:
The quick brown fox jumps over the lazy dog
OpenSSL command line:
echo "The quick brown fox jumps over the lazy dog" | openssl enc -e -aes-128-cbc -K 415b7540414432325a41576d2f333d45 -iv 30000000000000000000000000000000 | xxd
Updated WRT suggestion :
echo -n "The quick brown fox jumps over the lazy dog" | openssl enc -e -aes-128-cbc -K 415b7540414432325a41576d2f333d45 -iv 30 | xxd
OpenSSL Output:
00000000: 29d1 cf44 9246 fd7c 48a9 2261 afc1 6b34 )..D.F.|H."a..k4
00000010: ca5c c44d eddd 27a0 d64d 9679 81e4 fcb1 .\.M..'..M.y....
00000020: 9f10 0e47 ef73 37fa 5aa8 1a85 ec70 05c6 ...G.s7.Z....p..
Why are the output results different ( key and iv are both in hex) ?
I understand that the usage of iv "0" isnt recommended.
But if the iv is "0" what should be the hex value considered to match the encryption in command line.
PS : changing IV in code isnt an option for me :(
For my target application I want to use AES multiple times in a row for a given input.
After encrypting it $i$ times in a row it should result in same starting input if decrypting it $i$ times backwards.
Given some example code I already implemented some working solution:
//g++ -o aestest aestest.cpp -lcryptopp
#include <iostream>
#include <iomanip>
#include "cryptopp/modes.h"
#include "cryptopp/aes.h"
#include "cryptopp/filters.h"
#include <cassert>
void dispBA(std::vector<byte> &bav, std::string text =""){
std::cout << text << " : size "<< bav.size() <<" byte"<< std::endl;
for( long unsigned int i = 0; i < bav.size(); i++ ) {
std::cout << std::dec<< (int)((static_cast<byte>(bav[i]))) << ", ";
}
std::cout << std::endl << std::endl;
}
void encryptBV(CryptoPP::CBC_Mode_ExternalCipher::Encryption &cbcEncryption, std::vector<byte> &bytesIn, std::vector<byte> &bytesCrypOut, bool disp=false){
CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::ArraySink( &bytesCrypOut[0],bytesCrypOut.size() ), CryptoPP::StreamTransformationFilter::NO_PADDING );
stfEncryptor.Put( &bytesIn[0], bytesIn.size() );
stfEncryptor.MessageEnd();
if(disp)dispBA(bytesCrypOut, "Cipher numbers");
}
void decryptBV(CryptoPP::CBC_Mode_ExternalCipher::Decryption &cbcDecryption, std::vector<byte> &bytesCrypIn, std::vector<byte> &bytesDecrOut, bool disp=false){
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::ArraySink( &bytesDecrOut[0], bytesDecrOut.size() ), CryptoPP::StreamTransformationFilter::NO_PADDING );
stfDecryptor.Put( &bytesCrypIn[0], bytesCrypIn.size() );
stfDecryptor.MessageEnd();
if(disp)dispBA(bytesDecrOut, "Decrypted numbers");
}
int main(int argc, char* argv[]) {
//Key 32 bytes -> aes256
//block size always 16
const int myKeysize = 32;
byte key[ myKeysize ], iv[ CryptoPP::AES::BLOCKSIZE ];
memset( key, 0x00, myKeysize ); // no key set yet
memset( iv, 0x00, CryptoPP::AES::BLOCKSIZE );
//encryption
std::vector<byte> bytesCryp(myKeysize);
CryptoPP::AES::Encryption aesEncryption(key, myKeysize);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption( aesEncryption, iv );
//decryption
std::vector<byte> bytesDecr(myKeysize);
CryptoPP::AES::Decryption aesDecryption(key, myKeysize);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, iv );
std::vector<byte> bytesIn = {0 ,1, 2, 3, 4, 5 ,6 ,7 ,8 ,9 ,10 ,11, 12, 13 ,14 ,15 ,16, 17, 18 ,19 ,20 ,21 ,22 ,23 ,24 ,25 ,26 ,27 ,28 ,29 ,30,31};
assert(bytesIn.size()== myKeysize);
dispBA(bytesIn, "Starting number");
//-----does work for single en/decryption
// Create Cipher numbers
//encryptBV(cbcEncryption, bytesIn, bytesCryp, true);
// Decrypt
//decryptBV(cbcDecryption, bytesCryp, bytesDecr, true);
int count = 42;
for(int i=0; i < count; i++){
cbcEncryption.SetKeyWithIV(key, myKeysize, iv ); // ++
encryptBV(cbcEncryption, bytesIn, bytesCryp);
cbcEncryption.SetKeyWithIV(key, myKeysize, iv ); // ++
encryptBV(cbcEncryption, bytesCryp, bytesIn);
}
for(int i=0; i<count; i++){
cbcDecryption.SetKeyWithIV(key, myKeysize, iv ); // ++
decryptBV(cbcDecryption, bytesIn, bytesCryp);
cbcDecryption.SetKeyWithIV(key, myKeysize, iv ); // ++
decryptBV(cbcDecryption, bytesCryp, bytesIn);
}
dispBA(bytesIn, "end"); // this does only return the correct value if lines marked with ++ are added
//-----but it does also work if I repeat them without changing the inputs--- ["W2"]
// Create Cipher numbers
//encryptBV(cbcEncryption, bytesIn, bytesCryp, true);
//encryptBV(cbcEncryption, bytesIn, bytesCryp, true);
// Decrypt
//decryptBV(cbcDecryption, bytesCryp, bytesDecr, true);
//decryptBV(cbcDecryption, bytesCryp, bytesDecr, true);
return 0;
}
However currently this only works if I reset the key after every message (or generate new ExternalCipher). I though the key is only changed during the rounds at a single (128,196,256-bit) message (or inside a long) and not continue through messages.
Is there a better way to do this? Or why this happen and does not happen if I don't change the input (see ["W2"])?
Here I found different mode of operation. I guess those are different implementation of AES. Should I use a certain? (edit: ECB? its not supported afaik)
There is no ECB mode listed at crypto++ Modes of Operation but! crypto++ has some shown here with this I can do some small rewrite:
//ecb
void encryptBV(CryptoPP::ECB_Mode< CryptoPP::AES >::Encryption &ecbEncryption, std::vector<byte> &bytesIn, std::vector<byte> &bytesCrypOut, bool disp=false){
CryptoPP::StreamTransformationFilter stfEncryptor(ecbEncryption, new CryptoPP::ArraySink( &bytesCrypOut[0],bytesCrypOut.size() ), CryptoPP::StreamTransformationFilter::NO_PADDING );
stfEncryptor.Put( &bytesIn[0], bytesIn.size() );
stfEncryptor.MessageEnd();
if(disp)dispBA(bytesCrypOut, "Cipher number");
}
void decryptBV(CryptoPP::ECB_Mode< CryptoPP::AES >::Decryption &ecbDecryption, std::vector<byte> &bytesCrypIn, std::vector<byte> &bytesDecrOut, bool disp=false){
CryptoPP::StreamTransformationFilter stfDecryptor(ecbDecryption, new CryptoPP::ArraySink( &bytesDecrOut[0], bytesDecrOut.size() ), CryptoPP::StreamTransformationFilter::NO_PADDING );
stfDecryptor.Put( &bytesCrypIn[0], bytesCrypIn.size() );
stfDecryptor.MessageEnd();
if(disp)dispBA(bytesDecrOut, "Decrypted number");
}
int main(int argc, char* argv[]) {
//Key 32 bytes -> aes256
//block size always 16
const int myKeysize = 32;
byte key[ myKeysize ], iv[ CryptoPP::AES::BLOCKSIZE ];
memset( key, 0x00, myKeysize ); // no key set yet
memset( iv, 0x00, CryptoPP::AES::BLOCKSIZE );
CryptoPP::ECB_Mode< CryptoPP::AES >::Encryption ecbEncryption;
ecbEncryption.SetKey( key, myKeysize);
CryptoPP::ECB_Mode< CryptoPP::AES >::Decryption ecbDecryption;
ecbDecryption.SetKey( key, myKeysize);
std::vector<byte> bytesCryp(myKeysize);
std::vector<byte> bytesDecr(myKeysize);
std::vector<byte> bytesIn = {0 ,1, 2, 3, 4, 5 ,6 ,7 ,8 ,9 ,10 ,11, 12, 13 ,14 ,15 ,16, 17, 18 ,19 ,20 ,21 ,22 ,23 ,24 ,25 ,26 ,27 ,28 ,29 ,30,31};
dispBA(bytesIn, "Starting number");
//test single encrypt, decrypt
encryptBV(ecbEncryption, bytesIn, bytesCryp, true);
decryptBV(ecbDecryption, bytesCryp, bytesDecr, true);
int count = 42;
for(int i=0; i<count; i++){
encryptBV(ecbEncryption, bytesIn, bytesCryp);
encryptBV(ecbEncryption, bytesCryp, bytesIn);
}
for(int i=0; i<count; i++){
decryptBV(ecbDecryption, bytesIn, bytesCryp);
decryptBV(ecbDecryption, bytesCryp, bytesIn);
}
dispBA(bytesIn, "end");
}
It also runs faster (about 60%).
Warning: this is not secure for normal AES usage.
(if someone else found some better way I can change the correct answer)
I have a program that currently seems to run fine on Linux (Ubuntu 14.04), but when running on OS X (10.11.6) I get an abort trap 6. I've attached my code but I suspect the problem is not actually tied to the specific code. This code is for a class project, I'm not actually trying to crack passwords or anything.
Here's the code, I believe the all the important stuff happens in main.
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/conf.h>
#include <openssl/err.h>
#define KEY_BYTES KEY_LENGTH/8
#define KEY_LENGTH 128
unsigned char* h(unsigned char* p, unsigned char* hp);
void handleErrors(void);
int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
unsigned char *iv, unsigned char *ciphertext);
//assumes we've already padded with zeros
unsigned char* h(unsigned char* p, unsigned char *hp){
encrypt((unsigned char*)"0000000000000000", KEY_BYTES, p , (unsigned char*)"0000000000000000", hp);
return hp;
}
void handleErrors(void)
{
printf("panic!!\n");
//ERR_print_errors_fp(stderr); //sg: throw a real error you fool!
abort();
}
//sg: stolen from the evp man page
int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
unsigned char *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, key, iv))
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, plaintext, plaintext_len))
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 main(){
/* Initialise the library */
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);
EVP_CIPHER_CTX *ctx;
unsigned char hp[KEY_BYTES];
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
h((unsigned char*) "1111111111111111", hp);
for(int i = 0; i < KEY_BYTES; i++){
printf("h(%i) = %x\n", i, hp[i]);
}
return 0;
}
When run on linux I get the following (which is what I expect)
h(0) = 10
h(1) = df
h(2) = c1
h(3) = b5
h(4) = f6
h(5) = 6c
h(6) = fd
h(7) = 6a
h(8) = 1d
h(9) = c4
h(10) = 6d
h(11) = 66
h(12) = 90
h(13) = 7b
h(14) = ee
h(15) = b1
However when I run on OS X I get the following:
h(0) = 10
h(1) = df
h(2) = c1
h(3) = b5
h(4) = f6
h(5) = 6c
h(6) = fd
h(7) = 6a
h(8) = 1d
h(9) = c4
h(10) = 6d
h(11) = 66
h(12) = 90
h(13) = 7b
h(14) = ee
h(15) = b1
Abort trap: 6
When I pop this into gdb I get the following
(gdb) r
Starting program: /Users/sgillen/Code/457/proj3/a.out
h(0) = 10
h(1) = df
h(2) = c1
h(3) = b5
h(4) = f6
h(5) = 6c
h(6) = fd
h(7) = 6a
h(8) = 1d
h(9) = c4
h(10) = 6d
h(11) = 66
h(12) = 90
h(13) = 7b
h(14) = ee
h(15) = b1
Program received signal SIGABRT, Aborted.
0x00007fff93150f06 in __pthread_kill () from /usr/lib/system/libsystem_kernel.dylib
(gdb) where
#0 0x00007fff93150f06 in __pthread_kill () from /usr/lib/system/libsystem_kernel.dylib
#1 0x00007fff97b374ec in pthread_kill () from /usr/lib/system/libsystem_pthread.dylib
#2 0x00007fff9ba8077f in __abort () from /usr/lib/system/libsystem_c.dylib
#3 0x00007fff9ba8105e in __stack_chk_fail () from /usr/lib/system/libsystem_c.dylib
#4 0x0000000100000ea9 in main () at gen_table.cpp:90
Not sure how to do line numbers on stack overflow, but line 90 of gen_table.cpp is that last return 0 in main.
I compile my code with the following if that's relevant.
clang -Wall -std=c++11 gen_table.cpp -I/usr/local/opt/openssl/include/ -lcrypto -lssl -g
Any help would be greatly appreciated thank you!
I found the answer to my question I figured I'd post the answer for anyone else who somehow runs into the same problem. The issue was that I was overwriting my own stack. The encryption function I was using was actually writing 32 bytes to hp (which was a 16 byte unsigned char living on the stack). So I'd destroy my own stack but not write to any memory not owned by my process. This resulted in no seg faults but when the program tried to return there were eventually problems. The exact thing that killed me changed depending on how I compiled my code.
I'm actually very surprised valgrind didn't catch this. And I still don't know why it seemed to work fine on linux when compiled with clang (compiled with g++ I got a stack-smashing detected error).
edit:
To be clear the solution was to fix my implementation of encrypt so that it only writes 16 bytes. which I simply did by commenting out the EVP_EncryptFinal_ex call.
How can I encrypt a byte array with Crypto++'s RSA implementation? I already found an example for strings. But I can't find a good example how to do the same for a byte array.
This is my first attempt:
//dataSize: Size of data that is going to be send
//dataToSend Bytes to send to the user
//seedPool is an AutoSeededRandomPool
CryptoPP::RSAES_OAEP_SHA_Encryptor encryptor(publicKey);
int size = 64000;
byte * cipher = new byte(size);
CryptoPP::ArraySink* test = new CryptoPP::ArraySink(cipher, size);
CryptoPP::ArraySource as((byte*)dataToSend, dataSize, true, new CryptoPP::PK_EncryptorFilter(seedPool, encryptor, test));
int newDataSize = test->TotalPutLength();
unsigned int bytesSend = ::send(socketLink, (char *)(cipher), (int)newDataSize, 0);
delete[] cipher;
This doesn't work. TotalPutLength will always return 0 but there is data put in cipher.
What is a safe way to implement this? I don't want to be vulnerable for buffer overflows or any other attack.
byte * cipher = new byte(size);
I believe this should be:
byte * cipher = new byte[size];
Otherwise, I think you get one byte initialized to 6400 (which is truncated to 0x00).
CryptoPP::ArraySink * test = new CryptoPP::ArraySink(cipher, size);
This is kind of different. You can stay out of the memory manager if you'd like:
CryptoPP::ArraySink test(cipher, size);
int newDataSize = test->TotalPutLength();
I've never used TotalPutLength, and I did not see it documented on a BufferedTransformation or Sink. So I don't really have any advice on what its returning.
TotalPutLength is OK to use. An ArraySink could return the wrong value if the sink was full. It would happen if the array was fixed and too small for all the data. We cleared that issue at Crypto++ 5.6.3 or 5.6.4.
If you want to count the number of bytes processed (even if the sink cannot store they bytes), then you can also use a MeterFilter:
byte data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
string encoded;
MeterFilter meter( new StringSink( encoded ) );
ArraySource( data, sizeof( data ), true,
new HexEncoder(
new Redirector( meter ),
true /*UCase*/, 2 /*Group*/,
" " /*Separator*/
)
);
cout << "processed " << meter.GetTotalBytes() << " bytes" << endl;
cout << encoded << endl;
Output:
Processed 23 bytes
00 01 02 03 04 05 06 07
How can you encrypt a byte array with Cryptopp RSA implementation
Now we're talking ;) Try this from the Crypto++ wiki on RSA Encryption.
////////////////////////////////////////////////
// Generate keys
AutoSeededRandomPool rng;
InvertibleRSAFunction params;
params.GenerateRandomWithKeySize( rng, 1536 );
RSA::PrivateKey privateKey( params );
RSA::PublicKey publicKey( params );
string plain="RSA Encryption", cipher, recovered;
////////////////////////////////////////////////
// Encryption
RSAES_OAEP_SHA_Encryptor e( publicKey );
StringSource ss1( plain, true,
new PK_EncryptorFilter( rng, e,
new StringSink( cipher )
) // PK_EncryptorFilter
); // StringSource
////////////////////////////////////////////////
// Decryption
RSAES_OAEP_SHA_Decryptor d( privateKey );
StringSource ss2( cipher, true,
new PK_DecryptorFilter( rng, d,
new StringSink( recovered )
) // PK_DecryptorFilter
); // StringSource
assert( plain == recovered );