首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >(Crypto++)如何实现媒体文件加密?

(Crypto++)如何实现媒体文件加密?
EN

Stack Overflow用户
提问于 2020-04-20 01:05:48
回答 1查看 2K关注 0票数 5

我是Crypto++的新手,希望将我在网上找到的文本加密代码“转换”为Crypto++文件加密。基本上,一个图像文件只是一堆文本,需要用块来读取,对吗?

我想读取一个图像文件并用CryptoPP::AES加密它

代码语言:javascript
复制
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而不是文本读取文件?

EN

回答 1

Stack Overflow用户

发布于 2020-08-30 22:42:05

如果我正确理解这段代码,它会设置一个随机密钥和一个随机IV (不知道这意味着什么),并使用CFB_MODE::Encryption方法加密来自plainText变量的给定文本。

正确,该代码生成大小为128位的随机AES密钥和大小为128位的随机初始化向量(IV)。可以调整密钥大小以增加加密强度(也可以有256位密钥),而IV的大小必须等于AES块大小(128位),这与密钥大小无关。因此,在这种情况下,两者都是128位只是巧合。

分组密码模式被设置为CFB (参考文献 )。分组密码模式的动机是,我们不希望在输入的不同位置出现相同的数据块进行相同的加密。否则,就有可能从加密的数据中推断出原始数据的某些结构,如链接文章中的图像文件示例所示。为了避免这个问题,块密码模式以某种方式将当前块中的纯文本与前一个块组合在一起。CFB的数学细节在链接文章中得到了解释,但基本上它将使用前一个块的加密来异或明文。

第一个块是特例,因为它没有以前的块。IV用作第一个块的“前一个块”(因此IV需要等于块大小)。IV不需要是秘密的(与密钥不同),但是应该为每条加密的消息随机选择它,以防止攻击者推断消息的结构信息。

如何将此代码更改为加密作为参数的文件,并使用std::ifstream而不是文本读取文件?

要将加密应用于文件,可以使用FileSourceFileSink类,这些类由crypto++提供:

代码语言:javascript
复制
// 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}}};
}

这将“泵”所有数据从源到接收器,应用给定的转换。在这种情况下,源是输入文件,接收器是输出文件,转换是加密。

通常,不鼓励通过new进行手动内存管理,而倾向于使用智能指针或其他更高级别的抽象。然而,crypto++ API似乎早于这一指导方针,因此我们无法使用new,然后再信任crypto++为我们分配这些分配。

您也可以将文件名直接传递给FileSourceFileSink (参考文献参考文献),但是由于您专门询问了std::ifstream,所以我在示例中使用了它。

加密和解密的完整示例:

代码语言:javascript
复制
#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;
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61313699

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档