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 和密钥的选择取决于所使用的加密算法和具体的安全需求。

相关推荐
红色的山茶花10 分钟前
YOLOv9-0.1部分代码阅读笔记-loss_tal.py
笔记·深度学习·yolo
边缘计算社区38 分钟前
首个!艾灵参编的工业边缘计算国家标准正式发布
大数据·人工智能·边缘计算
游客5201 小时前
opencv中的各种滤波器简介
图像处理·人工智能·python·opencv·计算机视觉
一位小说男主1 小时前
编码器与解码器:从‘乱码’到‘通话’
人工智能·深度学习
深圳南柯电子1 小时前
深圳南柯电子|电子设备EMC测试整改:常见问题与解决方案
人工智能
Kai HVZ1 小时前
《OpenCV计算机视觉》--介绍及基础操作
人工智能·opencv·计算机视觉
biter00881 小时前
opencv(15) OpenCV背景减除器(Background Subtractors)学习
人工智能·opencv·学习
吃个糖糖1 小时前
35 Opencv 亚像素角点检测
人工智能·opencv·计算机视觉
qq_529025292 小时前
Torch.gather
python·深度学习·机器学习