openssl加解密-干货分享

0.需要包含的头文件和预定义常量

cpp 复制代码
#include <openssl/rand.h>

#include <fstream>

#include <openssl/aes.h>

#include <openssl/rand.h>


// 加密密钥和初始化向量(IV)长度

#define AES_KEY_LENGTH 32

#define AES_IV_LENGTH 16

1.密钥的生成与管理

cpp 复制代码
    unsigned char key[32];
    if (RAND_bytes(key, sizeof(key)) != 1) {
        // 处理错误
    }
    // 使用自己的加密密钥
    // 将 key 转换为十六进制字符串
    std::string key_str;
    for (size_t i = 0; i < sizeof(key); i++) {
        char hex[3];
        snprintf(hex, sizeof(hex), "%02x", key[i]);
        key_str += hex;
    }
    std::cout << "key_str=" << key_str << std::endl;

将加密密钥保存到文件:

cpp 复制代码
// 将加密密钥保存到文件

void saveKeyToFile(const char* filename, const AES_KEY* key) {

std::ofstream file(filename, std::ios::binary);

if (file.is_open()) {

// 写入轮数

file.write(reinterpret_cast<const char*>(&key->rounds), sizeof(key->rounds));

// 写入密钥调度表

file.write(reinterpret_cast<const char*>(key->rd_key), sizeof(key->rd_key));

file.close();

std::cout << "Encryption key saved to file: " << filename << std::endl;

} else {

std::cerr << "Error opening file for writing: " << filename << std::endl;

}

}

从文件中加载加密密钥:

cpp 复制代码
// 从文件中加载加密密钥

void loadKeyFromFile(const char* filename, AES_KEY* key) {

std::ifstream file(filename, std::ios::binary);

if (file.is_open()) {

// 读取轮数

file.read(reinterpret_cast<char*>(&key->rounds), sizeof(key->rounds));

// 读取密钥调度表

file.read(reinterpret_cast<char*>(key->rd_key), sizeof(key->rd_key));

file.close();

std::cout << "Encryption key loaded from file: " << filename << std::endl;

} else {

std::cerr << "Error opening file for reading: " << filename << std::endl;

}

}

2.加密

cpp 复制代码
    // 使用AES-256加密算法
    void encryptFile(const std::string &inputFilename, const std::string &outputFilename, const std::string &key) {
        AES_KEY aesKey;
        memset(&aesKey, 0, sizeof(AES_KEY));
        //AES_set_encrypt_key(ckey, AES_KEY_LENGTH * 8, &aesKey);//(const unsigned char *)key.c_str()
        AES_set_encrypt_key((const unsigned char *)key.c_str(), 128, &aesKey);
        // 将加密密钥保存到文件
        //saveKeyToFile("encryption_key.bin", &aesKey);
        std::cout << "key :\t" << key << std::endl;
        // 生成随机IV
        unsigned char iv[AES_IV_LENGTH];
        RAND_bytes(iv, AES_IV_LENGTH);
        iv[AES_IV_LENGTH-1]='\0';
        // 备份 IV
        unsigned char ivBackup[AES_IV_LENGTH];
        memcpy(ivBackup, iv, AES_IV_LENGTH);
        std::cout << "ivBackup :\t" << ivBackup << std::endl;
        std::ifstream inputFile(inputFilename, std::ios::binary);
        std::ofstream outputFile(outputFilename, std::ios::binary);

        outputFile.write(reinterpret_cast<const char *>(iv), AES_IV_LENGTH);
        unsigned char inBuffer[16], outBuffer[16];
        int num = 0;
        static int testi=0;

        while (inputFile.good()) { // 检查文件是否有效
            inputFile.read(reinterpret_cast<char *>(inBuffer), 16);

            // 获取实际读取的字节数
            int bytesRead = inputFile.gcount();
            if (inputFile.gcount() > 0) { // 检查实际读取的字节数
                memcpy( iv , ivBackup, AES_BLOCK_SIZE);
                AES_cfb128_encrypt(inBuffer, outBuffer, 16, &aesKey, iv, &num, AES_ENCRYPT);
                // 重置 IV
                //memcpy(iv, ivBackup, AES_IV_LENGTH);
                /* //if(testi<=1)是为了检查,检查解密出来的第一段16字节内容是否跟加密前的一样
                if(testi<=1) {
                    //std::cout << "inBuffer :\t" << inBuffer << std::endl;
                    std::cout << "encryptFile, inBuffer:\n";
                    for (int i = 0; i < 16; i++) {
                        printf("%02x", inBuffer[i]); // 打印十六进制形式
                    }
                    std::cout << "\n";
                    std::cout << "encrypted data:\t";
                    for (int i = 0; i < 16; i++) {
                        printf("%02x", outBuffer[i]); // 打印十六进制形式
                    }
                    std::cout << std::endl;
                    memcpy( iv , ivBackup, AES_BLOCK_SIZE);
                    unsigned char decrypt_outBuffer[16];
                    AES_cfb128_encrypt(outBuffer, decrypt_outBuffer, 16, &aesKey, iv, &num, AES_DECRYPT);
                    //std::cout << "decrypt_outBuffer :\t" << decrypt_outBuffer << std::endl;
                    std::cout << "encryptFile, decrypt_outBuffer:\n";
                    for (int i = 0; i < 16; i++) {
                        printf("%02x", decrypt_outBuffer[i]); // 打印十六进制形式
                    }
                    std::cout << "\n";
                    testi++;
                }*/
                outputFile.write(reinterpret_cast<const char *>(outBuffer), 16);
            }
        }
    }

这个写法有个很大的问题,把输入的文件内容认为是16字节的整数倍,这样是不合理的!修正后的写法:

cpp 复制代码
    void encryptFile(const std::string &inputFilename, const std::string &outputFilename, const std::string &key) {
        AES_KEY aesKey;
        memset(&aesKey, 0, sizeof(AES_KEY));
        AES_set_encrypt_key((const unsigned char *)key.c_str(), 128, &aesKey);

        // 生成随机 IV
        unsigned char iv[AES_IV_LENGTH];
        RAND_bytes(iv, AES_IV_LENGTH);

        // 备份 IV
        unsigned char ivBackup[AES_IV_LENGTH];
        memcpy(ivBackup, iv, AES_IV_LENGTH);

        std::cout << "key :\t" << key << std::endl;
        std::cout << "ivBackup :\t";
        for (int i = 0; i < AES_IV_LENGTH; i++) {
            printf("%02x", ivBackup[i]);
        }
        std::cout << std::endl;

        std::ifstream inputFile(inputFilename, std::ios::binary);
        std::ofstream outputFile(outputFilename, std::ios::binary);

        outputFile.write(reinterpret_cast<const char *>(iv), AES_IV_LENGTH);

        unsigned char inBuffer[AES_BLOCK_SIZE], outBuffer[AES_BLOCK_SIZE];
        int num = 0;
        //static int testi=0;
        while (inputFile.good()) {
            inputFile.read(reinterpret_cast<char *>(inBuffer), AES_BLOCK_SIZE);

            // 获取实际读取的字节数
            int bytesRead = inputFile.gcount();
            if (bytesRead > 0) {
                // 拷贝 IV
                //memcpy(iv, ivBackup, AES_BLOCK_SIZE);

                // 加密
                AES_cfb128_encrypt(inBuffer, outBuffer, bytesRead, &aesKey, iv, &num, AES_ENCRYPT);


                // 输出加密数据
                outputFile.write(reinterpret_cast<const char *>(outBuffer), bytesRead);
    // if(testi<=1) {
    //             // 重置 IV
    //             memcpy(iv, ivBackup, AES_BLOCK_SIZE);

    //             // 解密,为了测试
    //             unsigned char decrypt_outBuffer[AES_BLOCK_SIZE];
    //             AES_cfb128_encrypt(outBuffer, decrypt_outBuffer, bytesRead, &aesKey, iv, &num, AES_DECRYPT);

    //             // 打印信息,为了测试
    //             std::cout << "inBuffer:\n";
    //             for (int i = 0; i < bytesRead; i++) {
    //                 printf("%02x", inBuffer[i]);
    //             }
    //             std::cout << "\n";

    //             std::cout << "encrypted data:\t";
    //             for (int i = 0; i < bytesRead; i++) {
    //                 printf("%02x", outBuffer[i]);
    //             }
    //             std::cout << std::endl;

    //             std::cout << "decrypt_outBuffer:\n";
    //             for (int i = 0; i < bytesRead; i++) {
    //                 printf("%02x", decrypt_outBuffer[i]);
    //             }
    //             std::cout << "\n";
    //             testi++;
    // }
            }
        }
    }

3.解密

cpp 复制代码
    void decryptFile(const std::string &inputFilename, const std::string &outputFilename, const std::string &key) {
        AES_KEY aesKey;
        memset(&aesKey, 0, sizeof(AES_KEY));
        //unsigned char ckey[] = "helloworldkey\0";
        AES_set_encrypt_key((const unsigned char *)key.c_str(), 128, &aesKey);
        //AES_set_decrypt_key(ckey, AES_KEY_LENGTH * 8, &aesKey);//(const unsigned char *)key.c_str()
            /* set the encryption key */
        //AES_set_decrypt_key(ckey, 128, &aesKey);
        // 加载加密密钥
        //loadKeyFromFile("encryption_key.bin", &aesKey);
        std::cout << "key :\t" << key << std::endl;
        std::ifstream inputFile(inputFilename, std::ios::binary);
        std::ofstream outputFile(outputFilename, std::ios::binary);

        // 从文件中读取IV
        unsigned char iv[AES_IV_LENGTH];
        inputFile.read(reinterpret_cast<char *>(iv), AES_IV_LENGTH);
        // 备份 IV
        unsigned char ivBackup[AES_IV_LENGTH];
        memcpy(ivBackup, iv, AES_IV_LENGTH);
        std::cout << "ivBackup :\t" << ivBackup << std::endl;
        unsigned char inBuffer[16], outBuffer[16];
        int num = 0;
        static int testi=0;

        while (inputFile.good()) {
            inputFile.read(reinterpret_cast<char *>(inBuffer), 16);
            if (inputFile.gcount() > 0) { // 检查实际读取的字节数
                memcpy( iv , ivBackup, AES_BLOCK_SIZE);
                AES_cfb128_encrypt(inBuffer, outBuffer, 16, &aesKey, iv, &num, AES_DECRYPT);//nullptr
                // 重置 IV
                //memcpy(iv, ivBackup, AES_IV_LENGTH);
                if(testi<=1) {
                    //std::cout << "inBuffer :\t" << inBuffer << std::endl;
                    std::cout << "encrypted data:\t";
                    for (int i = 0; i < 16; i++) {
                        printf("%02x", inBuffer[i]); // 打印十六进制形式
                    }
                    std::cout << std::endl;
                    //std::cout << "outBuffer :\t" << outBuffer << std::endl;
                    std::cout << "decryptFile, outBuffer:\n";
                    for (int i = 0; i < 16; i++) {
                        printf("%02x", outBuffer[i]); // 打印十六进制形式
                    }
                    std::cout << "\n";
                    testi++;
                }
                outputFile.write(reinterpret_cast<char *>(outBuffer), 16);
            }
        }
    }

这个写法有个很大的问题,把输入的文件内容认为是16字节的整数倍,这样是不合理的!修正后的写法:

cpp 复制代码
void decryptFile(const std::string &inputFilename, const std::string &outputFilename, const std::string &key) {
        AES_KEY aesKey;
        memset(&aesKey, 0, sizeof(AES_KEY));
        AES_set_encrypt_key((const unsigned char *)key.c_str(), 128, &aesKey);

        // 打开输入文件
        std::ifstream inputFile(inputFilename, std::ios::binary);
        if (!inputFile) {
            std::cerr << "Error opening input file." << std::endl;
            return;
        }

        // 打开输出文件
        std::ofstream outputFile(outputFilename, std::ios::binary);
        if (!outputFile) {
            std::cerr << "Error opening output file." << std::endl;
            return;
        }

        // 从文件中读取 IV
        unsigned char iv[AES_IV_LENGTH];
        inputFile.read(reinterpret_cast<char *>(iv), AES_IV_LENGTH);

        // 备份 IV
        unsigned char ivBackup[AES_IV_LENGTH];
        memcpy(ivBackup, iv, AES_IV_LENGTH);
        std::cout << "ivBackup :\t";
        for (int i = 0; i < AES_IV_LENGTH; i++) {
            printf("%02x", ivBackup[i]);
        }
        std::cout << std::endl;

        unsigned char inBuffer[AES_BLOCK_SIZE], outBuffer[AES_BLOCK_SIZE];
        int num = 0;

        while (inputFile.good()) {
            inputFile.read(reinterpret_cast<char *>(inBuffer), AES_BLOCK_SIZE);

            // 获取实际读取的字节数
            int bytesRead = inputFile.gcount();
            if (bytesRead > 0) {
                // 拷贝 IV
                //memcpy(iv, ivBackup, AES_BLOCK_SIZE);

                // 解密
                AES_cfb128_encrypt(inBuffer, outBuffer, bytesRead, &aesKey, iv, &num, AES_DECRYPT);

                // 输出解密数据
                outputFile.write(reinterpret_cast<char *>(outBuffer), bytesRead);
            }
        }
    }

4.加密和解密接口的调用

cpp 复制代码
encryptFile("./models/test.jpg", "./models/encrypted_cornerModel.crypt", key_str);
decryptFile("./models/encrypted_cornerModel.crypt", "./models/decrypt_test.jpg", key_str);
encryptFile("./models/patternModel.onnx", "./models/encrypted_patternModel.crypt", key_str);
decryptFile("./models/encrypted_patternModel.crypt", "./models/decrypt_patternModel.onnx", key_str);
encryptFile("./models/cornerModel.onnx", "./models/encrypted_cornerModel.crypt", key_str);
decryptFile("./models/encrypted_cornerModel.crypt", "./models/decrypt_cornerModel.onnx", key_str);

5.解密出来的内容,不保存到文件,而是直接保存到内存缓冲区后,再将内存缓冲区的模型数据传递给 readNet 接口

cpp 复制代码
void decryptAndLoadModel(const std::string &inputFilename, const std::string &key) {
    AES_KEY aesKey;
    memset(&aesKey, 0, sizeof(AES_KEY));
    AES_set_encrypt_key((const unsigned char *)key.c_str(), 128, &aesKey);

    // 打开输入文件
    std::ifstream inputFile(inputFilename, std::ios::binary);
    if (!inputFile) {
        std::cerr << "Error opening input file." << std::endl;
        return;
    }

    // 从文件中读取 IV
    unsigned char iv[AES_IV_LENGTH];
    inputFile.read(reinterpret_cast<char *>(iv), AES_IV_LENGTH);

    // 备份 IV
    unsigned char ivBackup[AES_IV_LENGTH];
    memcpy(ivBackup, iv, AES_IV_LENGTH);

    // 定义内存缓冲区用于存储解密的模型数据
    std::vector<unsigned char> decryptedModelBuffer;

    unsigned char inBuffer[AES_BLOCK_SIZE], outBuffer[AES_BLOCK_SIZE];
    int num = 0;

    while (inputFile.good()) {
        inputFile.read(reinterpret_cast<char *>(inBuffer), AES_BLOCK_SIZE);

        // 获取实际读取的字节数
        int bytesRead = inputFile.gcount();
        if (bytesRead > 0) {
            // 解密
            AES_cfb128_encrypt(inBuffer, outBuffer, bytesRead, &aesKey, iv, &num, AES_DECRYPT);

            // 存储解密数据到内存缓冲区
            decryptedModelBuffer.insert(decryptedModelBuffer.end(), outBuffer, outBuffer + bytesRead);
        }
    }

    // 使用 OpenCV 读取解密后的模型数据
    cv::Mat modelDataMat(1, decryptedModelBuffer.size(), CV_8U, decryptedModelBuffer.data());

    // 将解密后的模型数据传递给 readNet 接口
    cv::dnn::Net neuralNet = cv::dnn::readNetFromONNX(modelDataMat);
    
    // 使用 neuralNet 对象进行后续操作,如推理等
    // ...
}

在加密中,IV(Initialization Vector,初始化向量)和 Key(密钥)是两个重要的概念,它们通常用于对数据进行加密和解密。

  1. Initialization Vector(IV,初始化向量): IV 是在对称加密中使用的固定长度的随机值。它的作用是增强加密算法的安全性,以防止在相同密钥下对相同的明文进行多次加密时产生相同的密文输出。

    IV 与密钥不同,IV 不需要保密,通常会与密文一起传输。对于每个独立的消息,IV 都应该是唯一的,但不需要保密。在开始加密之前,IV 会与密钥一起输入到加密算法中,以确保对相同的明文使用相同的密钥和 IV 时,每次得到的密文都是不同的。

  2. Key(密钥): 密钥是用于加密和解密数据的机密值。在对称加密中,加密和解密使用相同的密钥。保持密钥的机密性对于加密的安全性至关重要。只有知道密钥的人才能解密数据。

    密钥应该是足够长且具有足够的随机性,以防止被暴力破解。安全的加密算法强调了密钥的安全性和保密性,因为知道密钥的人可以解密被加密的数据。

IV 和密钥的选择对于加密的安全性至关重要。合适的 IV 长度和随机性以及安全的密钥管理对于确保加密系统的安全性非常重要。IV 和密钥的选择取决于所使用的加密算法和具体的安全需求。

相关推荐
LZXCyrus7 分钟前
【杂记】vLLM如何指定GPU单卡/多卡离线推理
人工智能·经验分享·python·深度学习·语言模型·llm·vllm
我感觉。25 分钟前
【机器学习chp4】特征工程
人工智能·机器学习·主成分分析·特征工程
YRr YRr33 分钟前
深度学习神经网络中的优化器的使用
人工智能·深度学习·神经网络
DieYoung_Alive33 分钟前
一篇文章了解机器学习(下)
人工智能·机器学习
夏沫的梦35 分钟前
生成式AI对产业的影响与冲击
人工智能·aigc
goomind1 小时前
YOLOv8实战木材缺陷识别
人工智能·yolo·目标检测·缺陷检测·pyqt5·木材缺陷识别
只怕自己不够好1 小时前
《OpenCV 图像基础操作全解析:从读取到像素处理与 ROI 应用》
人工智能·opencv·计算机视觉
幻风_huanfeng1 小时前
人工智能之数学基础:线性代数在人工智能中的地位
人工智能·深度学习·神经网络·线性代数·机器学习·自然语言处理
嵌入式大圣1 小时前
嵌入式系统与OpenCV
人工智能·opencv·计算机视觉
ZOMI酱2 小时前
【AI系统】GPU 架构与 CUDA 关系
人工智能·架构