-
-
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; | |
| } |
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);
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.
I am trying to use this example in Visual Studio 2017 and I have error: identifier "bzero" is undefined
Can anyone help how to implement multi-threaded implementation of decryption as shown above in AES CTR mode?
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? :)
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
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));
there is a memory leak in this line 83:
buffer = (unsigned char)malloc(decodeLen + 1);