Используя openssl в проекте c ++, я выполнял шифрование файлов, используя AES / CB C 128 бит. У меня есть проект java, который выполняет дешифрование файла.
Идея в том, что в c ++ мы будем читать исходный файл фрагментом 4096 байт. Будет выполнять шифрование с использованием функции openssl EVP_CipherUpdate()
, как только мы получим зашифрованный буфер от этой функции, мы запишем IV (из 16 байт) в выходной файл, затем зашифрованный буфер и, наконец, вызвав EVP_CipherFinal()
, мы зашифруем блок (из 16 байт) и запишите это в файл. Этот лог c будет вызываться в while
l oop до достижения EOF.
Таким образом, зашифрованный файл будет иметь 16 байтов (из IV) + 4096 или размер байта (фактический зашифрованный текст). ) + 16 байт (заполнения). Для каждых 4096 (и последних оставшихся) байтов эта структура следует в зашифрованном файле.
Ниже приведена функция, которая выполняет шифрование файлов в c ++ с использованием openssl: (Ссылка от https://medium.com/@amit.kulkarni / encrypting-decrypting-a -file-using-openssl-evp-b26e0e4d28d4 )
void file_encrypt_decrypt(cipher_params_t* params, FILE* ifp, FILE* ofp) {
const size_t BUFSIZE = 4096;
/* Allow enough space in output buffer for additional block */
int cipher_block_size = EVP_CIPHER_block_size(params->cipher_type);
unsigned char in_buf[BUFSIZE];
OPENSSL_assert(cipher_block_size == 16);
unsigned char out_buf[4096+16+16];
int num_bytes_read, out_len;
EVP_CIPHER_CTX* ctx;
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
fprintf(stderr, "ERROR: EVP_CIPHER_CTX_new failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
//cleanup(params, ifp, ofp, ERR_EVP_CTX_NEW);
}
/* Don't set key or IV right away; we want to check lengths */
if (!EVP_CipherInit_ex(ctx, params->cipher_type, NULL, NULL, NULL, params->encrypt)) {
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
//cleanup(params, ifp, ofp, ERR_EVP_CIPHER_INIT);
}
OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == 16);
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == 16);
/* Now we can set key and IV */
if (!EVP_CipherInit_ex(ctx, NULL, NULL, params->key, params->iv, params->encrypt)) {
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
//cleanup(params, ifp, ofp, ERR_EVP_CIPHER_INIT);
}
while(1)
{
// Read in data in blocks until EOF. Update the ciphering with each read.
num_bytes_read = fread(in_buf, sizeof(unsigned char), BUFSIZE, ifp);
if (ferror(ifp)) {
fprintf(stderr, "ERROR: fread error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
//cleanup(params, ifp, ofp, errno);
}
if (!EVP_CipherUpdate(ctx, out_buf, &out_len, in_buf, num_bytes_read)) {
fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
//cleanup(params, ifp, ofp, ERR_EVP_CIPHER_UPDATE);
}
fwrite(params->iv, sizeof(unsigned char), EVP_CIPHER_CTX_iv_length(ctx), ofp);
fflush(ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
//cleanup(params, ifp, ofp, errno);
}
fwrite(out_buf, sizeof(unsigned char), out_len, ofp);
fflush(ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
//cleanup(params, ifp, ofp, errno);
}
/* Now cipher the final block and write it out to file */
if (!EVP_CipherFinal(ctx, out_buf, &out_len)) {
fprintf(stderr, "ERROR: EVP_CipherFinal_ex failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
//cleanup(params, ifp, ofp, ERR_EVP_CIPHER_FINAL);
}
fwrite(out_buf, sizeof(unsigned char), out_len, ofp);
fflush(ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
//cleanup(params, ifp, ofp, errno);
}
if (num_bytes_read < BUFSIZE) {
/* Reached End of file */
break;
}
memset(out_buf, 204, sizeof(out_buf));
memset(in_buf, 204, sizeof(in_buf));
}
EVP_CIPHER_CTX_cleanup(ctx);
}
Здесь cipher_params_t
является структурой:
typedef struct _cipher_params_t {
unsigned char* key;
unsigned char* iv;
unsigned int encrypt;
const EVP_CIPHER* cipher_type;
}cipher_params_t;
В main()
, Мы устанавливаем key
IV
путем генерации случайных ключей. EVP_CIPHER
установлено на EVP_aes_128_cbc()
; Вот основная функция:
int main(int argc, char* argv[])
{
FILE* f_input, * f_enc;
cipher_params_t* params = (cipher_params_t*)malloc(sizeof(cipher_params_t));
/* Key to use for encrpytion and decryption */
unsigned char key[17] = "0123456789abcdef";
/* Initialization Vector */
unsigned char iv[17] = "AAAAAAAAAAAAAAAA";
/* Generate cryptographically strong pseudo-random bytes for key and IV */
//if (!RAND_bytes(key, sizeof(key)) || !RAND_bytes(iv, sizeof(iv))) {
// /* OpenSSL reports a failure, act accordingly */
// fprintf(stderr, "ERROR: RAND_bytes error: %s\n", strerror(errno));
// return errno;
//}
params->key = key;
params->iv = iv;
/* Indicate that we want to encrypt */
params->encrypt = 1;
/* Set the cipher type you want for encryption-decryption */
params->cipher_type = EVP_aes_128_cbc();
/* Open the input file for reading in binary ("rb" mode) */
f_input = fopen("C:\\CMakeCache.txt", "rb");
/* Open and truncate file to zero length or create ciphertext file for writing */
f_enc = fopen("C:\\20161224_143119_DEC.txt", "wb");
/* Encrypt the given file */
file_encrypt_decrypt(params, f_input, f_enc);
/* Encryption done, close the file descriptors */
fclose(f_input);
fclose(f_enc);
/* Free the memory allocated to our structure */
free(params);
return 0;
}
Эта программа работает должным образом и генерирует зашифрованный файл, но когда я расшифровываю, используя JAVA, файл дешифруется, но с некоторыми ненужными символами. В java мы использовали AES/CBC/PKCS5Padding
, и для расшифровки мы также делаем то же самое, из файлового буфера мы сначала читаем 4128 байтов, затем извлекаем 16 байтов (для IV), затем на оставшихся байтах выполняем cipher.doFinal()
. Эта java программа также выполняет расшифровку файла без каких-либо ошибок, но выдает некоторые ненужные символы в расшифрованном файле.
Наблюдения (при копании проблемы):
In дешифрованный файл, после каждых 4096 байтов записывается несколько ненужных символов (ровно 16 байтов). Если мы реализуем шифрование в java, тогда файл расшифровывается в java без мусорных символов. То же самое, если я реализую расшифровку в c ++, то в выходном файле не будет мусорных символов.
Еще раз извините за такой длинный вопрос, я действительно не понимаю, что происходит? Какой процесс помещает ненужные символы в расшифрованный файл, который был зашифрован в c ++?