加密/解密过程中加密++显式破坏?

时间:2022-06-04 18:30:19

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?

我写了一些使用crypto ++加密/解密文件的包装函数。我试过在维基中查找,但可以找到我的答案。我想知道我是否需要明确地销毁我创建的对象?

I found in the wiki that some objects when passed into functions are destroyed for you, but no examples of my exact use were there so I just wanted to be sure.

我在维基中发现,传递给函数的某些对象会被破坏,但是没有我确切使用的例子,所以我只想确定。

   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();

Once in this function the bytes arrays are truncated for some reason

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

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;    }

Output:

key: 6574D7BDFD0DD3BC59CD3846D4A196A8Size of key: 16iv: 1B4ED692F91A32246B41F63F6B8C6EAASize of iv: 16key: 6574D7BDFD0DD3BCSize of key: 8iv: 1B4ED692F91A3224Size of iv: 8

2 个解决方案

#1


3  

No, you don't. The objects you create have automatic storage duration, which means their destructor will be automatically invoked at the end of their scope. Moreover, the arguments that you pass with new will be owned by the Crypto++ objects, and their corresponding destructor will release the memory for you. They fall into the category of a sink or a filter, and it turns out that you also pass the ownership. For more details see:

不,你没有。您创建的对象具有自动存储持续时间,这意味着它们的析构函数将在其作用域结束时自动调用。此外,您传递给new的参数将由Crypto ++对象拥有,并且它们相应的析构函数将为您释放内存。它们属于接收器或过滤器的类别,事实证明您也通过了所有权。有关更多详情,请参阅

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

Basically this is what happens (super simplified example):

基本上这就是发生的事情(超简化示例):

#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

住在Coliru

I have to say that this is by far my least favourite style of software design. One can use templates and mixins to probably achieve similar things (read about policy based design), without pointers floating around with no clear ownership.

我不得不说这是迄今为止我最不喜欢的软件设计风格。可以使用模板和mixin来实现类似的东西(阅读基于策略的设计),没有指针浮动,没有明确的所有权。

#2


2  

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?

我写了一些使用crypto ++加密/解密文件的包装函数。我试过在维基中查找,但可以找到我的答案。我想知道我是否需要明确地销毁我创建的对象?

It depends. From the README under Important Usage Notes (the two items are listed):

这取决于。从重要使用说明下的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.

    如果A的构造函数接受指向对象B的指针(除了诸如int和char之类的基本类型),则A拥有B并将在A的销毁时删除B.如果A的构造函数接受对象B的引用,则调用者保留B的所有权,并且在A不再需要它之前不应销毁它。

  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.

    Crypto ++在类级别是线程安全的。这意味着您可以在多线程应用程序中安全地使用Crypto ++,但是当多个线程访问公共Crypto ++对象时,您必须提供同步。

Here's your code. It looks good, and it will not need to be changed. But we can walk though it for completeness (the CryptoPP were removed for brevity):

这是你的代码。它看起来不错,而且不需要更改。但我们可以通过它来完成(为简洁而删除了CryptoPP):

FileSource(inFile, true, new StreamTransformationFilter(encryptor, new FileSink(outFile)));
  1. you have the stack based FileSource. Its an automatic variable and it is deleted when it goes out of scope. Its boilerplate C++.
  2. 你有基于堆栈的FileSource。它是一个自动变量,当它超出范围时会被删除。它的样板C ++。

  3. you have inFile. Its a reference, you are responsible for deleting it. Its stack based, and it is deleted when it goes out of scope in the caller. Its boilerplate C++.
  4. 你有inFile。它是一个参考,你负责删除它。它的堆栈基于,当它超出调用者的范围时被删除。它的样板C ++。

  5. you have the StreamTransformationFilter created with new. Its a pointer and the FileSource owns it. It will be deleted when the FileSource destructor runs. Pipelines are an acquired taste.
  6. 你有使用new创建的StreamTransformationFilter。它是一个指针,FileSource拥有它。它将在FileSource析构函数运行时删除。管道是一种后天的味道。

  7. you have encryptor. Its a reference, you are responsible for deleting it. Its stack based, and it is deleted when it goes out of scope. Its boilerplate C++.
  8. 你有加密器。它是一个参考,你负责删除它。它的堆栈基于,当它超出范围时被删除。它的样板C ++。

  9. you have the FileSink created with new. Its a pointer and the StreamTransformationFilter owns it. It will be deleted when the StreamTransformationFilter destructor runs. Pipelines are an acquired taste.
  10. 你有新的FileSink创建。它是一个指针,StreamTransformationFilter拥有它。当StreamTransformationFilter析构函数运行时,它将被删除。管道是一种后天的味道。

  11. you have outFile. Its a reference, you are responsible for deleting it. Its stack based, and it is deleted when it goes out of scope in the caller. Its boilerplate C++.
  12. 你有文件。它是一个参考,你负责删除它。它的堆栈基于,当它超出调用者的范围时被删除。它的样板C ++。

The information is on the wiki, but its kind of hard to find if you don't know what you are looking for. Also see Pipelining | Ownership on the wiki.

这些信息在维基上,但如果您不知道自己在寻找什么,那就很难找到。另见Pipelining |维基上的所有权。


Related, this looks suspect:

相关,这看起来很可疑:

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

Because key is a function parameter declared as ... byte key[], byte iv[] ..., I believe it decays to a pointer with a size of 4 (i686) or 8 (x86_64). You should use something like the following, which allows you to specify the size of the array:

因为key是一个声明为... byte key [],byte iv [] ...的函数参数,我相信它会衰减到一个大小为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);    ...}

So, given:

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

Then call it like so:

然后像这样调用它:

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

#1


3  

No, you don't. The objects you create have automatic storage duration, which means their destructor will be automatically invoked at the end of their scope. Moreover, the arguments that you pass with new will be owned by the Crypto++ objects, and their corresponding destructor will release the memory for you. They fall into the category of a sink or a filter, and it turns out that you also pass the ownership. For more details see:

不,你没有。您创建的对象具有自动存储持续时间,这意味着它们的析构函数将在其作用域结束时自动调用。此外,您传递给new的参数将由Crypto ++对象拥有,并且它们相应的析构函数将为您释放内存。它们属于接收器或过滤器的类别,事实证明您也通过了所有权。有关更多详情,请参阅

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

Basically this is what happens (super simplified example):

基本上这就是发生的事情(超简化示例):

#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

住在Coliru

I have to say that this is by far my least favourite style of software design. One can use templates and mixins to probably achieve similar things (read about policy based design), without pointers floating around with no clear ownership.

我不得不说这是迄今为止我最不喜欢的软件设计风格。可以使用模板和mixin来实现类似的东西(阅读基于策略的设计),没有指针浮动,没有明确的所有权。

#2


2  

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?

我写了一些使用crypto ++加密/解密文件的包装函数。我试过在维基中查找,但可以找到我的答案。我想知道我是否需要明确地销毁我创建的对象?

It depends. From the README under Important Usage Notes (the two items are listed):

这取决于。从重要使用说明下的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.

    如果A的构造函数接受指向对象B的指针(除了诸如int和char之类的基本类型),则A拥有B并将在A的销毁时删除B.如果A的构造函数接受对象B的引用,则调用者保留B的所有权,并且在A不再需要它之前不应销毁它。

  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.

    Crypto ++在类级别是线程安全的。这意味着您可以在多线程应用程序中安全地使用Crypto ++,但是当多个线程访问公共Crypto ++对象时,您必须提供同步。

Here's your code. It looks good, and it will not need to be changed. But we can walk though it for completeness (the CryptoPP were removed for brevity):

这是你的代码。它看起来不错,而且不需要更改。但我们可以通过它来完成(为简洁而删除了CryptoPP):

FileSource(inFile, true, new StreamTransformationFilter(encryptor, new FileSink(outFile)));
  1. you have the stack based FileSource. Its an automatic variable and it is deleted when it goes out of scope. Its boilerplate C++.
  2. 你有基于堆栈的FileSource。它是一个自动变量,当它超出范围时会被删除。它的样板C ++。

  3. you have inFile. Its a reference, you are responsible for deleting it. Its stack based, and it is deleted when it goes out of scope in the caller. Its boilerplate C++.
  4. 你有inFile。它是一个参考,你负责删除它。它的堆栈基于,当它超出调用者的范围时被删除。它的样板C ++。

  5. you have the StreamTransformationFilter created with new. Its a pointer and the FileSource owns it. It will be deleted when the FileSource destructor runs. Pipelines are an acquired taste.
  6. 你有使用new创建的StreamTransformationFilter。它是一个指针,FileSource拥有它。它将在FileSource析构函数运行时删除。管道是一种后天的味道。

  7. you have encryptor. Its a reference, you are responsible for deleting it. Its stack based, and it is deleted when it goes out of scope. Its boilerplate C++.
  8. 你有加密器。它是一个参考,你负责删除它。它的堆栈基于,当它超出范围时被删除。它的样板C ++。

  9. you have the FileSink created with new. Its a pointer and the StreamTransformationFilter owns it. It will be deleted when the StreamTransformationFilter destructor runs. Pipelines are an acquired taste.
  10. 你有新的FileSink创建。它是一个指针,StreamTransformationFilter拥有它。当StreamTransformationFilter析构函数运行时,它将被删除。管道是一种后天的味道。

  11. you have outFile. Its a reference, you are responsible for deleting it. Its stack based, and it is deleted when it goes out of scope in the caller. Its boilerplate C++.
  12. 你有文件。它是一个参考,你负责删除它。它的堆栈基于,当它超出调用者的范围时被删除。它的样板C ++。

The information is on the wiki, but its kind of hard to find if you don't know what you are looking for. Also see Pipelining | Ownership on the wiki.

这些信息在维基上,但如果您不知道自己在寻找什么,那就很难找到。另见Pipelining |维基上的所有权。


Related, this looks suspect:

相关,这看起来很可疑:

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

Because key is a function parameter declared as ... byte key[], byte iv[] ..., I believe it decays to a pointer with a size of 4 (i686) or 8 (x86_64). You should use something like the following, which allows you to specify the size of the array:

因为key是一个声明为... byte key [],byte iv [] ...的函数参数,我相信它会衰减到一个大小为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);    ...}

So, given:

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

Then call it like so:

然后像这样调用它:

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