前两天发布了《字符串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。