cryptography - 将PBKDF2与OpenSSL库一起使用

标签 cryptography openssl pbkdf2

我想将PBKDF2算法与SHA1 HMAC结合使用(基于this答案)。

我如何通过加密库利用它?

我从查看man openssl开始,但是openssl passwd命令(man page)仅支持少数算法。查看crypto文档,evp模块具有EVP_BytesToKey方法。


仔细选择参数将提供与PKCS#5 PBKDF1兼容的实现。但是,新应用程序通常不应使用此功能(例如,首选PCKS#5的PBKDF2)。


这使我回到最初的问题,如何通过加密使用PBKDF2?我是否需要深入研究代码并调用未公开API的方法(例如PKCS5_PBKDF2_HMAC)? (如果是这样,什么使它不被暴露?)

最佳答案

通过my github repository处的OpenSSL库,我确实有一个工作正常但效果不佳的PBKDF2 C示例,包括在Linux和Windows(通过MinGW)下均可编译的脚本。位于“发布”下的源代码众所周知。 master分支中的源代码是WIP。除了SSLeay许可OpenSSL之外,此变体还根据相同的4条款BSD许可。

我仍在努力添加一些功能,然后我将回到在Code Review StackExchange网站上获得的出色输入,并升级到C99语法,依此类推。

核心代码非常原始,尽管通过了非常广泛的基于字符串的测试向量,但仍可能包含缺陷。尚未(尚未)针对纯二进制输入进行过测试。

#include <openssl/evp.h>
#include <openssl/sha.h>
// crypto.h used for the version
#include <openssl/crypto.h>

void PBKDF2_HMAC_SHA_1nat_string(const char* pass, const unsigned char* salt, int32_t iterations, uint32_t outputBytes, char* hexResult)
{
    unsigned int i;
    unsigned char digest[outputBytes];
    PKCS5_PBKDF2_HMAC_SHA1(pass, strlen(pass), salt, strlen(salt), iterations, outputBytes, digest);
    for (i = 0; i < sizeof(digest); i++)
        sprintf(hexResult + (i * 2), "%02x", 255 & digest[i]);
}


如果您使用的是64位系统,我强烈建议您升级到PBKDF2-HMAC-SHA-512或PBKDF2-HMAC-SHA-384:

#include <openssl/evp.h>
#include <openssl/sha.h>
// crypto.h used for the version
#include <openssl/crypto.h>


void PBKDF2_HMAC_SHA_384_string(const char* pass, const unsigned char* salt, int32_t iterations, uint32_t outputBytes, char* hexResult)
{
    unsigned int i;
    unsigned char digest[outputBytes];
    PKCS5_PBKDF2_HMAC(pass, strlen(pass), salt, strlen(salt), iterations, EVP_sha384(), outputBytes, digest);
    for (i = 0; i < sizeof(digest); i++)
        sprintf(hexResult + (i * 2), "%02x", 255 & digest[i]);
}

void PBKDF2_HMAC_SHA_512_string(const char* pass, const unsigned char* salt, int32_t iterations, uint32_t outputBytes, char* hexResult)
 {
     unsigned int i;
     unsigned char digest[outputBytes];
     PKCS5_PBKDF2_HMAC(pass, strlen(pass), salt, strlen(salt), iterations, EVP_sha512(), outputBytes, digest);
     for (i = 0; i < sizeof(digest); i++)
         sprintf(hexResult + (i * 2), "%02x", 255 & digest[i]);
 }    


使用的一个例子是:

// 2*outputBytes+1 is 2 hex bytes per binary byte, 
// and one character at the end for the string-terminating \0
char hexResult[2*outputBytes+1];
memset(hexResult,0,sizeof(hexResult));
PBKDF2_HMAC_SHA_1nat_string(pass, salt, iterations, outputBytes, hexResult);
printf("%s\n", hexResult);


要么

// 2*outputBytes+1 is 2 hex bytes per binary byte, 
// and one character at the end for the string-terminating \0
char hexResult[2*outputBytes+1];
memset(hexResult,0,sizeof(hexResult));
PBKDF2_HMAC_SHA_512_string(pass, salt, iterations, outputBytes, hexResult);
printf("%s\n", hexResult);


使用8-16个二进制字节(即16-32个十六进制数字)的按用户使用的随机盐-我的代码尚无生成此示例的示例

不管您选择什么,都一定要针对测试向量进行验证(其中一些在我的存储库中的pbkdf2_test.bat / sh中)。

此外,在您的系统上进行一些基准测试-当然是在PBKDF2-HMAC-SHA-384和PBKDF2-HMAC-SHA-512变体上进行的,在64位系统下进行编译会产生明显更好的结果。将其与my equally poor C++ Crypto++和/或my poor C PolarSSL示例或Jither's C# implementation example进行比较,具体取决于目标系统是什么。

您关心速度的原因是,与高峰时间登录/创建密码的用户数量相比,您必须根据生产系统提供的性能来选择迭代计数,以免产生太多的速度慢的抱怨。

攻击者将使用类似oclHashcat的东西,在具有8个AMD R9 290Xstock核心时钟的单台PC上,它可以每30天尝试针对PBKDF2-HMAC-SHA-1(SSID为盐)进行3.4E12(2 ^ 41)猜测,密码,32个字节的输出长度,4096个迭代(又名WPA / WPA2),它或多或少与PBKDF2-HMAC-SHA-1(salt,pw,20个字节的输出长度,8192个迭代)等效。


如果您使用65536次迭代,则攻击者每30天只能尝试8.5E11(〜2 ^ 39)个猜测。
如果使用1024次迭代,攻击者将每30天尝试2.7E13(〜2 ^ 44)次猜测。


当攻击者开始选择攻击时,区别变得很重要。


在这两种情况下,攻击者都将使用非常小的密钥进行暴力破解。没有理由不花几分钟甚至几个小时来买那些低挂的水果。

这是长度为1-n的所有十六进制字符,然后是长度为n + 1到n + m的所有可打印字符,然后一直沿行直到它们达到n + y并经过硬编码!在末尾 :)。

在这两种情况下,攻击者都将使用较小的词典和较小的规则集。说出184389个单词的phpbb词典和Best64规则集

如果您有1000位用户使用1000种不同的随机盐,并且使用PB​​KDF2-HMAC-SHA-1进行了65536次迭代,那将需要我们的一台PC,即8个GPU攻击者(184389 * 64 * 1000)/(8.5E11 / 30)天= 0.41天。非常值得!

现在,如何处理相同的phpbb字典和4089条规则的中型T0X1C规则集?

如果您有1000位用户使用1000种不同的随机盐,并且使用PB​​KDF2-HMAC-SHA-1进行了65536次迭代,那将需要我们一台PC,即8个GPU攻击者(184389 * 4089 * 1000)/(8.5E11 / 30)天= 26.61天。

仍然值得,但这台机器花在一次攻击上将近4周!

如果您有1000位用户使用1000种不同的随机盐,并且使用PB​​KDF2-HMAC-SHA-1进行了65536次迭代,那将需要我们一台PC,即8个GPU攻击者(184389 * 4089 * 1000)/(2.7E13 / 30)天= 0.83天。

完全值得的!


现在,如何处理相同的phpbb字典和35404条规则的出色d3ead0ne规则集?

如果您有1000位用户使用1000种不同的随机盐,并且使用PB​​KDF2-HMAC-SHA-1进行了65536次迭代,那将需要我们一台PC,即8个GPU攻击者(184389 * 35404 * 1000)/(8.5E11 / 30)天= 230.39天。

不错,是时候购买更多机器或在非工作时间进行这项工作了。

如果您有1000位用户使用1000种不同的随机盐,并且使用PB​​KDF2-HMAC-SHA-1进行了65536次迭代,那将需要我们一台PC,即8个GPU攻击者(184389 * 4089 * 1000)/(2.7E13 / 30)天= 7.18天。

值得!才一个星期吃饭。




现在,对于PBKDF2,还有一些其他要知道的事情:


对于密码哈希,请不要选择大于本地哈希大小的二进制输出大小。就个人而言,无论如何我都不建议二进制输出大小在20个字节以下,因此这对SHA-1有点限制。

SHA-1的大小= 20字节
SHA-224是20 <=大小<= 28字节
SHA-256是20 <=大小<= 32字节
SHA-384是20 <=大小<= 48字节
SHA-512是20 <=大小<= 64字节
当然,请调整散列的存储方式(如果它不是纯二进制格式的话)。
原因:PBKDF2首先运行一个本机输出大小(上面右边的数字)请求的迭代次数。如果您想要的更多,它将再次运行整个迭代计数。如果您想要的还不够,它将被截断。
攻击者只会匹配第一个本机大小-如果第一个字节匹配,是的,那就是密码,因此最好增加迭代次数。

关于cryptography - 将PBKDF2与OpenSSL库一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22795471/

相关文章:

javascript - 将 OpenSSL 命令行 AES 加密映射到等效的 NodeJS Crypto API

node.js - 使用异步等待时为 "Error: No callback provided to pbkdf2"

Java-Python AES加密解密

encryption - 如何将二进制私钥文件转换为openssl可接受的pem格式

ios - 字符串加密 AES PBKDF2

java - 更改加密文件的 AES key 而不解密/重新加密它

c++ - 生成随机数 C++

java - Sha256 不提供 16 字节数组

c# - RNGCryptoServiceProvider 不会为相同的 PWD、Salt、Iteration 组合生成相同的哈希值

node.js - 为 Facebook-messenger bot 应用程序设置 webhook 时的自签名证书问题