Thread: EVP_DecryptFinal_ex usage

  1. #1
    Registered User
    Join Date
    Mar 2008
    Location
    India
    Posts
    147

    EVP_DecryptFinal_ex usage

    Hi Team,

    I am trying to use openssl API's for decryption of the key file with password given as argument.

    CLI commands which work fine are as below.

    Below is encode plain text file into encoded one.

    Code:
    openssl aes-256-cbc -salt -in plaintext_file.txt -out encrypted_file.enc -pass pass:111111
    The same encoded one to decrypt.
    Code:
    openssl aes-256-cbc -d -in encrypted_file.enc -out decrypted_file.txt -pass pass:111111

    I tried to use the same "encrypted_file.enc" file and decrypt using the openssl and crypto API's as below and get a plain text file by using below c program.


    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <openssl/conf.h>
    #include <openssl/evp.h>
    #include <openssl/err.h>
    
    void handleErrors(void)
    {
        ERR_print_errors_fp(stderr);
        abort();
    }
    
    int decryptFile(const char *inputFile, const char *outputFile, const char *passphrase)
    {
        OpenSSL_add_all_algorithms();
        ERR_load_crypto_strings();
    
        FILE *inFile = fopen(inputFile, "rb");
        if (!inFile) {
            perror("Error opening input file");
            return 1;
        }
    
        FILE *outFile = fopen(outputFile, "wb");
        if (!outFile) {
            perror("Error opening output file");
            fclose(inFile);
            return 1;
        }
    
        const EVP_CIPHER *cipher = EVP_aes_256_cbc();
        const EVP_MD *digest = EVP_sha256();
    
        unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
    
        if (!EVP_BytesToKey(cipher, digest, NULL, (const unsigned char *)passphrase, strlen(passphrase), 1, key, iv)) {
            perror("Error deriving key and IV");
            fclose(inFile);
            fclose(outFile);
            return 1;
        }
    
        EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
        if (!ctx) {
            perror("Error creating context");
            fclose(inFile);
            fclose(outFile);
            return 1;
        }
    
        if (1 != EVP_DecryptInit_ex(ctx, cipher, NULL, key, iv)) {
            perror("Error initializing decryption");
            EVP_CIPHER_CTX_free(ctx);
            fclose(inFile);
            fclose(outFile);
            return 1;
        }
        EVP_CIPHER_CTX_set_padding(ctx, 0);
    
        unsigned char inBuf[1024], outBuf[1024];
        int bytesRead, decryptedLen;
    
        while ((bytesRead = fread(inBuf, 1, sizeof(inBuf), inFile)) > 0) {
            if (1 != EVP_DecryptUpdate(ctx, outBuf, &decryptedLen, inBuf, bytesRead)) {
                perror("Error updating decryption");
                EVP_CIPHER_CTX_free(ctx);
                fclose(inFile);
                fclose(outFile);
                return 1;
            }
    
            fwrite(outBuf, 1, decryptedLen, outFile);
        }
    
        if (1 != EVP_DecryptFinal_ex(ctx, outBuf, &decryptedLen)) {
            ERR_print_errors_fp(stderr);
            perror("Error finalizing decryption");
            EVP_CIPHER_CTX_free(ctx);
            fclose(inFile);
            fclose(outFile);
            return 1;
        }
    
        fwrite(outBuf, 1, decryptedLen, outFile);
    
        EVP_CIPHER_CTX_free(ctx);
        fclose(inFile);
        fclose(outFile);
    
        return 0;
    }
    
    int main()
    {
        const char *inputFile = "encrypted_file.enc";
        const char *outputFile = "decrypted_file.txt";
        const char *passphrase = "111111";
    
        if (decryptFile(inputFile, outputFile, passphrase) == 0) {
            printf("File decrypted successfully.\n");
        } else {
            fprintf(stderr, "Error decrypting file.\n");
        }
    
        ERR_free_strings();
        return 0;
    }

    When I execute the same, I don't get a plain text file but it's still with some encrypted data I believe.

    content of decrypted_file.txt as below.

    $ cat decrypted_file.txt
    #r▒e▒▒R6e ݌!/▒▒~4f▒>KvC▒▒▒


    Any inputs / leads in this will be very helpfull.

    Thanks
    Last edited by vlrk; 12-25-2023 at 02:21 AM.

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    You asked for salt but didn't supply it to EVP_BytesToKey(). You just passed NULL, which means no salt.
    The salt is stored in the encrypted file as bytes 8 to 15 (the 8 bytes right after Salted__).
    So try something like:
    Code:
        unsigned char salt[8] = {0};
        fread(salt, 1, 8, inFile); // skip Salted__
        fread(salt, 1, 8, inFile); // store next 8 bytes
        if (!EVP_BytesToKey(cipher, digest, salt, (const unsigned char *)passphrase,
                            strlen(passphrase), 1, key, iv)) {
    A little inaccuracy saves tons of explanation. - H.H. Munro

  3. #3
    Registered User
    Join Date
    Mar 2008
    Location
    India
    Posts
    147
    @john.c,

    thanks for inputs.

    I changed the code as you suggested , still it does not gives out the valid decrypted data.

    Not sure , still what I am missing.

    I am updating my latest code in this openssl API Usage - Pastebin.com

    Just to refer again , want to decrypt the file created in this fashion "openssl aes-256-cbc -in plaintext_file.txt -out encrypted_file.enc -pass pass:111111".
    Last edited by vlrk; 12-29-2023 at 08:27 AM.

  4. #4
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    This seems to work for me.
    Code:
    // gcc -std=c11 -Wall decrypt.c -lssl -lcrypto
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <openssl/conf.h>
    #include <openssl/evp.h>
    #include <openssl/err.h>
     
    #define PADDING 16
     
    void handleErrors(void)
    {
        ERR_print_errors_fp(stderr);
        abort();
    }
     
    int decryptFile(const char *inputFile, const char *outputFile, const char *passphrase)
    {
        OpenSSL_add_all_algorithms();
        ERR_load_crypto_strings();
     
        FILE *inFile = fopen(inputFile, "rb");
        if (!inFile) {
            perror("Error opening input file");
            return 1;
        }
     
        FILE *outFile = fopen(outputFile, "wb");
        if (!outFile) {
            perror("Error opening output file");
            fclose(inFile);
            return 1;
        }
     
        unsigned char salt_buf[9] = {0}, *salt = salt_buf;
        fscanf(inFile, "%8s", salt); // skip Salted__
        if (strcmp((char*)salt, "Salted__") == 0)
            fread(salt, 1, 8, inFile); // store next 8 bytes
        else {
            rewind(inFile);
            salt = NULL;
        }
     
        const EVP_CIPHER *cipher = EVP_aes_256_cbc();
        const EVP_MD     *digest = EVP_sha256();
        unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
     
    // int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md,
    //                    const unsigned char *salt,
    //                    const unsigned char *data, int datal, int count,
    //                    unsigned char *key, unsigned char *iv); 
     
        if (!EVP_BytesToKey(cipher, digest, salt, (unsigned char*)passphrase,
                            strlen(passphrase), 1, key, iv)) {
            perror("Error deriving key and IV");
            fclose(inFile);
            fclose(outFile);
            return 1;
        }
     
        EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
        if (!ctx) {
            perror("Error creating context");
            fclose(inFile);
            fclose(outFile);
            return 1;
        }
     
    // int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl,
    //                        const unsigned char *key, const unsigned char *iv);
     
        if (1 != EVP_DecryptInit_ex(ctx, cipher, NULL, key, iv)) {
            perror("Error initializing decryption");
            EVP_CIPHER_CTX_free(ctx);
            fclose(inFile);
            fclose(outFile);
            return 1;
        }
     
        EVP_CIPHER_CTX_set_padding(ctx, PADDING);
     
        unsigned char inBuf[1024], outBuf[sizeof inBuf + PADDING];
        int bytesRead, decryptedLen = 0;
     
        while ((bytesRead = fread(inBuf, 1, sizeof inBuf, inFile)) > 0) {
     
    // int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
    //                       int *outl, const unsigned char *in, int inl);
     
            if (1 != EVP_DecryptUpdate(ctx, outBuf, &decryptedLen, inBuf, bytesRead)) {
                perror("Error updating decryption");
                EVP_CIPHER_CTX_free(ctx);
                fclose(inFile);
                fclose(outFile);
                return 1;
            }
     
            fwrite(outBuf, 1, decryptedLen, outFile);
        }
     
    // int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);
     
        if (1 != EVP_DecryptFinal_ex(ctx, outBuf, &decryptedLen)) {
            ERR_print_errors_fp(stderr);
            perror("Error finalizing decryption");
            EVP_CIPHER_CTX_free(ctx);
            fclose(inFile);
            fclose(outFile);
            return 1;
        }
        
        fwrite(outBuf, decryptedLen, 1, outFile);
     
        EVP_CIPHER_CTX_free(ctx);
        fclose(inFile);
        fclose(outFile);
     
        return 0;
    }
     
    int main()
    {
        const char *inputFile  = "encrypted_file.enc";
        const char *outputFile = "decrypted_file.txt";
        const char *passphrase = "111111";
     
        if (decryptFile(inputFile, outputFile, passphrase) != 0)
            fprintf(stderr, "Error decrypting file.\n");
     
        ERR_free_strings();
     
        return 0;
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

  5. #5
    Registered User
    Join Date
    Mar 2008
    Location
    India
    Posts
    147
    Thanks @jhon.c

    This code is working, one change I made to the encrypt command to use sha256 digest.

    openssl aes-256-cbc -in plaintext_file.txt -out encrypted_file.enc -md sha256 -pass pass:111111

    without this it used to give some error as below

    140023352215472:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:618:
    Error finalizing decryption: No such file or directory
    Error decrypting file.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. VC++ 6 - CPU Usage Help
    By solem1 in forum C Programming
    Replies: 0
    Last Post: 09-08-2009, 11:16 PM
  2. Bit Usage
    By Hypercase in forum C Programming
    Replies: 20
    Last Post: 09-12-2004, 07:40 AM
  3. anyone help me on usage of this
    By black in forum C++ Programming
    Replies: 8
    Last Post: 05-24-2004, 08:25 PM
  4. 99% CPU Usage...
    By napkin111 in forum Game Programming
    Replies: 27
    Last Post: 03-04-2003, 11:37 AM
  5. Usage
    By whistlenm1 in forum C++ Programming
    Replies: 9
    Last Post: 07-10-2002, 11:06 AM

Tags for this Thread