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;// 生成隨機IVunsigned char iv[AES_IV_LENGTH];RAND_bytes(iv, AES_IV_LENGTH);iv[AES_IV_LENGTH-1]='\0';// 備份 IVunsigned 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);// 生成隨機 IVunsigned char iv[AES_IV_LENGTH];RAND_bytes(iv, AES_IV_LENGTH);// 備份 IVunsigned 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);// 從文件中讀取IVunsigned char iv[AES_IV_LENGTH];inputFile.read(reinterpret_cast<char *>(iv), AES_IV_LENGTH);// 備份 IVunsigned 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;}// 從文件中讀取 IVunsigned char iv[AES_IV_LENGTH];inputFile.read(reinterpret_cast<char *>(iv), AES_IV_LENGTH);// 備份 IVunsigned 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;}// 從文件中讀取 IVunsigned char iv[AES_IV_LENGTH];inputFile.read(reinterpret_cast<char *>(iv), AES_IV_LENGTH);// 備份 IVunsigned 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(密鑰)是兩個重要的概念,它們通常用于對數據進行加密和解密。
-
Initialization Vector(IV,初始化向量): IV 是在對稱加密中使用的固定長度的隨機值。它的作用是增強加密算法的安全性,以防止在相同密鑰下對相同的明文進行多次加密時產生相同的密文輸出。
IV 與密鑰不同,IV 不需要保密,通常會與密文一起傳輸。對于每個獨立的消息,IV 都應該是唯一的,但不需要保密。在開始加密之前,IV 會與密鑰一起輸入到加密算法中,以確保對相同的明文使用相同的密鑰和 IV 時,每次得到的密文都是不同的。
-
Key(密鑰): 密鑰是用于加密和解密數據的機密值。在對稱加密中,加密和解密使用相同的密鑰。保持密鑰的機密性對于加密的安全性至關重要。只有知道密鑰的人才能解密數據。
密鑰應該是足夠長且具有足夠的隨機性,以防止被暴力破解。安全的加密算法強調了密鑰的安全性和保密性,因為知道密鑰的人可以解密被加密的數據。
IV 和密鑰的選擇對于加密的安全性至關重要。合適的 IV 長度和隨機性以及安全的密鑰管理對于確保加密系統的安全性非常重要。IV 和密鑰的選擇取決于所使用的加密算法和具體的安全需求。