Skip to content

Instantly share code, notes, and snippets.

@irbull
Last active July 18, 2023 13:02
Show Gist options
  • Save irbull/c76a8c60e049a9fcba1116aa81771253 to your computer and use it in GitHub Desktop.
Save irbull/c76a8c60e049a9fcba1116aa81771253 to your computer and use it in GitHub Desktop.
#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;
}
@IoanDascal
Copy link

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

@chiraggirdhar95
Copy link

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

@ivan-kovtun
Copy link

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? :)

@faffner1
Copy link

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

@th30c0der
Copy link

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));

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