文件AES对称加密-openssl命令和C代码实现

        前两天发布了《字符串AES对称加密》的博文,虽然很相似,但还是觉得有必要介绍下如何对文件进行AES对称加密、解密。文件加密实际就是读出文件内容,再进行字符串加密

        还是分别用openssl命令C语言方式实现相同的AES对称加、解密功能

准备工作:新建文件 file_in.txt,内容随意,我在文件里输入的 "123456"。

一、openssl命令对文件AES对称加密、解密

1、使用OpenSSL命令对文件加密

$ openssl aes-256-cbc -e -nosalt -in file_in.txt -out file_cmd_en.txt -pass pass:aes_password

  • -aes-256-cbc:使用AES算法的256位密钥和CBC模式;
  • -e:加密操作;(-d 表示解密)
  • -nosalt:不使用盐值。在AES-CBC模式中,盐值通常是随机生成的,以增加密钥的强度。
  • -in:表示输入文件,后面应该紧跟输入文件的文件名
  • -out:表示输出文件,后面应该紧跟输出文件的文件名。
  • -pass pass:<password> 指定了加密的密钥

file_in.txt文件加密(没有使用base64编码)生成加密文件 file_cmd_en.txt,内容如图:

2、使用OpenSSL命令对文件解密

$ openssl aes-256-cbc -d -nosalt -in file_cmd_en.txt -out file_cmd_de.txt -pass pass:aes_password

将加密文件 file_cmd_en.txt 解密,生成 file_cmd_de.txt ,内容与加密前的文件相同。

二、C语言对文件进行AES对称加密、解密

代码下载链接:https://download.csdn.net/download/hinewcc/89212904

1、代码介绍

openssl_aes.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <error.h>
#include <fcntl.h>
#include "openssl_aes.h"

#define SIZE 2048

/*
*****************************************************************************************
*	函 数 名: aes_encrypt_file
*	功能说明: AES加密文件
*	形    参:   _pPassword  :   密码
*               _pInfile    :   输入需要加密的文件路径
*               _pOutfile   :   加密后生成的文件
*	返 回 值: 0:成功, -1:失败
*****************************************************************************************
*/
int aes_encrypt_file(char *_pPassword, char *_pInfile, char *_pOutfile)
{
    EVP_CIPHER_CTX *pEn_ctx;
    int inFile, outFile;
    int inlen = 0, flen = 0, outlen = 0;
    int i, nrounds = 1;
    unsigned char key[32], iv[32];
    char inbuf[SIZE + AES_BLOCK_SIZE] = {0};
    char outbuf[SIZE + AES_BLOCK_SIZE] = {0};
    const EVP_CIPHER *cipherType = EVP_aes_256_cbc();

    if (_pPassword == NULL || _pInfile == NULL || _pOutfile == NULL) {
        return -1;
    }

    /* 打开文件 */
    if ((inFile = open((char *)_pInfile, O_RDONLY)) <0) {                  //打开输入文件
        perror("ERROR, Infile path not exist:");
        return -1;
    }

    if ((outFile = open(_pOutfile, O_CREAT|O_RDWR, 0400|0200)) <0) {       //创建输出文件
        perror("ERROR, CANT create _pOutfile file:");
        close(inFile);
        return -1;
    }

    /*
    * Gen key & IV for AES 256 CBC mode. A SHA1 digest is used to hash the supplied key material.
    * nrounds is the number of times the we hash the material. More rounds are more secure but
    * slower.
    */
    i = EVP_BytesToKey(cipherType, EVP_md5(), NULL, _pPassword, strlen(_pPassword), nrounds, key, iv);  //输入密码产生了密钥key和初始化向量iv
    if (i != 32) {
        printf("Key size is %d bits - should be 256 bits\n", i);
        goto aes_err;
    }

    pEn_ctx = EVP_CIPHER_CTX_new();                             //创建加密上下文

    EVP_CIPHER_CTX_init(pEn_ctx);                               //初始化 EVP_CIPHER_CTX 上下文
    EVP_EncryptInit_ex(pEn_ctx, cipherType, NULL, key, iv);     //初始化加密操作


    while ((inlen = read(inFile, inbuf, SIZE)) > 0) {
        printf("file data: %s, len: %d\n", inbuf, inlen);
        
        /* Update cipher text */
        if (!EVP_EncryptUpdate(pEn_ctx, (unsigned char*)outbuf, &outlen,(unsigned char*) inbuf, inlen)) {                                      //加密操作
            perror("\n Error,ENCRYPR_UPDATE:");
            goto aes_err;
        }
        if (write(outFile, outbuf, outlen) != outlen) {                     //数据写入输出文件
            perror("\n Error,Cant write encrypted bytes to outfile:");
            goto aes_err;
        }
        break;
    }

    if (!EVP_EncryptFinal_ex(pEn_ctx, (unsigned char*)outbuf, &flen)) {      //完成加密操作,处理剩余字节
            perror("\n Error,ENCRYPT_FINAL:");
            goto aes_err;
    }

    if (write(outFile, outbuf, flen) != flen) {                             //剩余数据写入输出文件
        perror("\n Error,Wriring final bytes of data:");
        goto aes_err;
    }

    EVP_CIPHER_CTX_cleanup(pEn_ctx);

aes_err:
    close(inFile);
    close(outFile);

    return 0;               /* SUCCESS */
}

/*
*****************************************************************************************
*	函 数 名: aes_decrypt_file
*	功能说明: 文件AES解密
*	形    参:   _pPassword  :   密码
*               _pInfile    :   输入需要解密的文件路径
*               _pOutfile   :   解密后生成的文件
*	返 回 值: 0:成功, -1:失败
*****************************************************************************************
*/
int aes_decrypt_file(char *_pPassword, char *_pInfile, char *_pOutfile)
{
    EVP_CIPHER_CTX *pDe_ctx;
    int inFile, outFile;
    int inlen = 0, flen = 0, outlen = 0;
    int i, nrounds = 1;
    unsigned char key[32], iv[32];
    char inbuf[SIZE + AES_BLOCK_SIZE] = {0};
    char outbuf[SIZE + AES_BLOCK_SIZE] = {0};
    const EVP_CIPHER *cipherType = EVP_aes_256_cbc();

    if (_pPassword == NULL || _pInfile == NULL || _pOutfile == NULL) {
        return -1;
    }

/* 打开文件 */
    if ((inFile = open((char *)_pInfile, O_RDONLY)) <0) {                  //打开输入文件
        perror("ERROR,original path\n");
        return -1;
    }

    if ((outFile = open(_pOutfile, O_CREAT|O_RDWR, 0400|0200)) <0) {       //创建输出文件
        perror("ERROR,CANT create temp file\n");
        close(inFile);
        return -1;
    }

    /*
    * Gen key & IV for AES 256 CBC mode. A SHA1 digest is used to hash the supplied key material.
    * nrounds is the number of times the we hash the material. More rounds are more secure but
    * slower.
    */
    i = EVP_BytesToKey(cipherType, EVP_md5(), NULL, _pPassword, strlen(_pPassword), nrounds, key, iv);  //输入密码产生了密钥key和初始化向量iv
    if (i != 32) {
        printf("Key size is %d bits - should be 256 bits\n", i);
        goto aes_err;
    }

    pDe_ctx = EVP_CIPHER_CTX_new();                             //创建加密上下文

    EVP_CIPHER_CTX_init(pDe_ctx);                               //初始化 EVP_CIPHER_CTX 上下文
    EVP_DecryptInit_ex(pDe_ctx, cipherType, NULL, key, iv);     //初始化解密操作

    while ((inlen = read(inFile, inbuf, SIZE)) >0) {
        if (!EVP_DecryptUpdate(pDe_ctx, (unsigned char*)outbuf, &outlen, (unsigned char*)inbuf, inlen)) {                        //解密操作
            perror("\n Error,DECRYPT_UPDATE:");
            goto aes_err;
        }
        if ((write(outFile, outbuf, outlen)) != outlen) {    //将解密后的数据写入输出文件
            perror("\n Error,Writing dec bytes:");
            goto aes_err;
        }
    }

    if (!EVP_DecryptFinal_ex(pDe_ctx, (unsigned char*)outbuf, &flen)) {    //完成解密操作,处理剩余字节
        perror("\n Error,DECRYPT_FINAL:");
        goto aes_err;
    }

    if ((write(outFile, outbuf,flen)) != flen) {            //将解密后的数据写入输出文件
        perror("\n Error,Writng FINAL dec bytes:");
        goto aes_err;
    }

    EVP_CIPHER_CTX_cleanup(pDe_ctx);

aes_err:
    close(inFile);
    close(outFile);

    return 0;               /* SUCCESS */
}

main.c 需带入4个参数。确保解密后的文件和加密前的文件内容相同,说明功能OK。

  • 加密前的文件
  • 加密后的文件
  • 解密后的文件
  • 密码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "openssl_aes.h"

static int encrypt_string(char *_pInBuf, int _InLen, char *_pOutBuf, int *_pOutLen, char *_pPassword);
int main(int argc, char **argv)
{
	int i;
	char acFilePath_In[96] = {0};
	char acFilePath_Encrypt[96] = {0};
    char acFilePath_Decrypt[96] = {0};
    char acPassword[96] = {0};

	if (argc != 5) {
		return -1;
	}

	strcpy(acFilePath_In, argv[1]);
	strcpy(acFilePath_Encrypt, argv[2]);
    strcpy(acFilePath_Decrypt, argv[3]);
    strcpy(acPassword, argv[4]);

	printf("in path: %s\n", acFilePath_In);            //需加密的文件
    printf("Encrypt path: %s\n", acFilePath_Encrypt);  //加密后的文件(加密功能)
	printf("Decrypt path: %s\n", acFilePath_Decrypt);  //解密后的文件(解密功能)
    printf("acPassword: %s\n", acPassword);            //密码

	if (aes_encrypt_file(acPassword, acFilePath_In, acFilePath_Encrypt) != 0) {         //文件AES对称加密
        printf("aes_encrypt_file failed!!!\n");
        return -1;
    }
    printf("aes_encrypt_file success!!!\n");

    if (aes_decrypt_file(acPassword, acFilePath_Encrypt, acFilePath_Decrypt) != 0) {     //文件AES对称解密
        printf("aes_decrypt_file failed!!!\n");
        return -1;
    }
    printf("aes_decrypt_file success!!!\n");

	return 0;
}

2、编译及测试结果 

  • 编译

$ gcc -o aes_test main.c openssl_aes.c -lcrypto

  • 运行

$ ./aes_test file_in.txt file_en.txt file_de.txt aes_password

生成加密后的文件 file_en.txt 内容如下图,和openssl命令加密的相同。

问题:为什么文件和字符串加密都为"123456",但加密后的结果不一样?原因是文件中多了换行符'\n'。

生成解密后的文件 file_de.txt 与加密前的 file_in.txt 内容相同都为"123456",验证文件AES对称加、解密功能OK。

  • 10
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值