[英](Crypto++) How to realize media file encryption?
我是 Crypto++ 的新手,想將我在網上找到的文本加密代碼“轉換”為 Crypto++ 文件加密。 基本上,圖像文件只是一堆需要分塊讀取的文本,對嗎?
我想讀取圖像文件並使用CryptoPP::AES對其進行加密:
void encryptImage(std::filesystem::path const& file) {
std::ifstream inpf(file.string().c_str(), std::ios::binary);
CryptoPP::AutoSeededRandomPool rnd;
int keyLength = CryptoPP::AES::DEFAULT_KEYLENGTH; // 16 bytes = 128 bit key
int defBlockSize = CryptoPP::AES::BLOCKSIZE;
// Generate a random key
CryptoPP::byte key[CryptoPP::AES::DEFAULT_KEYLENGTH];
rnd.GenerateBlock(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
// Generate a random IV
CryptoPP::byte iv[CryptoPP::AES::BLOCKSIZE];
rnd.GenerateBlock(iv, CryptoPP::AES::BLOCKSIZE);
char plainText[] = "Hello! How are you.";
int messageLen = (int)strlen(plainText) + 1;
//encrypt
CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption cfbEncryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH, iv);
cfbEncryption.ProcessData((CryptoPP::byte*)plainText, (CryptoPP::byte*)plainText, messageLen);
}
如果我正確理解這段代碼,它會設置一個隨機密鑰和一個隨機 IV(不知道這應該是什么意思)並使用CFB_MODE::Encryption方法從plainText變量中加密給定的文本。
我現在的問題是...如何更改此代碼,以便它加密我作為參數提供的文件並使用std::ifstream而不是文本讀取?
如果我正確理解這段代碼,它會設置一個隨機密鑰和一個隨機 IV(不知道這應該是什么意思)並使用 CFB_MODE::Encryption 方法從 plainText 變量中加密給定的文本。
正確,代碼生成大小為 128 位的隨機 AES 密鑰和大小為 128 位的隨機初始化向量 (IV)。 可以調整密鑰大小以增加加密強度(即您也可以擁有 256 位密鑰),而 IV 的大小必須等於 AES 塊大小(128 位),這與密鑰無關尺寸。 所以在這種情況下兩者都是 128 位只是一個巧合。
分組密碼模式設置為 CFB( 參考)。 分組密碼模式的動機是我們不希望出現在輸入中不同位置的相同數據塊具有相同的加密。 否則,可以從加密數據中推斷出原始數據的某些結構,如鏈接文章中的圖像文件示例所示。 為了避免這個問題,分組密碼模式以某種方式將來自當前塊的純文本與前一個塊結合起來。 CFB 的數學細節在鏈接文章中進行了解釋,但基本上它會將明文與前一個塊的加密進行異或。
第一個塊是一種特殊情況,因為它沒有前一個塊。 IV 用作第一個塊的“前一個塊”(因此為什么 IV 需要等於塊大小)。 IV 不需要保密(與密鑰不同),但應該為每個加密消息隨機選擇它,以防止攻擊者推斷有關消息結構的信息。
如何更改此代碼,以便它加密我作為參數提供的文件並使用 std::ifstream 而不是文本讀取?
要將加密應用於文件,可以使用 crypto++ 提供的FileSource
和FileSink
類:
// Type aliases for key and IV
using aes_key_t = std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH>;
using aes_iv_t = std::array<CryptoPP::byte, CryptoPP::AES::BLOCKSIZE>;
void encrypt(const aes_key_t &key, const aes_iv_t &iv,
const std::string &filename_in, const std::string &filename_out) {
CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption cipher{};
cipher.SetKeyWithIV(key.data(), key.size(), iv.data());
std::ifstream in{filename_in, std::ios::binary};
std::ofstream out{filename_out, std::ios::binary};
CryptoPP::FileSource{in, /*pumpAll=*/true,
new CryptoPP::StreamTransformationFilter{
cipher, new CryptoPP::FileSink{out}}};
}
這會將所有數據從源“泵”到接收器,應用給定的轉換。 在這種情況下,源是輸入文件,接收器是 output 文件,轉換是加密。
一般來說,不鼓勵通過new
進行手動 memory 管理,而是使用智能指針或其他更高級別的抽象。 但是,crypto++ API 似乎早於本指南,因此我們無法繞過使用new
然后信任 crypto++ 為我們delete
這些分配。
您也可以將文件名直接傳遞給FileSource
和FileSink
(參考、參考),但由於您特別詢問了std::ifstream
,我在示例中使用了它。
加密和解密的完整示例:
#include <cryptopp/files.h>
#include <cryptopp/modes.h>
#include <cryptopp/osrng.h>
#include <fstream>
#include <iostream>
using aes_key_t = std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH>;
using aes_iv_t = std::array<CryptoPP::byte, CryptoPP::AES::BLOCKSIZE>;
void encrypt(const aes_key_t &key, const aes_iv_t &iv,
const std::string &filename_in, const std::string &filename_out) {
CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption cipher{};
cipher.SetKeyWithIV(key.data(), key.size(), iv.data());
std::ifstream in{filename_in, std::ios::binary};
std::ofstream out{filename_out, std::ios::binary};
CryptoPP::FileSource{in, /*pumpAll=*/true,
new CryptoPP::StreamTransformationFilter{
cipher, new CryptoPP::FileSink{out}}};
}
void decrypt(const aes_key_t &key, const aes_iv_t &iv,
const std::string &filename_in, const std::string &filename_out) {
CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption cipher{};
cipher.SetKeyWithIV(key.data(), key.size(), iv.data());
std::ifstream in{filename_in, std::ios::binary};
std::ofstream out{filename_out, std::ios::binary};
CryptoPP::FileSource{in, /*pumpAll=*/true,
new CryptoPP::StreamTransformationFilter{
cipher, new CryptoPP::FileSink{out}}};
}
int main(int argc, char **argv) {
std::cout << CryptoPP::AES::BLOCKSIZE << std::endl;
CryptoPP::AutoSeededRandomPool rng{};
// Generate a random key
aes_key_t key{};
rng.GenerateBlock(key.data(), key.size());
// Generate a random IV
aes_iv_t iv{};
rng.GenerateBlock(iv.data(), iv.size());
// encrypt
encrypt(key, iv, "abc.jpg", "abc_encrypted");
// decrypt
decrypt(key, iv, "abc_encrypted", "abc_decrypted.jpg");
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.