Crypto ++在加密/解密期间显式破坏?
Posted
技术标签:
【中文标题】Crypto ++在加密/解密期间显式破坏?【英文标题】:Crypto++ explicit destruction during encryption/decryption? 【发布时间】:2017-07-21 13:40:43 【问题描述】:我编写了一些包装函数来使用 crypto++ 加密/解密文件。我尝试在 wiki 中查找,但可以找到我的答案。我想知道是否需要显式销毁创建的对象?
我在 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();
一旦在这个函数中,字节数组由于某种原因被截断
加密文件
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
【问题讨论】:
【参考方案1】:不,你没有。您创建的对象有automatic storage duration,这意味着它们的析构函数将在其作用域结束时自动调用。此外,您使用new
传递的参数将归 Crypto++ 对象所有,它们相应的析构函数将为您释放内存。它们属于 sink 或 filter 的类别,事实证明您也传递了所有权。更多详情见:
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
我不得不说,这是迄今为止我最不喜欢的软件设计风格。一个人可以使用模板和 mixin 来实现类似的事情(阅读 policy based design),而没有指针浮动,没有明确的所有权。
【讨论】:
很棒的解释!谢谢!是的,我还没有遇到过这种类型的设计。 @hbchevelle68 这是一个很好的问题,我记得当我第一次遇到 Crypto++ 时,我问过自己同样的问题。我仍然认为他们的设计可以改进。 本地创建的对象或提供线程同步的全局对象,怎样才能更好地扩展?对象的本地创建和销毁可能会影响性能,因为它们是从同一个堆中分配的。【参考方案2】:我编写了一些包装函数来使用 crypto++ 加密/解密文件。我尝试在 wiki 中查找,但可以找到我的答案。我想知道是否需要显式销毁创建的对象?
这取决于。来自重要使用说明下的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++。
您已使用new
创建了StreamTransformationFilter
。它是一个指针,FileSource
拥有它。当FileSource
析构函数运行时,它将被删除。管道是一种后天习得的品味。
你有encryptor
。它是一个参考,你有责任删除它。它基于堆栈,超出范围时将被删除。它的样板 C++。
您已使用new
创建了FileSink
。它是一个指针,StreamTransformationFilter
拥有它。当StreamTransformationFilter
析构函数运行时,它将被删除。管道是一种后天习得的品味。
你有outFile
。它是一个参考,你有责任删除它。它基于堆栈,并且在超出调用者范围时被删除。它的样板 C++。
信息在 wiki 上,但如果您不知道自己在寻找什么,就很难找到。另请参阅 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);
【讨论】:
哇,我得到了 2 个超级棒的答案。走过有助于使整个事情的头成为尾,我真的很感激。我继续并听取了您对字节指针的建议,感谢您的收获! 在集成字节指针后,我做了检查以验证大小,它仍然会降级到大小 8(从 16)。有什么想法吗? @hbchevelle68 - 我们需要看看您是如何调用encrypt_file
和decrypt_file
的。如果是SecByteBlock key
,只需使用key, key.size()
。如果是std::string key
,则使用reinterpret_cast<const byte*>(&key[0]), key.size()
。
我继续编辑发布以显示我如何调用它以及密钥生成和输出。
您可以使用key, sizeof(key)
调用函数。在调用者中,sizeof(key)
将是 AES::DEFAULT_KEYLENGTH
。但是,一旦进入被调用函数,byte key[AES::DEFAULT_KEYLENGTH]
就会降级为大小为 4 (i686) 或 8 (x86_64) 的指针。以上是关于Crypto ++在加密/解密期间显式破坏?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Crypto++ 中使用 RSA OAEP SHA-256 加密/解密数据
crypto-js 与 php-mcrypt AES 加密/解密
Harmony OSARK UIets使用第三方类库crypto实现加密解密
Windows 2000 和 Windows 2003 RC2 使用 Windows Crypto API 加密/解密?