openssl加解密-干货分享

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

#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.密钥的生成与管理

    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;

将加密密钥保存到文件:

// 将加密密钥保存到文件

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;

}

}

从文件中加载加密密钥:
 

// 从文件中加载加密密钥

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.加密
 

    // 使用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字节的整数倍,这样是不合理的!修正后的写法:

    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.解密

    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字节的整数倍,这样是不合理的!修正后的写法:

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.加密和解密接口的调用

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 接口

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

猜你喜欢

转载自blog.csdn.net/Fan0920/article/details/134581193