我正在尝试使用OpenSSL的PKCS5_PBKDF2_HMAC_SHA1方法。我认为如果成功则返回0,否则返回其他值。我的问题是,非零回报值意味着什么?内存错误?使用错误?我的程序应如何处理它(重试,退出?)?
编辑:一个必然的问题是,除了对方法本身进行逆向工程之外,还有什么方法可以解决这个问题吗?
答案 0 :(得分:4)
除了对方法本身进行逆向工程外,还有什么方法可以解决这个问题吗?
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
引擎的库代码。
请注意,如果是第3代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
或其他源代码浏览器。