我使用crypto ++编写了一些包装函数来加密/解密文件。我试着查看维基但可以找到我的答案。我想知道是否需要明确销毁我创建的对象?
我在维基中发现,传递给函数的某些对象会被破坏,但没有我确切使用的例子,所以我只想确定。
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();
在此函数中,字节数组由于某种原因被截断
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
答案 0 :(得分:3)
不,你没有。您创建的对象具有automatic storage duration,这意味着它们的析构函数将在其作用域的末尾自动调用。此外,您使用new
传递的参数将由Crypto ++对象拥有,其相应的析构函数将为您释放内存。它们属于接收器或过滤器的类别,事实证明您也传递了所有权。有关详细信息,请参阅:
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
}
我不得不说这是迄今为止我最不喜欢的软件设计风格。可以使用模板和mixin来实现类似的东西(阅读policy based design),没有指针浮动,没有明确的所有权。
答案 1 :(得分:2)
我使用crypto ++编写了一些包装函数来加密/解密文件。我试着查看维基但可以找到我的答案。我想知道是否需要明确销毁我创建的对象?
这取决于。来自 重要使用说明 下的README(列出了两个项目):
如果A的构造函数接受指向对象B的指针(除了诸如int和char之类的基本类型),那么A拥有B并将删除B 在A的破坏。如果A的构造函数引用了一个 对象B,然后调用者保留B的所有权,不应该 消灭它直到A不再需要它。
- 醇>
Crypto ++在类级别是线程安全的。这意味着您可以在多线程应用程序中安全地使用Crypto ++,但您必须提供 多个线程访问公共Crypto ++对象时的同步。
这是你的代码。它看起来不错,不需要改变。但是我们可以通过它来完成(为了简洁,CryptoPP
被删除了):
FileSource(inFile, true, new StreamTransformationFilter(encryptor, new FileSink(outFile)));
FileSource
的堆栈。它是一个自动变量,当它超出范围时会被删除。它的样板C ++。inFile
。它是一个参考,你负责删除它。它的堆栈基于,当它超出调用者的范围时被删除。它的样板C ++。StreamTransformationFilter
创建了new
。它是一个指针,而FileSource
拥有它。它将在FileSource
析构函数运行时删除。管道是一种后天的品味。encryptor
。它是一个参考,你负责删除它。它的堆栈基于,当它超出范围时被删除。它的样板C ++。FileSink
创建了new
。它是一个指针,而StreamTransformationFilter
拥有它。它将在StreamTransformationFilter
析构函数运行时删除。管道是一种后天的品味。outFile
。它是一个参考,你负责删除它。它的堆栈基于,当它超出调用者的范围时被删除。它的样板C ++。这些信息在维基上,但如果您不知道自己在寻找什么,那就很难找到。另请参阅维基上的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);