C语言 OpenSSL AES 256 CBC 通过 C 中的 EVP api

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24856303/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 11:14:40  来源:igfitidea点击:

OpenSSL AES 256 CBC via EVP api in C

cencryptioncryptographyopensslaes

提问by Kevin

What I am trying to do:Write a program in C that opens a file of arbitrary size and reads its contents. Once The contents are read it will encrypt them in AES 256 CBC and save the ciphertext to a file called ciphertext. Once this is saved it will close both files. Then will open the cipher text from the file that was just saved and decrypt the cipher text and save it to a file called decrypted.

我想要做的是:用 C 编写一个程序,打开一个任意大小的文件并读取其内容。读取内容后,它将在 AES 256 CBC 中对它们进行加密,并将密文保存到一个名为密文的文件中。保存后,它将关闭这两个文件。然后将从刚刚保存的文件中打开密文并解密密文并将其保存到名为decrypted的文件中。

My Problem:It seems to never decrypt my cipher text. I get garbage, I have no idea what I am doing wrong. Please help.

我的问题:它似乎永远无法解密我的密文。我得到了垃圾,我不知道我做错了什么。请帮忙。

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/aes.h>

void encrypt(FILE *ifp, FILE *ofp)
{
  //Get file size
  fseek(ifp, 0L, SEEK_END);
  int fsize = ftell(ifp);
  //set back to normal
  fseek(ifp, 0L, SEEK_SET);

  int outLen1 = 0; int outLen2 = 0;
  unsigned char *indata = malloc(fsize);
  unsigned char *outdata = malloc(fsize*2);
  unsigned char ckey[] =  "thiskeyisverybad";
  unsigned char ivec[] = "dontusethisinput";

  //Read File
  fread(indata,sizeof(char),fsize, ifp);//Read Entire File

  //Set up encryption
  EVP_CIPHER_CTX ctx;
  EVP_EncryptInit(&ctx,EVP_aes_256_cbc(),ckey,ivec);
  EVP_EncryptUpdate(&ctx,outdata,&outLen1,indata,fsize);
  EVP_EncryptFinal(&ctx,outdata,&outLen2);
  fwrite(outdata,sizeof(char),fsize,ofp);
}

void decrypt(FILE *ifp, FILE *ofp)
{
  //Get file size
  fseek(ifp, 0L, SEEK_END);
  int fsize = ftell(ifp);
  //set back to normal
  fseek(ifp, 0L, SEEK_SET);

  int outLen1 = 0; int outLen2 = 0;
  unsigned char *indata = malloc(fsize);
  unsigned char *outdata = malloc(fsize*2);
  unsigned char ckey[] =  "thiskeyisverybad";
  unsigned char ivec[] = "dontusethisinput";

  //Read File
  fread(indata,sizeof(char),fsize, ifp);//Read Entire File

  //setup decryption
  EVP_CIPHER_CTX ctx;
  EVP_DecryptInit(&ctx,EVP_aes_256_cbc(),ckey,ivec);
  EVP_DecryptUpdate(&ctx,outdata,&outLen1,indata,fsize);
  EVP_DecryptFinal(&ctx,outdata,&outLen2);
  fwrite(outdata,sizeof(char),fsize,ofp);
}

int main(int argc, char *argv[])
{    
  FILE *fIN, *fOUT;

  fIN = fopen("plain.txt", "rb");//File to be encrypted; plain text
  fOUT = fopen("cyphertext.txt", "wb");//File to be written; cipher text    
  encrypt(fIN, fOUT);

  fclose(fIN);
  fclose(fOUT);

  //Decrypt file now
  fIN = fopen("cyphertext.txt", "rb");//File to be written; cipher text
  fOUT = fopen("decrypted.txt", "wb");//File to be written; cipher text
  decrypt(fIN,fOUT);

  fclose(fIN);
  fclose(fOUT);

  return 0;
}

Note: there may be some misspellings. EDIT: Seems Like I made a mistake with the key and IV, both of which are 128 bit and I am trying to use the 256 bit CBC. This was my problem, seems to work once I changed it to

注意:可能有一些拼写错误。编辑:似乎我在密钥和 IV 上犯了一个错误,这两个都是 128 位,我正在尝试使用 256 位 CBC。这是我的问题,一旦我将其更改为

EVP_aes_128_cbc()

回答by President James K. Polk

Here is my version of your code. Naturally I like it better, but I offer it just as an alternative. Note the complete absence of error checking: real code would have it.

这是我的代码版本。自然我更喜欢它,但我提供它只是作为替代。注意完全没有错误检查:真正的代码会有它。

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/aes.h>

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif


/**
 * Encrypt or decrypt, depending on flag 'should_encrypt'
 */
void en_de_crypt(int should_encrypt, FILE *ifp, FILE *ofp, unsigned char *ckey, unsigned char *ivec) {

    const unsigned BUFSIZE=4096;
    unsigned char *read_buf = malloc(BUFSIZE);
    unsigned char *cipher_buf;
    unsigned blocksize;
    int out_len;
    EVP_CIPHER_CTX ctx;

    EVP_CipherInit(&ctx, EVP_aes_256_cbc(), ckey, ivec, should_encrypt);
    blocksize = EVP_CIPHER_CTX_block_size(&ctx);
    cipher_buf = malloc(BUFSIZE + blocksize);

    while (1) {

        // Read in data in blocks until EOF. Update the ciphering with each read.

        int numRead = fread(read_buf, sizeof(unsigned char), BUFSIZE, ifp);
        EVP_CipherUpdate(&ctx, cipher_buf, &out_len, read_buf, numRead);
        fwrite(cipher_buf, sizeof(unsigned char), out_len, ofp);
        if (numRead < BUFSIZE) { // EOF
            break;
        }
    }

    // Now cipher the final block and write it out.

    EVP_CipherFinal(&ctx, cipher_buf, &out_len);
    fwrite(cipher_buf, sizeof(unsigned char), out_len, ofp);

    // Free memory

    free(cipher_buf);
    free(read_buf);
}

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

    unsigned char ckey[] = "thiskeyisverybad";
    unsigned char ivec[] = "dontusethisinput";
    FILE *fIN, *fOUT;

    if (argc != 2) {
        printf("Usage: <executable> /path/to/file/exe");
        return -1;
    }

    // First encrypt the file

    fIN = fopen("plain.txt", "rb"); //File to be encrypted; plain text
    fOUT = fopen("cyphertext.txt", "wb"); //File to be written; cipher text

    en_de_crypt(TRUE, fIN, fOUT, ckey, ivec);

    fclose(fIN);
    fclose(fOUT);

    //Decrypt file now

    fIN = fopen("cyphertext.txt", "rb"); //File to be read; cipher text
    fOUT = fopen("decrypted.txt", "wb"); //File to be written; cipher text

    en_de_crypt(FALSE, fIN, fOUT, ckey, ivec);

    fclose(fIN);
    fclose(fOUT);

    return 0;
}

回答by Kevin

This code works, if anyone has some suggestions as to how it would be cleaner or more efficient please drop a comment.

此代码有效,如果有人对它如何更清洁或更高效有一些建议,请发表评论。

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/aes.h>

void encrypt(FILE *ifp, FILE *ofp)
{
    //Get file size
    fseek(ifp, 0L, SEEK_END);
    int fsize = ftell(ifp);
    //set back to normal
    fseek(ifp, 0L, SEEK_SET);

    int outLen1 = 0; int outLen2 = 0;
    unsigned char *indata = malloc(fsize);
    unsigned char *outdata = malloc(fsize*2);
    unsigned char ckey[] =  "thiskeyisverybad";
    unsigned char ivec[] = "dontusethisinput";

    //Read File
    fread(indata,sizeof(char),fsize, ifp);//Read Entire File

    //Set up encryption
    EVP_CIPHER_CTX ctx;
    EVP_EncryptInit(&ctx,EVP_aes_128_cbc(),ckey,ivec);
    EVP_EncryptUpdate(&ctx,outdata,&outLen1,indata,fsize);
    EVP_EncryptFinal(&ctx,outdata + outLen1,&outLen2);
    fwrite(outdata,sizeof(char),outLen1 + outLen2,ofp);
}

void decrypt(FILE *ifp, FILE *ofp)
{
    //Get file size
    fseek(ifp, 0L, SEEK_END);
    int fsize = ftell(ifp);
    //set back to normal
    fseek(ifp, 0L, SEEK_SET);

    int outLen1 = 0; int outLen2 = 0;
    unsigned char *indata = malloc(fsize);
    unsigned char *outdata = malloc(fsize);
    unsigned char ckey[] =  "thiskeyisverybad";
    unsigned char ivec[] = "dontusethisinput";

    //Read File
    fread(indata,sizeof(char),fsize, ifp);//Read Entire File

    //setup decryption
    EVP_CIPHER_CTX ctx;
    EVP_DecryptInit(&ctx,EVP_aes_128_cbc(),ckey,ivec);
    EVP_DecryptUpdate(&ctx,outdata,&outLen1,indata,fsize);
    EVP_DecryptFinal(&ctx,outdata + outLen1,&outLen2);
    fwrite(outdata,sizeof(char),outLen1 + outLen2,ofp);
}

int main(int argc, char *argv[])
{        
    if(argc != 2){
        printf("Usage: <executable> /path/to/file/exe");
        return -1;
    }
    FILE *fIN, *fOUT;
    fIN = fopen("plain.txt", "rb");//File to be encrypted; plain text
    fOUT = fopen("cyphertext.txt", "wb");//File to be written; cipher text

    encrypt(fIN, fOUT);
    fclose(fIN);
    fclose(fOUT);
    //Decrypt file now
    fIN = fopen("cyphertext.txt", "rb");//File to be written; cipher text
    fOUT = fopen("decrypted.txt", "wb");//File to be written; cipher text
    decrypt(fIN,fOUT);
    fclose(fIN);
    fclose(fOUT);

    return 0;
}

Also According to this post the EVP api will handle an arbitrary sized input

另外根据这篇文章,EVP api 将处理任意大小的输入

AES Encryption- large files

AES 加密 - 大文件