繁体   English   中英

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

[英](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++ 提供的FileSourceFileSink类:

// 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这些分配。

您也可以将文件名直接传递给FileSourceFileSink参考参考),但由于您特别询问了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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM