C语言使用OpenSSL对文件进行加解密操作
OpenSSL是一个强大的开源加密库,广泛应用于互联网安全通信的各个方面。在本篇文章中,博主会在windows7的环境下使用DEVC++来编写加密和解密的C代码,同时和大家一起探讨关于openssl的安装和使用
引言
OpenSSL是一个强大的开源加密库,广泛应用于互联网安全通信的各个方面。OpenSSL提供了一个全面的密码学开发包,包括主要的密码算法、密钥和证书封装管理功能以及SSL协议。它通过提供丰富的应用程序和API,支持多种标准,如ASN.1的证书和密钥相关标准,实现了对证书、公钥、私钥、证书请求以及CRL等数据对象的DER、PEM和BASE64的编解码功能。OpenSSL还支持生成各种公开密钥对和对称密钥,以及对私钥的加密保护功能,确保密钥可以安全地进行存储和分发
在本篇文章中,博主会在windows7的环境下使用DEVC++来编写加密和解密的C代码,同时和大家一起探讨关于openssl的安装和使用
openssl的安装和配置
1.安装
下载链接:https://slproweb.com/products/Win32OpenSSL.html
前往上述的链接中下载适合你的openssl版本的.exe安装包,下载好后运行安装包
需要注意的是,openssl的位数要和devC++的位数一样
为了方便在cmd中使用openssl可以在安装时可以将第二个复选框勾上
2.配置
openssl安装完成后需要记录下安装目录,然后打开devC++,依次点击工具,编译选项
在编译器里面将第二个复选框勾上,并加入链接参数
-llibssl -llibcrypto
接着点击目,,配置所需要的文件
在库中添加openssl文件夹中的lib文件夹的路径
然后在C包含文件中添加openssl文件夹中的include文件夹的路径
最后点击确定,devC++就可以正常使用openssl函数库了
具体实现
这里使用openssl的aes_256_cbc加密算法进行演示,这种加密算法的安全性和稳定性都比较高,所以采用aes_256_cbc加密算,,256的意思就是使用256位的密钥;cbc就是Cipher Block Chaining(密码块链接),在CBC模式中,每个明文块在加密前会与前一个密文块进行异或操作,这样即使两个相同的明文块在加密后也会生成不同的密文块,增加了加密的安全性
在这里需要用到openssl中的头文件有err.h,evp.h和aes.h还有一些常用的库函数
1.加密
AES-256-CBC的加密过程如下:
1.首先,生成一个 256 位(32 字节)的密钥,用于加密操作。
2选择一个随机的、唯一的 128 位(16 字节)初始化向量 IV。
3.将明文数据分成固定大小的分组,每个分组通常为 128 位(16 字节)。
4.与前一分组的密文进行异或(XOR)操作,对于第一个分组,使用 IV 与明文分组进行异或。对于后续的分组,使用前一个分组的密文与当前明文分组进行异或。
5.使用 AES-256 加密算法对异或后的结果进行加密,得到密文分组。
6.重复步骤 4 和 5,直到所有明文分组都被处理。
需要使用的头文件如下
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#define KEY_SIZE 32
#define IV_SIZE 16
KEY_SIZE 定义了用于 AES-256 加密算法的密钥长度。AES-256 要求密钥长度为 256 位,即 32 字节。通过将 KEY_SIZE
定义为 32,确保在生成密钥和后续加密操作中使用正确长度的密钥。
IV_SIZE 定义了初始化向量的长度。通常,AES 加密在 CBC 模式下使用的 IV 长度为 16 字节。定义 IV_SIZE
为 16 有助于正确生成、处理和使用初始化向量。
定义错误处理函数
void handleErrors() {
printf("Error occurred.\n");
exit(1);
}
定义密钥和初始化向量管理函数
// 生成随机密钥和初始化向量,并保存到指定文件
int generateAndSaveKeyIV(const char *keyFile, const char *ivFile) {
FILE *keyOutFile, *ivOutFile;
unsigned char key[KEY_SIZE], iv[IV_SIZE];
// 生成随机密钥
if (!RAND_bytes(key, KEY_SIZE)) {
handleErrors();
}
// 生成随机初始化向量
if (!RAND_bytes(iv, IV_SIZE)) {
handleErrors();
}
// 打开密钥文件进行写入
keyOutFile = fopen(keyFile, "wb");
if (keyOutFile == NULL) {
printf("Could not open key output file.\n");
return -1;
}
// 打开初始化向量文件进行写入
ivOutFile = fopen(ivFile, "wb");
if (ivOutFile == NULL) {
printf("Could not open IV output file.\n");
fclose(keyOutFile);
return -1;
}
// 将密钥写入文件
fwrite(key, 1, KEY_SIZE, keyOutFile);
// 将初始化向量写入文件
fwrite(iv, 1, IV_SIZE, ivOutFile);
// 关闭文件
fclose(keyOutFile);
fclose(ivOutFile);
return 0;
}
keyFile参数:生成密钥文件的路径
ivFile参数:生成初始化向量文件的路径
定义加密函数
int encryptFile(const char *inputFile, const char *outputFile, const char *keyFile, const char *ivFile) {
FILE *inFile, *outFile, *keyInFile, *ivInFile;
EVP_CIPHER_CTX *ctx;
int len;
int ciphertextLen;
unsigned char key[KEY_SIZE], iv[IV_SIZE];
unsigned char inBuf[1024], outBuf[1024 + EVP_MAX_BLOCK_LENGTH];
// 打开密钥文件读取密钥
keyInFile = fopen(keyFile, "rb");
if (keyInFile == NULL) {
printf("Could not open key file.\n");
return -1;
}
// 打开初始化向量文件读取初始化向量
ivInFile = fopen(ivFile, "rb");
if (ivInFile == NULL) {
printf("Could not open IV file.\n");
fclose(keyInFile);
return -1;
}
// 读取密钥
fread(key, 1, KEY_SIZE, keyInFile);
// 读取初始化向量
fread(iv, 1, IV_SIZE, ivInFile);
// 关闭密钥和初始化向量文件
fclose(keyInFile);
fclose(ivInFile);
// 打开输入和输出文件
if ((inFile = fopen(inputFile, "rb")) == NULL) {
printf("Could not open input file.\n");
return -1;
}
if ((outFile = fopen(outputFile, "wb")) == NULL) {
printf("Could not open output file.\n");
fclose(inFile);
return -1;
}
// 初始化加密上下文
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
handleErrors();
}
// 初始化加密操作
if (1!= EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) {
handleErrors();
}
// 加密文件
while ((len = fread(inBuf, 1, 1024, inFile)) > 0) {
if (1!= EVP_EncryptUpdate(ctx, outBuf, &ciphertextLen, inBuf, len)) {
handleErrors();
}
fwrite(outBuf, 1, ciphertextLen, outFile);
}
// 完成加密
if (1!= EVP_EncryptFinal_ex(ctx, outBuf, &ciphertextLen)) {
handleErrors();
}
fwrite(outBuf, 1, ciphertextLen, outFile);
// 清理
EVP_CIPHER_CTX_free(ctx);
fclose(inFile);
fclose(outFile);
//删除原始加密文件
if (remove(inputFile)!= 0){
perror("Failed to remove the original encrypted file");
}
return 0;
}
inputFile参数:需要加密的文件路径
outputFile参数:生成加密文件的路径
keyFile参数:密钥文件的路径
ivFile参数:初始化向量文件的路径
2.解密
AES-256-CBC的解密过程如下:
1.获取和加密相同的256位密钥。
2.使用与加密时相同初始化向量。
3.将密文分成固定大小的分组,每组128位(16字节)。
4.使用AES_256解密算法对密文进行分组解密。
5.与前一分组的密文进行异或(XOR)操作:对于第一个分组,使用 IV 与解密后的结果进行异或,得到明文分组。对于后续的分组,使用前一个分组的密文与解密后的结果进行异或,得到明文分组。
6.重复步骤 4 和 5,直到所有密文分组都被处理,得到完整的明文。
定义的错误处理函数和加密中的完全一样
定义解密函数
int decryptFile(const char *inputFile, const char *outputFile, const char *keyFile, const char *ivFile) {
FILE *inFile, *outFile, *keyInFile, *ivInFile;
EVP_CIPHER_CTX *ctx;
int len;
int plaintextLen;
unsigned char key[KEY_SIZE], iv[IV_SIZE];
unsigned char inBuf[1024], outBuf[1024 + EVP_MAX_BLOCK_LENGTH];
// 打开密钥文件读取密钥
keyInFile = fopen(keyFile, "rb");
if (keyInFile == NULL) {
printf("Could not open key file.\n");
return -1;
}
// 打开初始化向量文件读取初始化向量
ivInFile = fopen(ivFile, "rb");
if (ivInFile == NULL) {
printf("Could not open IV file.\n");
fclose(keyInFile);
return -1;
}
// 读取密钥
fread(key, 1, KEY_SIZE, keyInFile);
// 读取初始化向量
fread(iv, 1, IV_SIZE, ivInFile);
// 关闭密钥和初始化向量文件
fclose(keyInFile);
fclose(ivInFile);
// 打开输入和输出文件
if ((inFile = fopen(inputFile, "rb")) == NULL) {
printf("Could not open input file.\n");
return -1;
}
if ((outFile = fopen(outputFile, "wb")) == NULL) {
printf("Could not open output file.\n");
fclose(inFile);
return -1;
}
// 初始化解密上下文
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
handleErrors();
}
// 初始化解密操作
if (1!= EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) {
handleErrors();
}
// 解密文件
while ((len = fread(inBuf, 1, 1024, inFile)) > 0) {
if (1!= EVP_DecryptUpdate(ctx, outBuf, &plaintextLen, inBuf, len)) {
handleErrors();
}
fwrite(outBuf, 1, plaintextLen, outFile);
}
// 完成解密
if (1!= EVP_DecryptFinal_ex(ctx, outBuf, &plaintextLen)) {
handleErrors();
}
fwrite(outBuf, 1, plaintextLen, outFile);
// 清理
EVP_CIPHER_CTX_free(ctx);
fclose(inFile);
fclose(outFile);
return 0;
}
inputFile参数:需要解密文件的路径
outputFile参数:生成解密文件的路径
keyFile:加密时生成密钥的路径
inFile:加密时生成初始化向量的路径
完整代码
加密代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#define KEY_SIZE 32
#define IV_SIZE 16
void handleErrors() {
printf("Error occurred.\n");
exit(1);
}
// 生成随机密钥和初始化向量,并保存到指定文件
int generateAndSaveKeyIV(const char *keyFile, const char *ivFile) {
FILE *keyOutFile, *ivOutFile;
unsigned char key[KEY_SIZE], iv[IV_SIZE];
// 生成随机密钥
if (!RAND_bytes(key, KEY_SIZE)) {
handleErrors();
}
// 生成随机初始化向量
if (!RAND_bytes(iv, IV_SIZE)) {
handleErrors();
}
// 打开密钥文件进行写入
keyOutFile = fopen(keyFile, "wb");
if (keyOutFile == NULL) {
printf("Could not open key output file.\n");
return -1;
}
// 打开初始化向量文件进行写入
ivOutFile = fopen(ivFile, "wb");
if (ivOutFile == NULL) {
printf("Could not open IV output file.\n");
fclose(keyOutFile);
return -1;
}
// 将密钥写入文件
fwrite(key, 1, KEY_SIZE, keyOutFile);
// 将初始化向量写入文件
fwrite(iv, 1, IV_SIZE, ivOutFile);
// 关闭文件
fclose(keyOutFile);
fclose(ivOutFile);
return 0;
}
int encryptFile(const char *inputFile, const char *outputFile, const char *keyFile, const char *ivFile) {
FILE *inFile, *outFile, *keyInFile, *ivInFile;
EVP_CIPHER_CTX *ctx;
int len;
int ciphertextLen;
unsigned char key[KEY_SIZE], iv[IV_SIZE];
unsigned char inBuf[1024], outBuf[1024 + EVP_MAX_BLOCK_LENGTH];
// 打开密钥文件读取密钥
keyInFile = fopen(keyFile, "rb");
if (keyInFile == NULL) {
printf("Could not open key file.\n");
return -1;
}
// 打开初始化向量文件读取初始化向量
ivInFile = fopen(ivFile, "rb");
if (ivInFile == NULL) {
printf("Could not open IV file.\n");
fclose(keyInFile);
return -1;
}
// 读取密钥
fread(key, 1, KEY_SIZE, keyInFile);
// 读取初始化向量
fread(iv, 1, IV_SIZE, ivInFile);
// 关闭密钥和初始化向量文件
fclose(keyInFile);
fclose(ivInFile);
// 打开输入和输出文件
if ((inFile = fopen(inputFile, "rb")) == NULL) {
printf("Could not open input file.\n");
return -1;
}
if ((outFile = fopen(outputFile, "wb")) == NULL) {
printf("Could not open output file.\n");
fclose(inFile);
return -1;
}
// 初始化加密上下文
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
handleErrors();
}
// 初始化加密操作
if (1!= EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) {
handleErrors();
}
// 加密文件
while ((len = fread(inBuf, 1, 1024, inFile)) > 0) {
if (1!= EVP_EncryptUpdate(ctx, outBuf, &ciphertextLen, inBuf, len)) {
handleErrors();
}
fwrite(outBuf, 1, ciphertextLen, outFile);
}
// 完成加密
if (1!= EVP_EncryptFinal_ex(ctx, outBuf, &ciphertextLen)) {
handleErrors();
}
fwrite(outBuf, 1, ciphertextLen, outFile);
// 清理
EVP_CIPHER_CTX_free(ctx);
fclose(inFile);
fclose(outFile);
//删除原始加密文件
if (remove(inputFile)!= 0){
perror("Failed to remove the original encrypted file");
}
return 0;
}
int main() {
const char *keyFile = "C:\\Users\\Administrator\\Desktop\\key.txt";
const char *ivFile = "C:\\Users\\Administrator\\Desktop\\iv.txt";
// 生成并保存密钥和初始化向量
if (generateAndSaveKeyIV(keyFile, ivFile)!= 0) {
printf("Failed to generate and save key and IV.\n");
return -1;
}
const char *inputFile = "C:\\Users\\Administrator\\Desktop\\safe.pdf";
const char *encryptedFile = "C:\\Users\\Administrator\\Desktop\\safee.pdf";
// 加密文件
if (encryptFile(inputFile, encryptedFile, keyFile, ivFile)!= 0) {
printf("Encryption failed.\n");
return -1;
}
printf("Encryption completed successfully.\n");
return 0;
}
解密代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#define KEY_SIZE 32
#define IV_SIZE 16
void handleErrors() {
printf("Error occurred.\n");
exit(1);
}
int decryptFile(const char *inputFile, const char *outputFile, const char *keyFile, const char *ivFile) {
FILE *inFile, *outFile, *keyInFile, *ivInFile;
EVP_CIPHER_CTX *ctx;
int len;
int plaintextLen;
unsigned char key[KEY_SIZE], iv[IV_SIZE];
unsigned char inBuf[1024], outBuf[1024 + EVP_MAX_BLOCK_LENGTH];
// 打开密钥文件读取密钥
keyInFile = fopen(keyFile, "rb");
if (keyInFile == NULL) {
printf("Could not open key file.\n");
return -1;
}
// 打开初始化向量文件读取初始化向量
ivInFile = fopen(ivFile, "rb");
if (ivInFile == NULL) {
printf("Could not open IV file.\n");
fclose(keyInFile);
return -1;
}
// 读取密钥
fread(key, 1, KEY_SIZE, keyInFile);
// 读取初始化向量
fread(iv, 1, IV_SIZE, ivInFile);
// 关闭密钥和初始化向量文件
fclose(keyInFile);
fclose(ivInFile);
// 打开输入和输出文件
if ((inFile = fopen(inputFile, "rb")) == NULL) {
printf("Could not open input file.\n");
return -1;
}
if ((outFile = fopen(outputFile, "wb")) == NULL) {
printf("Could not open output file.\n");
fclose(inFile);
return -1;
}
// 初始化解密上下文
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
handleErrors();
}
// 初始化解密操作
if (1!= EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) {
handleErrors();
}
// 解密文件
while ((len = fread(inBuf, 1, 1024, inFile)) > 0) {
if (1!= EVP_DecryptUpdate(ctx, outBuf, &plaintextLen, inBuf, len)) {
handleErrors();
}
fwrite(outBuf, 1, plaintextLen, outFile);
}
// 完成解密
if (1!= EVP_DecryptFinal_ex(ctx, outBuf, &plaintextLen)) {
handleErrors();
}
fwrite(outBuf, 1, plaintextLen, outFile);
// 清理
EVP_CIPHER_CTX_free(ctx);
fclose(inFile);
fclose(outFile);
return 0;
}
int main(){
const char *keyFile = "C:\\Users\\Administrator\\Desktop\\key.txt";
const char *ivFile = "C:\\Users\\Administrator\\Desktop\\iv.txt";
const char *encryptedFile = "C:\\Users\\Administrator\\Desktop\\safee.pdf";
const char *decryptedFile = "C:\\Users\\Administrator\\Desktop\\safeee.pdf";
if (decryptFile(encryptedFile, decryptedFile, keyFile, ivFile)!= 0) {
printf("Decryption failed.\n");
return -1;
}
printf("decryptfile completed successfully");
return 0;
}
本篇文章到此结束,感谢大家的浏览!
如有写的不对的地方,请大家多多谅解。
非常欢迎各位大佬前来指教! ! !
更多推荐
所有评论(0)