【问题标题】:What does PKCS5_PBKDF2_HMAC_SHA1 return value mean?PKCS5_PBKDF2_HMAC_SHA1 返回值是什么意思?
【发布时间】:2014-05-16 02:52:11
【问题描述】:

我正在尝试使用 OpenSSL 的 PKCS5_PBKDF2_HMAC_SHA1 方法。我认为如果成功则返回 0,否则返回其他值。我的问题是,非零返回值是什么意思?内存错误?使用错误?我的程序应该如何处理它(重试,退出?)?

编辑:一个必然的问题是,除了对方法本身进行逆向工程之外,还有什么方法可以解决这个问题?

【问题讨论】:

标签: error-handling openssl pbkdf2


【解决方案1】:

除了对方法本身进行逆向工程之外,还有其他方法可以解决这个问题吗?

PKCS5_PBKDF2_HMAC_SHA1 看起来像是那些未记录的函数之一,因为我在 OpenSSL docs 中找不到它。 OpenSSL 有很多,所以如果你要使用这个库,你应该准备好研究源代码。


如果成功则返回 0,否则返回其他值。

实际上,它反过来了。这是我知道的...

$ grep -R PKCS5_PBKDF2_HMAC_SHA1 *
crypto/evp/evp.h:int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
crypto/evp/p5_crpt2.c:int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
...

所以,你在crypto/evp/p5_crpt2.c中找到了函数的实现:

int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
                           const unsigned char *salt, int saltlen, int iter,
                           int keylen, unsigned char *out)
    {
        return PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter,
                                 EVP_sha1(), keylen, out);
    }

关注PKCS5_PBKDF2_HMAC:

$ grep -R PKCS5_PBKDF2_HMAC *
...
crypto/evp/evp.h:int PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
crypto/evp/p5_crpt2.c:int PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
...

再一次,来自crypto/evp/p5_crpt2.c:

int PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
                      const unsigned char *salt, int saltlen, int iter,
                      const EVP_MD *digest,
                      int keylen, unsigned char *out)
{
    unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4];
    int cplen, j, k, tkeylen, mdlen;
    unsigned long i = 1;
    HMAC_CTX hctx_tpl, hctx;

    mdlen = EVP_MD_size(digest);
    if (mdlen < 0)
        return 0;

    HMAC_CTX_init(&hctx_tpl);
    p = out;
    tkeylen = keylen;
    if(!pass)
        passlen = 0;
    else if(passlen == -1)
        passlen = strlen(pass);
    if (!HMAC_Init_ex(&hctx_tpl, pass, passlen, digest, NULL))
    {
        HMAC_CTX_cleanup(&hctx_tpl);
        return 0;
    }
    while(tkeylen)
    {
        if(tkeylen > mdlen)
            cplen = mdlen;
        else
            cplen = tkeylen;
        /* We are unlikely to ever use more than 256 blocks (5120 bits!)
         * but just in case...
         */
        itmp[0] = (unsigned char)((i >> 24) & 0xff);
        itmp[1] = (unsigned char)((i >> 16) & 0xff);
        itmp[2] = (unsigned char)((i >> 8) & 0xff);
        itmp[3] = (unsigned char)(i & 0xff);
        if (!HMAC_CTX_copy(&hctx, &hctx_tpl))
        {
            HMAC_CTX_cleanup(&hctx_tpl);
            return 0;
        }
        if (!HMAC_Update(&hctx, salt, saltlen)
            || !HMAC_Update(&hctx, itmp, 4)
            || !HMAC_Final(&hctx, digtmp, NULL))
        {
            HMAC_CTX_cleanup(&hctx_tpl);
            HMAC_CTX_cleanup(&hctx);
            return 0;
        }
        HMAC_CTX_cleanup(&hctx);
        memcpy(p, digtmp, cplen);
        for(j = 1; j < iter; j++)
        {
            if (!HMAC_CTX_copy(&hctx, &hctx_tpl))
            {
                HMAC_CTX_cleanup(&hctx_tpl);
                return 0;
            }
            if (!HMAC_Update(&hctx, digtmp, mdlen)
                || !HMAC_Final(&hctx, digtmp, NULL))
            {
                HMAC_CTX_cleanup(&hctx_tpl);
                HMAC_CTX_cleanup(&hctx);
                return 0;
            }
            HMAC_CTX_cleanup(&hctx);
            for(k = 0; k < cplen; k++)
                p[k] ^= digtmp[k];
        }
        tkeylen-= cplen;
        i++;
        p+= cplen;
    }
    HMAC_CTX_cleanup(&hctx_tpl);

    return 1;
}

所以它看起来像 0 失败,1 成功。您不应该看到其他值。如果你得到一个0,那么所有OUT 参数都是垃圾。


内存错误?使用错误?

嗯,有时您可以致电ERR_get_error。如果你调用它并且它是有意义的,那么错误代码是好的。如果错误代码没有意义,那么它可能不好。

很遗憾,这是我处理它的方式,因为库与设置错误代码不一致。例如,这里是加载 RDRAND 引擎的库代码。

注意代码会在失败时清除错误代码如果它是第三代 Ivy Bridge(这是正在测试的功能),否则不会清除或设置错误!!!

void ENGINE_load_rdrand (void)
{
    extern unsigned int OPENSSL_ia32cap_P[];

    if (OPENSSL_ia32cap_P[1] & (1<<(62-32)))
    {
        ENGINE *toadd = ENGINE_rdrand();
        if(!toadd) return;
        ENGINE_add(toadd);
        ENGINE_free(toadd);
        ERR_clear_error();
    }
}

我的程序应该如何处理它(重试,退出?)?

这看起来像是一个严重的失败。


最后,这正是我在这种情况下浏览资源的方式。如果您不喜欢grep,可以尝试ctags 或其他源代码浏览器。

【讨论】:

  • 通过“我的程序应该如何处理它?”,我的意思是,这是否意味着 OpenSSL 做错了什么(逻辑错误),还是意味着我做错了什么(使用错误)?还是其他原因(例如,内存错误)?
  • @dafrazzman - 对,这取决于失败。但是 OpenSSL 并没有给你一个返回值来区分。很烂,但就是这样。
猜你喜欢
  • 2013-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-09
相关资源
最近更新 更多