encryption/decryption 期间 Crypto++ 显式销毁?

Crypto++ explicit destruction during encryption/decryption?

我使用 crypto++ 向 encrypt/decrypt 文件编写了一些包装函数。我尝试查看维基,但可以找到我的答案。我想知道我是否需要显式销毁我创建的对象?

我在 wiki 中发现传递给函数的一些对象会为您销毁,但没有我确切使用的示例,所以我只是想确定一下。

   CryptoPP::AutoSeededRandomPool prng;
   //Key generation
   byte key[AES::DEFAULT_KEYLENGTH];
   prng.GenerateBlock(key, sizeof(key));
   //IV generation
   byte iv[AES::BLOCKSIZE];
   prng.GenerateBlock(iv, sizeof(iv));



   //print key
   encoded.clear();
   StringSource(key, sizeof(key), true, new HexEncoder(new StringSink(encoded)));
   cout << "key: " << encoded << endl;
   cout << "Size of key: " << sizeof(key) << endl;

   //print iv
   encoded.clear();
   StringSource(iv, sizeof(iv), true, new HexEncoder(new StringSink(encoded)));
   cout << "iv: " << encoded << endl;
   cout << "Size of iv: " << sizeof(iv) << endl;

   //See function below
   encrypt_file(inFile, outFile, key, iv, err); 

   inFile.close();
   outFile.close();

一旦在此函数中,字节数组由于某种原因被截断

Encrypt_file

    bool encrypt_file(std::ifstream& inFile,
       std::ofstream& outFile,
       const byte* key, const byte* iv,
       std::string& errMsg)
    {
       std::string encoded;
       //print key
       encoded.clear();
       StringSource(key, sizeof(key), true, new HexEncoder(new StringSink(encoded)));
       cout << "key: " << encoded << endl;
       cout << "Size of key: " << sizeof(key) << endl;

       //print iv
       encoded.clear();
       StringSource(iv, sizeof(iv), true, new HexEncoder(new StringSink(encoded)));
       cout << "iv: " << encoded << endl;
       cout << "Size of iv: " << sizeof(iv) << endl;
       try {
          CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption e;
          e.SetKeyWithIV(key, sizeof(key), iv);
          CryptoPP::FileSource(inFile, true, new CryptoPP::StreamTransformationFilter(e, new CryptoPP::FileSink(outFile)));
          inFile.close();
          outFile.close();
       }
       catch (CryptoPP::Exception& e) {
          errMsg = e.GetWhat();
          return false;
       }
       return true;
    }

输出:

key: 6574D7BDFD0DD3BC59CD3846D4A196A8
Size of key: 16
iv: 1B4ED692F91A32246B41F63F6B8C6EAA
Size of iv: 16
key: 6574D7BDFD0DD3BC
Size of key: 8
iv: 1B4ED692F91A3224
Size of iv: 8

不,你不知道。您创建的对象具有 automatic storage duration,这意味着它们的析构函数将在其作用域结束时自动调用。此外,您通过 new 传递的参数将归 Crypto++ 对象所有,它们相应的析构函数将为您释放内存。它们属于 sinkfilter 的类别,结果你也传递了所有权。欲了解更多详情,请参阅:

https://www.cryptopp.com/wiki/Pipelining#Ownership

基本上是这样的(超级简化的例子):

#include <iostream>

struct Foo{};

class X
{
    Foo *p_;
public:
    X(Foo* p): p_(p) {}
    // we'd also need a copy ctor and copy assignment operator, ignored here
    ~X()
    {
        std::cout << "Releasing the memory...\n";
        delete p_;
    }
};

int main()
{
    X x(new Foo()); // sinking, no memory leak
}

Live on Coliru

我不得不说,这是迄今为止我最不喜欢的软件设计风格。人们可以使用模板和混入来实现类似的事情(阅读 policy based design),而不需要指针在没有明确所有权的情况下四处浮动。

I wrote some wrapper functions to encrypt/decrypt files using crypto++. I tried looking in the wiki but could find my answer. I am wondering if I need to explicitly destroy my objects that are created?

视情况而定。来自Important Usage Notes下的README(列出两项):

  1. If a constructor for A takes a pointer to an object B (except primitive types such as int and char), then A owns B and will delete B at A's destruction. If a constructor for A takes a reference to an object B, then the caller retains ownership of B and should not destroy it until A no longer needs it.

  2. Crypto++ is thread safe at the class level. This means you can use Crypto++ safely in a multithreaded application, but you must provide synchronization when multiple threads access a common Crypto++ object.

这是您的代码。它看起来不错,不需要更改。但是为了完整起见,我们可以遍历它(为简洁起见,删除了 CryptoPP):

FileSource(inFile, true, new StreamTransformationFilter(encryptor, new FileSink(outFile)));
  1. 你有基于堆栈的FileSource。它是一个自动变量,当它超出范围时会被删除。它的样板 C++。
  2. 你有 inFile。它是参考,您有责任删除它。它是基于堆栈的,当它超出调用者的范围时就会被删除。它的样板 C++。
  3. 您已使用 new 创建了 StreamTransformationFilter。它是一个指针,FileSource 拥有它。当 FileSource 析构函数运行时,它将被删除。管道是一种后天的品味。
  4. 你有 encryptor。它是参考,您有责任删除它。它基于堆栈,超出范围时将被删除。它的样板 C++。
  5. 您已使用 new 创建了 FileSink。它是一个指针,StreamTransformationFilter 拥有它。当 StreamTransformationFilter 析构函数运行时,它将被删除。管道是一种后天的品味。
  6. 你有 outFile。它是参考,您有责任删除它。它是基于堆栈的,当它超出调用者的范围时就会被删除。它的样板 C++。

信息在 wiki 上,但如果您不知道要查找什么,则很难找到。另请参阅维基上的 Pipelining | Ownership


相关,这看起来很可疑:

e.SetKeyWithIV(key, sizeof(key), iv);

因为key是声明为... byte key[], byte iv[] ...的函数参数,我相信它decays to a pointer的大小为4(i686)或8(x86_64)。您应该使用类似于以下内容的内容,它允许您指定数组的大小:

bool encrypt_file(std::ifstream& inFile,
    std::ofstream& outFile,
    const byte* key, size_t ksize,
    const byte* iv, size_t vsize,
    std::string& errMsg)
{
    ...
    e.SetKeyWithIV(key, ksize, iv);
    ...
}

所以,给定:

byte key[AES::DEFAULT_KEYLENGTH];
prng.GenerateBlock(key, sizeof(key));
byte iv[AES::BLOCKSIZE];
prng.GenerateBlock(iv, sizeof(iv));

然后这样称呼它:

encrypt_file(inFile, outFile, key, sizeof(key), iv, sizeof(iv), err);