openssl encryption and decryption-dry information sharing

0. Header files and predefined constants that need to be included
 

#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. Key generation and management

    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;

Save the encryption key to a file:

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

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;

}

}

Load the encryption key from a file:
 

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

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. Encryption
 

    // 使用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);
            }
        }
    }

There is a big problem with this way of writing. It is unreasonable to consider the input file content as an integer multiple of 16 bytes! Corrected writing:

    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. Decryption

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

There is a big problem with this way of writing. It is unreasonable to consider the input file content as an integer multiple of 16 bytes! Corrected writing:

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. Calling encryption and decryption interfaces

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. The decrypted content is not saved to a file, but directly saved to the memory buffer, and then the model data in the memory buffer is passed to the readNet interface.

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 对象进行后续操作,如推理等
    // ...
}

In encryption, IV (Initialization Vector) and Key (key) are two important concepts, which are usually used to encrypt and decrypt data.

  1. Initialization Vector (IV, Initialization Vector): IV is a fixed-length random value used in symmetric encryption. Its role is to enhance the security of the encryption algorithm to prevent the same ciphertext output when the same plaintext is encrypted multiple times under the same key.

    IV Unlike a key, the IV does not need to be kept secret and is usually transmitted along with the ciphertext. The IV should be unique for each individual message, but does not need to be confidential. The IV is fed into the encryption algorithm along with the key before encryption begins, ensuring that the resulting ciphertext is different each time the same key and IV are used on the same plaintext.

  2. Key: A key is a secret value used to encrypt and decrypt data. In symmetric encryption, the same key is used for encryption and decryption. Keeping your keys confidential is critical to the security of your encryption. Only someone who knows the key can decrypt the data.

    The key should be long enough and random enough to prevent brute force attack. Secure encryption algorithms emphasize the security and confidentiality of the key, because anyone who knows the key can decrypt the encrypted data.

The choice of IV and key is critical to the security of the encryption. Proper IV length and randomness as well as secure key management are important to ensure the security of a cryptographic system. The choice of IV and key depends on the encryption algorithm used and the specific security needs.

Guess you like

Origin blog.csdn.net/Fan0920/article/details/134581193