我想将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种不同的随机盐,并且使用PBKDF2-HMAC-SHA-1进行了65536次迭代,那将需要我们的一台PC,即8个GPU攻击者(184389 * 64 * 1000)/(8.5E11 / 30)天= 0.41天。非常值得!
现在,如何处理相同的phpbb字典和4089条规则的中型T0X1C规则集?
如果您有1000位用户使用1000种不同的随机盐,并且使用PBKDF2-HMAC-SHA-1进行了65536次迭代,那将需要我们一台PC,即8个GPU攻击者(184389 * 4089 * 1000)/(8.5E11 / 30)天= 26.61天。
仍然值得,但这台机器花在一次攻击上将近4周!
如果您有1000位用户使用1000种不同的随机盐,并且使用PBKDF2-HMAC-SHA-1进行了65536次迭代,那将需要我们一台PC,即8个GPU攻击者(184389 * 4089 * 1000)/(2.7E13 / 30)天= 0.83天。
完全值得的!
现在,如何处理相同的phpbb字典和35404条规则的出色d3ead0ne规则集?
如果您有1000位用户使用1000种不同的随机盐,并且使用PBKDF2-HMAC-SHA-1进行了65536次迭代,那将需要我们一台PC,即8个GPU攻击者(184389 * 35404 * 1000)/(8.5E11 / 30)天= 230.39天。
不错,是时候购买更多机器或在非工作时间进行这项工作了。
如果您有1000位用户使用1000种不同的随机盐,并且使用PBKDF2-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/