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

相关推荐
撞南墙者5 分钟前
OpenCV自学系列(1)——简介和GUI特征操作
人工智能·opencv·计算机视觉
OCR_wintone4216 分钟前
易泊车牌识别相机,助力智慧工地建设
人工智能·数码相机·ocr
王哈哈^_^27 分钟前
【数据集】【YOLO】【VOC】目标检测数据集,查找数据集,yolo目标检测算法详细实战训练步骤!
人工智能·深度学习·算法·yolo·目标检测·计算机视觉·pyqt
一者仁心34 分钟前
【AI技术】PaddleSpeech
人工智能
是瑶瑶子啦42 分钟前
【深度学习】论文笔记:空间变换网络(Spatial Transformer Networks)
论文阅读·人工智能·深度学习·视觉检测·空间变换
EasyCVR1 小时前
萤石设备视频接入平台EasyCVR多品牌摄像机视频平台海康ehome平台(ISUP)接入EasyCVR不在线如何排查?
运维·服务器·网络·人工智能·ffmpeg·音视频
柳鲲鹏1 小时前
OpenCV视频防抖源码及编译脚本
人工智能·opencv·计算机视觉
西柚小萌新1 小时前
8.机器学习--决策树
人工智能·决策树·机器学习
向阳12181 小时前
Bert快速入门
人工智能·python·自然语言处理·bert
jndingxin1 小时前
OpenCV视觉分析之目标跟踪(8)目标跟踪函数CamShift()使用
人工智能·opencv·目标跟踪