簡體   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