使用Crypto ++ pbkdf2 :: DeriveKey()的罕见崩溃

时间:2018-11-07 23:36:27

标签: c++ crypto++ pbkdf2

我正在使用CryptoPP库对一些密码进行哈希处理。大约有十分之一的次数,它在下面的DeriveKey行上崩溃,并带有段错误。

即使使用固定参数,崩溃仍然是随机的。我想知道我的字符串结尾是否需要'\ 0'。还是可能需要将输出缓冲区初始化为零,还是其他?

无论如何,这是代码。

#include <cryptopp/aes.h>
#include <cryptopp/algparam.h>
#include <cryptopp/filters.h>
#include <cryptopp/modes.h>
#include <cryptopp/sha.h>
#include <cryptopp/pwdbased.h>

int main()
{
CryptoPP::PKCS5_PBKDF2_HMAC<CryptoPP::SHA256> pbkdf2;

CryptoPP::byte salt[16];

CryptoPP::byte key[32];

/* Hard coded for testing purposes */
Common::podFromHex("00f8807a289655b2a8e38cda00182a32", salt);

/* Hard coded for testing purposes */
std::string password = "a";

std::cout << "Salt: " << Common::podToHex(salt) << std::endl;
std::cout << "Salt size: " << sizeof(salt) << std::endl;
std::cout << "Password: " << password.data() << std::endl;
std::cout << "Password size: " << password.size() << std::endl;

/* Rare segfault on this line */
pbkdf2.DeriveKey(
    key, sizeof(key), 0, (CryptoPP::byte *)password.data(),
    password.size(), salt, sizeof(salt), Constants::PBKDF2_ITERATIONS
);
}

一切似乎都已正确初始化-每次打印语句都会给我完全相同的东西:

Salt: 00f8807a289655b2a8e38cda00182a32
Salt size: 16
Password: a
Password size: 1

此外-散列密码不分段时可以使用。稍后我将使用AES加密,并且可以完全解密该文件,并且所有数据均符合预期。

可以通过以下方式找到派生密钥的源代码:https://www.cryptopp.com/docs/ref/pwdbased_8h_source.html#l00235

谢谢。

2 个答案:

答案 0 :(得分:3)

我很冒险,但是salt并非以NULL结尾。该程序可能正在访问salt数组的第16个元素之外:

std::cout << "Salt: " << Common::podToHex(salt) << std::endl;

以下命令可以多次执行而不会出现问题。它是您的程序,而不是对Common库的调用。

std::memcpy的调用仅占用字符串的最左16个字节。它不执行转换。 (我只想删除对Common的调用。)

$ cat test.cxx

#include "cryptlib.h"
#include "filters.h"
#include "sha.h"
#include "hex.h"
#include "files.h"
#include "pwdbased.h"

#include <string>
#include <iostream>
#include <cstring>

int main()
{
    using namespace CryptoPP;

    PKCS5_PBKDF2_HMAC<SHA256> pbkdf2;

    byte salt[16], key[32];

    /* Hard coded for testing purposes */
    // Common::podFromHex("00f8807a289655b2a8e38cda00182a32", salt);
    std::memcpy(salt, "00f8807a289655b2a8e38cda00182a32", 16);

    /* Hard coded for testing purposes */
    std::string password = "a";

    // std::cout << "Salt: " << Common::podToHex(salt) << std::endl;
    std::cout << "Salt: ";
    StringSource(salt, sizeof(salt), true, new HexEncoder(new FileSink(std::cout)));
    std::cout << std::endl;

    std::cout << "Salt size: " << sizeof(salt) << std::endl;
    std::cout << "Password: " << password.data() << std::endl;
    std::cout << "Password size: " << password.size() << std::endl;

    /* Rare segfault on this line */
    pbkdf2.DeriveKey(
        key, sizeof(key), 0, (byte *)password.data(),
        password.size(), salt, sizeof(salt), 10000 /*Constants::PBKDF2_ITERATIONS*/
    );

    std::cout << "Key: ";
    StringSource(key, sizeof(key), true, new HexEncoder(new FileSink(std::cout)));
    std::cout << std::endl;

    return 0;
}

编译并执行:

$ g++ -DNDEBUG -g2 -O3 test.cxx -o test.exe ./libcryptopp.a
$ ./test.exe
Salt: 30306638383037613238393635356232
Salt size: 16
Password: a
Password size: 1
Key: F88BA6947B802C66F7E7A2BC0099AFD92C81DC293E3CC48C2DA3FA75E27ECE6B

答案 1 :(得分:0)

我最终解决了这个问题。这实际上不是由于上面列出的任何代码,而是因为我在信号处理程序中使用此函数调用了函数。

由于运行(使用500,000次迭代)需要花费相当长的时间,因此每次似乎都在此处崩溃,但这实际上不是由于此行引起的。

我最终通过在信号处理程序中翻转bool标志来修复它,并有一个单独的线程监视该标志。设置该标志后,它调用了析构函数,该析构函数又触发了正常的关闭流程,从而允许我所有的线程关闭并正确保存。