我正在尝试了解 OpenSSL 加密。我的要求是解密使用以下代码加密的数据。它正在为接收者创建一个匿名 ID。我需要取回收到的 ID。
根据文档,我了解到使用 EVP_EncryptFinal
进行加密。但是 PKCS5_PBKDF2_HMAC_SHA1
在做什么?
代码使用了 KEY 和 IV。
int create_anon_id(uint32_t recvr_id, uint32_t smartcard_id, const char *hw_id, unsigned char *anon_id)
{
EVP_CIPHER_CTX ctx;
unsigned char ibuf[sizeof(recvr_id) + sizeof(smartcard_id)] = {};
unsigned char obuf[sizeof(ibuf) * 2] = {};
int olen = sizeof(obuf);
/* Convert to big endian. */
recvr_id = bswap32(recvr_id);
smartcard_id = bswap32(smartcard_id);
hw_id = bswap32(hw_id);
/* Fill input buffer with recvr_id | smartcard_id */
memcpy(ibuf, &recvr_id, sizeof(recvr_id));
memcpy(ibuf + sizeof(recvr_id), &smartcard_id, sizeof(smartcard_id));
if (EVP_EncryptInit(&ctx, EVP_des_ede3_cbc(), KEY, IV) == 1)
{
if (EVP_EncryptUpdate(&ctx, obuf, &olen, ibuf, sizeof(ibuf)) == 1)
{
olen = sizeof(obuf) - olen;
if (EVP_EncryptFinal(&ctx, obuf + sizeof(obuf) - olen, &olen) == 1)
{
return PKCS5_PBKDF2_HMAC_SHA1((const char *)obuf, olen, (unsigned char *)hw_id, HW_ID_SIZE, ROUNDS, ANON_ID_BIN_SIZE, anon_id);
}
}
}
}
最佳答案
该代码非常糟糕,尽管运气不好,一些错误被使用恰好是一个三重 DES 数据 block (64 位或 8 字节)的输入所掩盖。如果编码正确,加密将由 EVP_EncryptUpdate
和 EVP_EncryptFinal
完成;如所写,未填充 block 实际使用的唯一加密是由 Update
完成的。
但是 anon_id
中返回的值是NOT (JUST) ENCRYPTED。 PKCS5_PBKDF2_HMAC[_SHA1]
是 PBKDF2 algorithm 的一个实现正如此处所用,它本质上是计算
recvr_id
与smartcard_id
连接(更新:显然没有交换)然后使用KEY
和IV 进行三重 DES 加密
无论这段代码中有什么,作为“密码”hw_id
(更新:显然没有交换,因此“意外”类型有效)作为盐,和 PRF = HMAC-SHA1 for
ROUNDS
(更新:10001)迭代(更新)略微扩展到
ANON_ID_BIN_SIZE
(22) 字节。 (这需要 PBKDF2 的额外“通过”,这实际上会损害安全性;它会减慢防御者的速度而不会减慢攻击者的速度。)
PBKDF2 具有良好的 PRF(HMAC-SHA1 是)是一种单向函数,无法逆转,因为如果您知道或猜出 key ,加密就可以。如果盐和迭代计数选择得当,它还被设计成暴力破解的成本很高。 32 位盐肯定偏低,(更新)ROUNDS 10001 偏低但并不疯狂。
如果 32 位 recvr_id
和 smartcard_id
每个都只包含 16 位熵,那么作为一个更好的例子(对于你作为攻击者),hw_id
,ROUNDS
为1000,这是世纪之交写rfc2898时的推荐值,你要尝试多达256万亿种可能性,典型的桌面计算机在 CPU 上每秒可以处理 30,000,如果运气和技巧可能是 GPU 的 1000 倍,所以这将需要大约 3 个月的时间。
另一方面,如果 32 位输入是完全熵且 ROUNDS
为 1000000,则仅靠计算机是不可能的。如果您有几百万美元可用于 FPGA(或什至更好的 ASIC)以及发电厂(或您自己的水力发电大坝)的输出来运行它们,它仍将需要数百万年。
更新:对于 ROUNDS 10001,您很可能处于这些情况之间,但具体情况在很大程度上取决于输入的熵。
一般来说,这可能不会产生预期的结果。如果输出大小小于或什至大致等于输入的熵,就会发生冲突——产生所需输出的多个输入值(组合),可能很多(数百万,数十亿等)的此类投入。如果您需要原始输入,而不仅仅是产生(伪造)已知输出的一些输入,您将需要一些其他方法或标准来在可能的输入中进行选择暴力破解发现。 更新:对于最多 96 位熵的输出 22 字节,此风险可忽略不计。
关于java - 使用java解密OpenSSL加密数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40003909/