2

I would like to encrypt the architecture of a neural network, so I could protect the knowledge property of my research.

An example of one of these files, have similar structure as this example.

The code compiles, but I get a runtime error that I don't know how to solve. The error message is digital envelope routines:EVP_DecryptFinal_ex:wrong final block length.

Im using OpenSSL version 1.1.1a 20 Nov 2018

Most relevant includes

#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/err.h> 

Most relevant code for ENCRYPTION

Open and read file to encrypt

std::ifstream in_file(file_name, std::ios::binary);

in_file.seekg(0, in_file.end);
long size = in_file.tellg();
in_file.seekg(0, in_file.beg);

std::vector<unsigned char> binarydata(size);
in_file.read((char*)binarydata.data(), size);
in_file.close();

Encrypt

EVP_CIPHER_CTX *en;
en = EVP_CIPHER_CTX_new();

unsigned char *salt = (unsigned char *)"12345678";
unsigned char *key_data = (unsigned char *)"super_secret_key_with_32_charact";
int k_len = strlen((const char*)key_data);
int nrounds = 5;
unsigned char key[32], iv[32];

EVP_BytesToKey(
        EVP_aes_256_cbc(), EVP_sha1(), 
        salt, 
        key_data, k_len, nrounds, 
        key, iv);

EVP_CIPHER_CTX_init(en);

// I don't know why, but all examples that I have founded, 
// calls this function twice, so I am doing it too.
EVP_EncryptInit_ex(en, EVP_aes_256_cbc(), NULL, key, iv);
EVP_EncryptInit_ex(en, NULL, NULL, NULL, NULL);

int c_len = size + AES_BLOCK_SIZE, f_len = 0;
std::vector<unsigned char> ciphertext(c_len);

EVP_EncryptUpdate(en, ciphertext.data(), &c_len, binarydata.data(), size);
EVP_EncryptFinal_ex(en, ciphertext.data()+c_len, &f_len);
EVP_CIPHER_CTX_free(en)

Write ciphertext to a new file

std::ofstream out_file(output_file, std::ios::binary);
out_file.write((char*)ciphertext.data(), ciphertext.size() * 
sizeof(char));
out_file.close();

Most relevant code for DECRYPTION

Open and read encrypted file

std::ifstream in_file(file_name, std::ios::binary);

in_file.seekg(0, in_file.end);
int size = in_file.tellg();
in_file.seekg(0, in_file.beg);

std::vector<unsigned char> ciphertext(size);
in_file.read((char*)ciphertext.data(), size);
in_file.close();

Decrypt

EVP_CIPHER_CTX *de;
de = EVP_CIPHER_CTX_new();

unsigned char *salt = (unsigned char *)"12345";
unsigned char *key_data = (unsigned char *)"super_secret_key_with_32_charact";
int k_len = strlen((const char*)key_data);
int nrounds = 5;
unsigned char key[32], iv[32];

EVP_BytesToKey(
        EVP_aes_256_cbc(), EVP_sha1(), 
        salt, 
        key_data, k_len, nrounds, 
        key, iv)

EVP_CIPHER_CTX_init(de);

// I don't know why, but all examples that I have founded, 
// calls this function twice, so I am doing it too.
EVP_DecryptInit_ex(de, EVP_aes_256_cbc(), NULL, key, iv);
EVP_DecryptInit_ex(de, NULL, NULL, NULL, NULL);

int p_len = size, f_len = 0;
std::vector<unsigned char> plaintext(p_len);
EVP_DecryptUpdate(de, plaintext.data(), &p_len, ciphertext.data(), size);
EVP_DecryptFinal_ex(de, plaintext.data()+p_len, &f_len);

EVP_CIPHER_CTX_free(de);

return plaintext;

I would like to have some help on how to solve this problem.

Carlos Ost
  • 492
  • 7
  • 22
  • 1
    Suggest removing EVP_EncryptInit_ex(en, NULL, NULL, NULL, NULL). In openssl docs it is not present https://www.openssl.org/docs/man1.0.2/man3/EVP_EncryptFinal_ex.html You should not write to the file ciphertext.size() bytes, but c_len+f_len instead – Oleg Feb 19 '19 at 16:07
  • @Oleg I am using the version 1.1.1 and the manual says it is ok to call this function like I did, but I admit I am just blindly following some examples. I will try to remove it and also try the c_len+f_len you've suggested. I will back here with the results. Regards – Carlos Ost Feb 20 '19 at 14:04
  • `EVP_BytesToKey` is not the best password based key derivation function (PBKDF). But that is made worse if you use SHA-1. I'd replace it with SHA-512 so the result has enough bits to be used for both key and IV. Of course, your salt should not be a static value either; it should be random and included with the ciphertext (e.g. prefixed, it has a constant length, so it is easy to strip off). Preferably the iteration count should be 100K or something similar. An iteration count of 5 makes very little sense, you might as well use the default value for OpenSSL command line: 1. – Maarten Bodewes Feb 20 '19 at 16:44

1 Answers1

0

I don't know if this is still an issue. I had the exact same issue and I solved the problem with adapting the length of the ciphertext after encryption:

EVP_EncryptFinal_ex(en, ciphertext.data()+c_len, &f_len);
ciphertext.erase(ciphertext.begin() + c_len + f_len, ciphertext.end());

With this, the length of ciphertext should be n * AES_BLOCK_SIZE.

Daniel
  • 1
  • 1