Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <string.h>
#include <iostream>
using namespace std;
void handleOpenSSLErrors(void)
{
ERR_print_errors_fp(stderr);
abort();
}
string decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
unsigned char *iv ) {
EVP_CIPHER_CTX *ctx;
unsigned char *plaintexts;
int len;
int plaintext_len;
unsigned char* plaintext = new unsigned char[ciphertext_len];
bzero(plaintext,ciphertext_len);
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleOpenSSLErrors();
/* Initialise the decryption 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_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
handleOpenSSLErrors();
EVP_CIPHER_CTX_set_key_length(ctx, EVP_MAX_KEY_LENGTH);
/* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
handleOpenSSLErrors();
plaintext_len = len;
/* Finalise the decryption. Further plaintext bytes may be written at
* this stage.
*/
if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleOpenSSLErrors();
plaintext_len += len;
/* Add the null terminator */
plaintext[plaintext_len] = 0;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
string ret = (char*)plaintext;
delete [] plaintext;
return ret;
}
void initAES(const string& pass, unsigned char* salt, unsigned char* key, unsigned char* iv )
{
bzero(key,sizeof(key));
bzero(iv,sizeof(iv));
EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, (unsigned char*)pass.c_str(), pass.length(), 1, key, iv);
}
size_t calcDecodeLength(char* b64input) {
size_t len = strlen(b64input), padding = 0;
if (b64input[len-1] == '=' && b64input[len-2] == '=') //last two chars are =
padding = 2;
else if (b64input[len-1] == '=') //last char is =
padding = 1;
return (len*3)/4 - padding;
}
void Base64Decode( char* b64message, unsigned char** buffer, size_t* length) {
BIO *bio, *b64;
int decodeLen = calcDecodeLength(b64message);
*buffer = (unsigned char*)malloc(decodeLen + 1);
(*buffer)[decodeLen] = '\0';
bio = BIO_new_mem_buf(b64message, -1);
b64 = BIO_new(BIO_f_base64());
bio = BIO_push(b64, bio);
//BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer
*length = BIO_read(bio, *buffer, strlen(b64message));
BIO_free_all(bio);
}
int main (void)
{
// This is the string Hello, World! encrypted using aes-256-cbc with the
// pasword 12345
char* ciphertext_base64 = (char*) "U2FsdGVkX1/E/yWBwY9nW96pYIv2nouyJIFF9BtVaKA=\n";
int decryptedtext_len, ciphertext_len;
size_t cipher_len;
unsigned char* ciphertext;
unsigned char salt[8];
ERR_load_crypto_strings();
Base64Decode(ciphertext_base64, &ciphertext, &cipher_len);
unsigned char key[32];
unsigned char iv[32];
if (strncmp((const char*)ciphertext,"Salted__",8) == 0) {
memcpy(salt,&ciphertext[8],8);
ciphertext += 16;
cipher_len -= 16;
}
initAES("12345", salt, key, iv);
string result = decrypt(ciphertext, cipher_len, key, iv);
cout << result << endl;
// Clean up
EVP_cleanup();
ERR_free_strings();
return 0;
}
@tahazayed

This comment has been minimized.

Copy link

@tahazayed tahazayed commented Sep 12, 2017

there is a memory leak in this line 83:
buffer = (unsigned char)malloc(decodeLen + 1);

@ajgale

This comment has been minimized.

Copy link

@ajgale ajgale commented Oct 25, 2017

In relation to resolving that memory leak mentioned in the above comment:

Because the pointer to the start of ciphertext is moved in line 112:
ciphertext += 16;
you should first get a pointer to the start of the buffer which you can free during cleanup(unless you like segfaults):
unsigned char *ciphertext_start = ciphertext;
...then do strncmp and increment as above...
// Clean up
free(ciphertext_start);

@hmimyou

This comment has been minimized.

Copy link

@hmimyou hmimyou commented Jan 19, 2018

Be careful about line 70 as well. It bite me in the way that sometimes the bytes loaded from ifstream doesn't have \0 in the next position of the char *, and line 70 will get wrong len. This can randomly fail the decryption, with errors:

140735847007112:error:0607A082:digital envelope routines:EVP_CIPHER_CTX_set_key_length:invalid key length:evp_enc.c:595:
140735847007112:error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length:evp_enc.c:520:

The fix can be either explicitly pass the char * length to calcDecodeLength, or explicitly set \0 at the end of char * you pass in to calcDecodeLength.

@IoanDascal

This comment has been minimized.

Copy link

@IoanDascal IoanDascal commented Sep 28, 2018

I am trying to use this example in Visual Studio 2017 and I have error: identifier "bzero" is undefined

@chiraggirdhar95

This comment has been minimized.

Copy link

@chiraggirdhar95 chiraggirdhar95 commented May 15, 2019

Can anyone help how to implement multi-threaded implementation of decryption as shown above in AES CTR mode?

@ivan-kovtun

This comment has been minimized.

Copy link

@ivan-kovtun ivan-kovtun commented Jul 5, 2020

It is something wrong with initAES, when I use a password with only digits it works fine. But if it contains alphabetic symbols the key do not coincide with one I get in the openssl console.

openssl> openssl enc -aes-256-cbc -salt -S 5916B816382EF103 -md sha1 -P -k passwd
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
salt=5916B816382EF103
key=75CCC0851F84CD60CD45C57842280EB3B7A16F50D6868B4CDF38193CF545B947
iv =CFE8EF5C363C4C6B26773B7EE13D19B0

		TEST_METHOD(GetKeyForAlphabeticPwd)
		{
			aes256cbc* obj = new aes256cbc();
			unsigned char* salt = NULL;
			size_t salt_len = 0;
			unsigned char* key = new unsigned char[AES_KEY_SIZE + 1];
			unsigned char* iv = new unsigned char[AES_KEY_SIZE + 1];
			obj->Base64Decode("5916B816382EF103\n", &salt, &salt_len);
			obj->initAES(std::string("passwd"), salt, key, iv);
			unsigned char* etalon = NULL;
			size_t etalon_len = 0;
			obj->Base64Decode("75CCC0851F84CD60CD45C57842280EB3B7A16F50D6868B4CDF38193CF545B947\n", &etalon, &etalon_len);
			char* keyData = OPENSSL_buf2hexstr(key, AES_KEY_SIZE);  // can see hex in debuger
			int res = std::string((char*)key)
				.compare((char*)etalon);
			Assert::AreEqual(res, 0);
			delete[] key;
			delete[] iv;
			delete obj;

			OPENSSL_free(keyData);
		}

Can somebody help? :)

@ashraful1980

This comment has been minimized.

Copy link

@ashraful1980 ashraful1980 commented Aug 5, 2020

Sir,
I have encrypted key along with Salt & Passphrase Hashed. How to decrypt the hash any guideline.

Bellow information only for sample; it is already decrypt:
Master Key 1: 0xc1ce586fcbd57a0dd60a1b08a65a3fad9269f788d7bcecd411d95cc222c9f0cdf7ebfc6fa33847607f7b8c1338a2c3f8,
Salt: 0x10cb87989a39ef71. Passphrase hashed 60692 times with method 0 with other parameters 0x
Bitcoin Wallet Address: 17bqkPW21QhRUBcUQiy3C99ZC6L52Utu1b

Please help me i will great full to your cooperation.

Thanks & Regards,
Md. Ashraful Alam

@faffner1

This comment has been minimized.

Copy link

@faffner1 faffner1 commented Nov 22, 2020

I need help how to decrypt key from my wallet.dat,with cpp files,from bitcoin library,I have several wallet.dat,write PM please

@Mose3c

This comment has been minimized.

Copy link

@Mose3c Mose3c commented Jan 26, 2021

I am trying to use this example in Visual Studio 2017 and I have error: identifier "bzero" is undefined

You can use memset(var , 0 , sizeof(var));

@ashraful1980

This comment has been minimized.

Copy link

@ashraful1980 ashraful1980 commented Jan 26, 2021

After compile and run it is error

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment