Cómo resolver el “EVP_DecryptFInal_ex: mal descifrado” durante el descifrado de archivos

11 minutos de lectura

avatar de usuario
Sai

Tengo la siguiente consulta. ¿Alguien podría sugerirme una solución?

Estoy trabajando en el cifrado y descifrado de archivos por primera vez.

He cifrado el archivo a través del símbolo del sistema usando el comando:

openssl enc -aes-256-cbc -in file.txt -out file.enc -k "key value" -iv "iv value"

Tengo que descifrarlo programáticamente. Así que he escrito el programa para ello, pero arroja el siguiente error:

./exe_file enc_file_directory
...
error: 06065064: digital envelope routines: EVP_DecryptFInal_ex: bad decrypt: evp_enc.c

El siguiente programa toma la entrada como ruta de directorio y busca el archivo cifrado “.enc” e intenta descifrarlo y leerlo en el búfer.

Código:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/conf.h>
#include <libxml/globals.h>

void handleErrors(char *msg)
{
    {
        ERR_print_errors_fp(stderr);
        printf("%s", msg);
        abort(); 
    }
}

void freeMemory(char *mem)
{
    if (NULL != mem)
    {
        free(mem);
        mem = NULL;
    }
}

/* Function to decrypt the XML files */

int decryptXML(unsigned char *indata, unsigned char *outdata, int fsize)
{

    int outlen1 = 0, outlen2 = 0;

    unsigned char iv[] = "b63e541bc9ece19a1339df4f8720dcc3";
    unsigned char ckey[] = "70bbc518c57acca2c2001694648c40ddaf19e3b4fe1376ad656de8887a0a5ec2" ;

    if (NULL == indata)
    {
        printf ("input data is empty\n");
        return 0;
    }

    if (0 >= fsize)
    {
        printf ("file size is zero\n");
        return 0;
    }

    outdata = (char *) malloc (sizeof (char) * fsize * 2);

    EVP_CIPHER_CTX ctx;

    EVP_CIPHER_CTX_init(&ctx);

    if (! EVP_DecryptInit_ex (&ctx, EVP_aes_256_cbc(), NULL, ckey, iv))
    {
        EVP_CIPHER_CTX_cleanup(&ctx);
    handleErrors("DInit");
    }

    if (! EVP_DecryptUpdate (&ctx, outdata, &outlen1, indata, fsize))
    {
        EVP_CIPHER_CTX_cleanup(&ctx);
        handleErrors("DUpdate");
    }

    if (! EVP_DecryptFinal_ex (&ctx, outdata + outlen1, &outlen2))
    {

        EVP_CIPHER_CTX_cleanup(&ctx);
        handleErrors("DFinal");
    }

    EVP_CIPHER_CTX_cleanup(&ctx);

    return outlen1+outlen2;

}

int isDirectory(char *path)
{
    DIR *dir = NULL;
    FILE *fin = NULL, *fout = NULL;
    int enc_len = 0, dec_len = 0, fsize = 0, ksize = 0;
    unsigned char *indata = NULL, *outdata = NULL;
    char buff[BUFFER_SIZE], file_path[BUFFER_SIZE], cur_dir[BUFFER_SIZE];

    struct dirent *in_dir;
    struct stat s;

    if (NULL == (dir = opendir(path)))
    {
        printf ("ERROR: Failed to open the directory %s\n", path);
        perror("cannot open.");
        exit(1);
    }

    while (NULL != (in_dir = readdir(dir)))
    {

        if (!strcmp (in_dir->d_name, ".") || !strcmp(in_dir->d_name, ".."))
            continue;

        sprintf (buff, "%s/%s", path, in_dir->d_name);

        if (-1 == stat(buff, &s))
        {
            perror("stat");
            exit(1);
        }

        if (S_ISDIR(s.st_mode))
        {

            isDirectory(buff);
        }
        else
        {
            strcpy(file_path, buff);

            if (strstr(file_path, ".enc"))
            {

                /* File to be decrypted */

                fout = fopen(file_path,"rb"); 

                fseek (fout, 0L, SEEK_END);
                fsize = ftell(fout);
                fseek (fout, 0L, SEEK_SET);

                indata = (char*)malloc(fsize);

                fread (indata, sizeof(char), fsize, fout);

                if (NULL == fout)
                {
                    perror("Cannot open enc file: ");
                    return 1;
                }


                dec_len = decryptXML (indata, outdata, fsize);
                outdata[dec_len] = '\0';
                printf ("%s\n", outdata);
                fclose (fin);
                fclose (fout);

            }
        }
    }



    closedir(dir);
    freeMemory(outdata);
    freeMemory(indata);

    return 1; 
}


int main(int argc, char *argv[])
{
    int result;

    if (argc != 2)
    {
        printf ("Usage: <executable> path_of_the_files\n");
        return -1;
    }

    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();
    OPENSSL_config(NULL);

    /* Checking for the directory existance */

    result = isDirectory(argv[1]);

    EVP_cleanup();
    ERR_free_strings();

    if (0 == result)
        return 1;
    else
       return 0;
}

Gracias.

  • El modo CBC solo brinda confidencialidad y, por lo general, debe agregar una MAC para usar el modo CBC de manera segura. Probablemente debería usar cifrado autenticado porque proporciona ambas cosas confidencialidad y autenticidad. Ver Cifrado y descifrado autenticado por EVP en la wiki de OpenSSL.

    – jww

    16 de diciembre de 2015 a las 6:47

  • Simplifica tu código. Elimine toda la lectura del sistema de archivos. Cifre un archivo e intente descifrar ese archivo. La depuración es mucho más fácil entonces.

    – adlag

    16 de diciembre de 2015 a las 11:37

  • Gracias por la respuesta. ¿Quiso decir que el uso de llamadas al sistema desde el programa?

    – Sai

    17 de diciembre de 2015 a las 6:16

avatar de usuario
Sean Dawson

Este mensaje digital envelope routines: EVP_DecryptFInal_ex: bad decrypt también puede ocurrir cuando cifra y descifra con versiones incompatibles de openssl.

El problema que tenía era que estaba cifrando en Windows que tenía la versión 1.1.0 y luego descifrando en un sistema Linux genérico que tenía 1.0.2g.

¡No es un mensaje de error muy útil!


Solución de trabajo:

Una posible solución de @AndrewSavinykh que funcionó para muchos (ver los comentarios):

El resumen predeterminado ha cambiado entre esas versiones de md5 a sha256. Se puede especificar el resumen predeterminado en la línea de comando como -md sha256 o -md md5 respectivamente

  • Consulte aquí: stackoverflow.com/a/39641378/284111 El resumen predeterminado ha cambiado entre esas versiones de md5 a sha256. Se puede especificar el resumen predeterminado en la línea de comando como -md sha256 o -md md5 respectivamente

    – Andrew Savinykh

    8 de junio de 2017 a las 4:23


  • Acabo de actualizar Kubuntu artful a Kubuntu bionic, que actualizó openssl de 1.0.2g a 1.1.0g y no pude descifrar algunos archivos. El hash predeterminado utilizado por openssl enc para la derivación de clave basada en contraseña cambió en 1.1.0 a SHA256 frente a MD5 en versiones anteriores (fuente). mi solución fue descargar el mayor openssl paqueteforzar la instalación con dpkgdescifrar los archivos, forzar la actualización del openssl paquete del repositorio (usando Synaptic, por ejemplo) y cifre los archivos nuevamente.

    – Stéphane Treboux

    27 de mayo de 2018 a las 11:08


  • @AndrewSavinykh, ponga su comentario como respuesta para que pueda votarlo.

    – Bryan

    26 de junio de 2018 a las 11:03

  • @AndrewSavinykh por favor publíquelo como respuesta. porque es

    – oᴉɹǝɥɔ

    2 de agosto de 2018 a las 17:59

  • ¡Gracias por la respuesta! De todos modos, hay que decirlo: la gente de openssl son unos completos pueblerinos. Este no es un programa de juguete, no es una calculadora o algún juego, en serio… La gente como yo tenemos cosas importantes encriptadas con este programa. Asuntos financieros y legales! Entonces, cuando de repente necesito un documento encriptado hace un par de años y en lugar de un documento, o al menos información “use openssl con la versión X para descifrar”, recibo un estúpido mensaje de “descifrado incorrecto”, es como un ataque al corazón.

    – LLL

    4 de noviembre de 2020 a las 8:46

avatar de usuario
tobias braune

Experimenté una respuesta de error similar mientras usaba la interfaz de línea de comandos de openssl, mientras tenía la clave binaria correcta (-K). La opción “-nopad” resolvió el problema:

Ejemplo generando el error:

echo -ne "\x32\xc8\xde\x5c\x68\x19\x7e\x53\xa5\x75\xe1\x76\x1d\x20\x16\xb2\x72\xd8\x40\x87\x25\xb3\x71\x21\x89\xf6\xca\x46\x9f\xd0\x0d\x08\x65\x49\x23\x30\x1f\xe0\x38\x48\x70\xdb\x3b\xa8\x56\xb5\x4a\xc6\x09\x9e\x6c\x31\xce\x60\xee\xa2\x58\x72\xf6\xb5\x74\xa8\x9d\x0c" | openssl aes-128-cbc -d -K 31323334353637383930313233343536 -iv 79169625096006022424242424242424 | od -t x1

Resultado:

bad decrypt
140181876450560:error:06065064:digital envelope 
routines:EVP_DecryptFinal_ex:bad decrypt:../crypto/evp/evp_enc.c:535:
0000000 2f 2f 07 02 54 0b 00 00 00 00 00 00 04 29 00 00
0000020 00 00 04 a9 ff 01 00 00 00 00 04 a9 ff 02 00 00
0000040 00 00 04 a9 ff 03 00 00 00 00 0d 79 0a 30 36 38

Ejemplo con resultado correcto:

echo -ne "\x32\xc8\xde\x5c\x68\x19\x7e\x53\xa5\x75\xe1\x76\x1d\x20\x16\xb2\x72\xd8\x40\x87\x25\xb3\x71\x21\x89\xf6\xca\x46\x9f\xd0\x0d\x08\x65\x49\x23\x30\x1f\xe0\x38\x48\x70\xdb\x3b\xa8\x56\xb5\x4a\xc6\x09\x9e\x6c\x31\xce\x60\xee\xa2\x58\x72\xf6\xb5\x74\xa8\x9d\x0c" | openssl aes-128-cbc -d -K 31323334353637383930313233343536 -iv 79169625096006022424242424242424 -nopad | od -t x1

Resultado:

0000000 2f 2f 07 02 54 0b 00 00 00 00 00 00 04 29 00 00
0000020 00 00 04 a9 ff 01 00 00 00 00 04 a9 ff 02 00 00
0000040 00 00 04 a9 ff 03 00 00 00 00 0d 79 0a 30 36 38
0000060 30 30 30 34 31 33 31 2f 2f 2f 2f 2f 2f 2f 2f 2f
0000100

Creo que la clave y el IV utilizados para el cifrado mediante la línea de comandos y el descifrado mediante su programa no son los mismos.

Tenga en cuenta que cuando utiliza “-k” (diferente de “-K”), la entrada proporcionada se considera una contraseña de la que se deriva la clave. Generalmente, en este caso, no es necesaria la opción “-iv”, ya que tanto la clave como la contraseña se derivarán de la entrada proporcionada con la opción “-k”.

No está claro a partir de su pregunta, cómo se asegura de que la clave y el IV sean los mismos entre el cifrado y el descifrado.

En mi sugerencia, mejor use la opción “-K” y “-iv” para especificar explícitamente la clave y el IV durante el cifrado y use lo mismo para el descifrado. Si necesita usar “-k”, use la opción “-p” para imprimir la clave y la iv utilizada para el cifrado y use la misma en su programa de descifrado.

Se pueden obtener más detalles en https://www.openssl.org/docs/manmaster/apps/enc.html

  • Gracias Jay. ¡Si! tenía razón, no estaba obteniendo la clave correcta y el valor iv. probó un programa simple con su sugerencia (usando las opciones -K, -iv y -p) y funcionó. Tengo otra consulta aquí. He generado una clave privada usando este comando openssl genrsa -out key.pem 2048 He encriptado un archivo usando esta clave como se muestra a continuación openssl enc -aes-256-cbc -in rand_bytes.c -out rand_bytes.enc -kfile key.pem Ahora la pregunta es, tengo que leer la misma clave para descifrar el archivo usando las API de OpenSSL EVP. ¿Podría sugerirme cómo se puede lograr? Gracias.

    – Sai

    17 de diciembre de 2015 a las 6:17


  • @Sai: Si esto respondió a su pregunta en particular, márquelo como la respuesta para este hilo. La otra respuesta es útil por una razón diferente, pero al marcarla como la respuesta a su problema específico, aclara que este hilo no es un duplicado del vinculado en la otra respuesta.

    – subrayado_d

    1 de agosto de 2017 a las 11:03

Errores: “Cifrado/descifrado incorrecto” “gitencrypt_smudge: FALLO: error de openssl al descifrar el archivo”

Hay varias cadenas de error que se lanzan desde openssl, según las respectivas versiones y escenarios. A continuación se muestra la lista de verificación que utilizo en caso de problemas relacionados con openssl:

  1. Idealmente, openssl puede cifrar/descifrar usando la misma clave (+ sal) y algoritmo enc solamente.
  2. Asegúrese de que las versiones de openssl (utilizadas para cifrar/descifrar) sean compatibles. Por ej. el hash utilizado en openssl cambió en la versión 1.1.0 de MD5 a SHA256. Esto produce una clave diferente de la misma contraseña. Solución: agregue “-md md5” en 1.1.0 para descifrar datos de versiones inferiores y agregue “-md sha256 en versiones inferiores para descifrar datos de 1.1.0

  3. Asegúrese de que haya una sola versión de openssl instalada en su máquina. En caso de que haya múltiples versiones instaladas simultáneamente (en mi máquina, estas fueron instaladas: – ‘LibreSSL 2.6.5’ y ‘openssl 1.1.1d’), asegúrese de que solo la deseada aparezca en su variable PATH.

Este mensaje también puede ocurrir cuando especifica el contraseña de descifrado incorrecta (sí, lamentable, pero no tan obvio darse cuenta de esto a partir del mensaje de error, ¿eh?).

Estaba usando la línea de comando para descifrar la copia de seguridad reciente de DataBase para mi herramienta auxiliar y de repente me encontré con este problema.

Finalmente, después de 10 minutos de dolor y además de leer estas preguntas/respuestas, recordé que la contraseña es diferente y todo funcionó bien con la contraseña correcta.

  • Este fue mi caso. ¡Contraseña incorrecta!

    –Obinna Nnenanya

    28 de abril de 2020 a las 4:38

  • Este es mi caso también! ¡Definitivamente debería ser lo PRIMERO que uno verifique para este problema!

    – usuario1944491

    13 de mayo de 2021 a las 14:08

avatar de usuario
Digvijay Chougale

Mi caso, el servidor estaba encriptando con el relleno deshabilitado. Pero el cliente estaba tratando de descifrar con el relleno habilitado.

Al usar EVP_CIPHER*, el relleno está habilitado de manera predeterminada. Para deshabilitar explícitamente tenemos que hacer

EVP_CIPHER_CTX_set_padding(context, 0);

Por lo tanto, las opciones de relleno que no coinciden pueden ser una de las razones.

  • Este fue mi caso. ¡Contraseña incorrecta!

    –Obinna Nnenanya

    28 de abril de 2020 a las 4:38

  • Este es mi caso también! ¡Definitivamente debería ser lo PRIMERO que uno verifique para este problema!

    – usuario1944491

    13 de mayo de 2021 a las 14:08

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad