I have made an implementation using the OpenSSL library to encrypt a password. I am able to successfully encrypt and decrypt the password using the library in the code.
However, if I try to decrypt the cipher generated by the Library on a linux system on the terminal the decryption fails.
Encryption:
openssl enc -aes-256-cbc -base64 -salt -k <passphrase> -in plain.txt -out
encrypt.txt
Decryption:
openssl enc -aes-256-cbc -base64 -salt -d -k <passphrase> -in encrypt.txt -out plain.txt
Please help.
I have removed salts so as to make the process simpler. I have generated sample base64 ciphers on the terminal and tried decrypting with Library, this fails. I have tried generating sample base64 ciphers with Library and tried decrypting it in the terminal, this fails, too!
size_t init_key_iv(const std::string& pass, const unsigned char* salt, unsigned char* key, unsigned char* iv ) {
size_t derived_key_size = 0;
const unsigned char * pass_key = reinterpret_cast<const unsigned char*>( pass.c_str() );
const size_t pass_key_len = pass.size();
if(salt && key && iv && pass_key && pass_key_len > 0) {
memset(key, 0, sizeof(key));
memset( iv, 0, sizeof(iv));
derived_key_size = EVP_BytesToKey(cipher_type, msg_digest_type, salt, pass_key, pass_key_len, 5, key, iv);
}
return derived_key_size;
}
void encrypt(const unsigned char* msg, unsigned char** encrypted_message, const size_t msg_len, const unsigned char *key, unsigned char *iv) {
AES_KEY enc_key;
AES_set_encrypt_key(key, 256, &enc_key);
AES_cbc_encrypt(msg, *encrypted_message, msg_len, &enc_key, iv, AES_ENCRYPT);
}
void decrypt(const unsigned char* cipher, unsigned char** decrypted_msg, const size_t cipher_len, const unsigned char *key, unsigned char *iv ) {
AES_KEY enc_key;
AES_set_decrypt_key(key, 256, &enc_key);
AES_cbc_encrypt(cipher, *decrypted_msg, cipher_len, &enc_key, iv, AES_DECRYPT);
}
int decode(const char* b64_msg, unsigned char** decode_msg, const size_t decode_msg_len) {
size_t bytes_decoded = 0;
bytes_decoded = EVP_DecodeBlock(*decode_msg, (unsigned char *)b64_msg, strlen(b64_msg));
return bytes_decoded;
}
int encode(const unsigned char* msg, const size_t msg_len, char** b64_msg) {
size_t bytes_encoded = 0;
if(msg && msg_len > 0 && b64_msg) {
bytes_encoded = EVP_EncodeBlock((unsigned char *) *b64_msg, msg, msg_len);
}
return bytes_encoded;
}
const int derived_key_size = init_key_iv(password, salt, key, iv_enc);
encrypt((unsigned char *)msg, &encrypted_message, strlen(msg), key, iv_enc);
const size_t bytes_encoded( encode((const unsigned char*)encrypted_message, strlen(reinterpret_cast<char*>(encrypted_message)), &base64_enc_str) );
const size_t bytes_decoded( CBase64::decode(cipher_base64, &cipher, cipher_len) );
decrypt(cipher, &decrypted_message, cipher_len, key, iv_dec);
Expectation is; the base64 ciphers generated by the Library should be decrypted in the openssl terminal and vice versa.
Your code is not complete, and there are several things not shown which could be wrong, but the things shown that are definitely or probably wrong are:
you call
EVP_BytesToKeywith count=5, when commandlineencuses count=1. In addition you don't show whatcipher_typeandmsg_digest_typeare and they could be wrong; in particular, the default digest used forBytesToKeyin commandlineencvaries depending on the version of OpenSSL, and you didn't say what version(s) you are or will or might be using. Although specifying-md $hashoverrides that default, which is a more robust and clearer solution.you don't show where the plaintext comes from, and in particular whether and how you've padded it. Commandline
encby default uses PKCS5/7 padding, and has an option to use no padding, but in that case the plaintext length must always be an exact multiple of 16 -- have you guaranteed that?you use
strlen(ciphertext)as the length of the (raw = before base64) ciphertext; this is usually wrong. The ciphertext is effectively random bits, and can easily contain a byte with value 0, giving a strlen() that is too small, but if that doesn't happen it will not necessarily be followed or terminated by a 0 byte, giving a strlen() that is too large.you do not include in the base64 encoding the file header (aka 'magic') required by commandline
encwhen using salt. The code shown does not add the line breaks required by commandlineencfile format, but that could be done elsewhere, and only matters if the values you encrypt (and want to decrypt) are or (ever) can be more than 31 bytes.Also, you call
memset (key, 0, sizeof(key))and the same forivwhen they are pointers; this clears only the size of the pointer, 4 or 8 bytes on modern systems, not the object pointed to. But since these objects are promptly overwritten byBytesToKey, this mistake doesn't matter.Anyway, here is a minimal-ish code that is complete and produces an output that is decryptable by commandline
enc -aes-256-cbc -d -a -k $passwordwith-md sha256for versions below 1.1.0 where that is not the default. For convenience I have limited to 80 bytes input, but it should be obvious how to increase that if desired.