将PBKDF2与OpenSSL库一起使用 [英] Utilizing PBKDF2 with OpenSSL library

查看:185
本文介绍了将PBKDF2与OpenSSL库一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to utilize the PBKDF2 algorithm with SHA1 HMAC (based on this answer).

我该如何通过密码库来利用它?

How can I utilize this through the crypto library?

我从查看man openssl开始,但使用openssl passwd命令( man页)仅支持少量算法.查看 crypto 文档,

I started by looking at man openssl, but the openssl passwd command (man page) only supports a small handful of algorithms. Looking at the crypto documentation, the evp module has an EVP_BytesToKey method.

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

Careful selection of the parameters will provide a PKCS#5 PBKDF1 compatible implementation. However, new applications should not typically use this (preferring, for example, PBKDF2 from PCKS#5).

这让我回到了最初的问题,我该如何通过加密来利用PBKDF2?我是否需要深入研究代码并调用未公开API的方法(例如

Which brings me back to my original question, how do I utilize PBKDF2 via crypto? Do I need to dig into the code and call a non-API-exposed method (such as PKCS5_PBKDF2_HMAC)? (and if so, what's keeping it from being exposed?)

推荐答案

我确实通过

I do have a working but poor C example of PBKDF2 via the OpenSSL libraries at my github repository, including scripts to compile under both Linux and Windows (via MinGW). Source code located under "Releases" is known good; source code in the master branch is a WIP. This variant is licensed under the same 4-clause BSD in addition to SSLeay license OpenSSL is.

我仍在努力添加一些功能,然后我将回到在Code Review StackExchange网站上获得的出色信息,并升级到C99语法,等等.

I'm still working on adding a few features, then I'll go back to the excellent input I got on the Code Review StackExchange site and upgrade to C99 syntax and so on.

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

The core code is very primitive, and may contain flaws despite passing very extensive string-based test vectors. It has not (yet) been tested against pure binary input.

#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:

If you have a 64-bit system, I would highly recommend moving up to PBKDF2-HMAC-SHA-512 or PBKDF2-HMAC-SHA-384 instead:

#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中).

Regardless of what you choose, be sure to verify it against test vectors (a few are in pbkdf2_test.bat/sh in my repository).

此外,在您的系统上进行一些基准测试-当然是在PBKDF2-HMAC-SHA-384和PBKDF2-HMAC-SHA-512变体上进行的,在64位系统下进行编译可获得明显更好的结果.与我同样贫穷的C ++ Crypto ++ 和/或我可怜的C PolarSSL 示例,或

Additionally, on your system, do some benchmarking - certainly on the PBKDF2-HMAC-SHA-384 and PBKDF2-HMAC-SHA-512 variants, compiling under a 64-bit system produces dramatically better results. Compare it against my equally poor C++ Crypto++ and/or my poor C PolarSSL examples, or Jither's C# implementation example, depending on what your target system is.

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

The reason you care about speed is that you have to choose an iteration count based on the performance your production system has available compared to the number of users logging in/creating passwords at peak times, so as to not generate too many complaints of slowness.

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

Attackers are going to use something like oclHashcat, which on a single PC with 8x AMD R9 290Xstock core clock is able to attempt 3.4E12 (2^41) guesses every 30 days against PBKDF2-HMAC-SHA-1(SSID as salt, password, 32 bytes output length, 4096 iterations, a.k.a. WPA/WPA2), which is more or less equivalent to PBKDF2-HMAC-SHA-1(salt,pw,20 bytes output length, 8192 iterations).

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

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

The difference becomes important when the attacker starts choosing their attacks.

  • 在这两种情况下,攻击者都将使用非常小的密钥进行暴力破解;没有理由不花几分钟甚至几小时去买那些低挂的水果.
    • 这是长度为1-n的所有十六进制字符,然后是长度为n + 1到n + m的所有可打印字符,然后一直沿行直到它们以硬编码变为n + y为止!最后:).
    • In both cases the attacker's going to brute force very small keys; there's no reason not to spend a few minutes or even a few hours on the low hanging fruit.
      • This is all hex characters for length 1-n, and then all printable characters from length n+1 to n+m, and then going on down the line until they're at n+y with a hardcoded ! at the end :).
      • 如果您有1000位用户使用1000种不同的随机盐,并且使用了具有65536次迭代的PBKDF2-HMAC-SHA-1,那么我们的单台PC,8 GPU攻击者(184389 * 64 * 1000)/(8.5E11/30) )天= 0.41天.值得!
      • 如果您有1000位用户使用1000种不同的随机盐,并且使用了具有65536次迭代的PBKDF2-HMAC-SHA-1,那么我们的单台PC,8 GPU攻击者(184389 * 4089 * 1000)/(8.5E11/30) )天= 26.61天.
        • 还是值得的,但这台机器花在一次攻击上的时间将近4周!
        • If you had 1000 users with 1000 different random salts and used PBKDF2-HMAC-SHA-1 with 65536 iterations, that's going to take our single PC, 8 GPU attacker (184389*4089*1000)/(8.5E11/30) days = 26.61 days.
          • Still worth it, but that's almost 4 weeks for this machine to spend on one attack!
          • 完全值得!
          • 如果您有1000位用户使用1000种不同的随机盐,并且使用了具有65536次迭代的PBKDF2-HMAC-SHA-1,则将采用我们的8台PC攻击者(184389 * 35404 * 1000)/(8.5E11/30) )天= 230.39天.
            • 是的,是时候购买更多机器或在非工作时间进行这项工作了.
            • If you had 1000 users with 1000 different random salts and used PBKDF2-HMAC-SHA-1 with 65536 iterations, that's going to take our single PC, 8 GPU attacker (184389*35404*1000)/(8.5E11/30) days = 230.39 days.
              • Right, time to buy more machines or work on this in off times.
              • 值得!只是一个星期的一顿饭.

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

              Now, for PBKDF2, there are a few other things to know:

              • 对于密码哈希,请不要选择大于本地哈希大小的二进制输出大小.就个人而言,无论如何我都不建议二进制输出大小在20个字节以下,因此这对SHA-1有点限制.
                • SHA-1的大小= 20字节
                • SHA-224是20< =大小< = 28字节
                • SHA-256为20< =大小< = 32字节
                • SHA-384是20< =大小< = 48字节
                • SHA-512是20< =大小< = 64字节
                • 当然,如果哈希不是纯二进制格式,则调整哈希的存储方式.
                • 原因:PBKDF2首先运行为一个本机输出大小(上面右侧的数字)请求的迭代次数.如果您还需要更多,它将重新运行整个迭代计数.如果您想要的比这还少,它将被截断.
                • 攻击者只会匹配第一个本机大小-如果第一个字节匹配,是的,那是密码,所以最好增加迭代次数.
                • For password hashing, never select a binary output size larger than the native hash size. Personally, I wouldn't recommend a binary output size under 20 bytes regardless, so that's a bit limiting for SHA-1.
                  • SHA-1 is size = 20 bytes
                  • SHA-224 is 20 <= size <= 28 bytes
                  • SHA-256 is 20 <= size <= 32 bytes
                  • SHA-384 is 20 <= size <= 48 bytes
                  • SHA-512 is 20 <= size <= 64 bytes
                  • adjust for how you store the hash if it's not in pure binary, of course.
                  • Reason: PBKDF2 first run the # of iterations requested for one native output size (the number on the right, above). If you wanted more than that, it runs the entire iteration count all over again. If you wanted less than that, it truncates.
                  • The attacker's only going to match the first native size - if the first bytes match, yes, that's the password, so you're better off increasing your iteration count.

                  这篇关于将PBKDF2与OpenSSL库一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆