[英](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.