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;
	
}

本篇文章到此结束,感谢大家的浏览!

如有写的不对的地方请大家多多谅解。

非常欢迎各位大佬前来指教! ! !

以下是一个简单的示例程序,使用 OpenSSL进行 RSA 加解密,可以在 VS2010 中使用 C 语言编写。 ```c #include <stdio.h> #include <string.h> #include <openssl/rsa.h> #include <openssl/pem.h> #define KEY_LENGTH 2048 #define PUB_EXP 3 #define PRIV_EXP "mykey.pem" int main() { RSA *keypair = RSA_generate_key(KEY_LENGTH, PUB_EXP, NULL, NULL); if (!keypair) { printf("Error generating RSA key!\n"); return -1; } // 保存私钥 FILE *priv_file = fopen(PRIV_EXP, "wb"); if (priv_file) { PEM_write_RSAPrivateKey(priv_file, keypair, NULL, NULL, 0, NULL, NULL); fclose(priv_file); printf("Private key saved to %s.\n", PRIV_EXP); } else { printf("Error saving private key!\n"); RSA_free(keypair); return -1; } // 加密 const char *msg = "Hello, world!"; size_t msg_len = strlen(msg) + 1; unsigned char enc_msg[KEY_LENGTH / 8]; int enc_msg_len = RSA_public_encrypt(msg_len, (unsigned char*)msg, enc_msg, keypair, RSA_PKCS1_PADDING); if (enc_msg_len == -1) { printf("Error encrypting message!\n"); RSA_free(keypair); return -1; } printf("Encrypted message: "); for (int i = 0; i < enc_msg_len; i++) { printf("%02x", enc_msg[i]); } printf("\n"); // 解密 unsigned char dec_msg[KEY_LENGTH / 8]; int dec_msg_len = RSA_private_decrypt(enc_msg_len, enc_msg, dec_msg, keypair, RSA_PKCS1_PADDING); if (dec_msg_len == -1) { printf("Error decrypting message!\n"); RSA_free(keypair); return -1; } printf("Decrypted message: %s\n", dec_msg); RSA_free(keypair); return 0; } ``` 此示例程序生成一个 2048 位的 RSA 密钥对,并将私钥保存到 "mykey.pem" 文件中。然后,将一个字符串 "Hello, world!" 加密,并将加密后的消息打印出来。接着,解密加密后的消息,并将原始消息打印出来。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值