我不知道有任何关于 MySQL 的已发表密码分析OLD_PASSWORD()
,但它太弱了,简直是个笑话。它可以作为密码学课程中的练习。
更新: 类似于下面描述的中间相遇的密码分析发表在2006 年国际信息安全和密码学会议 - ICISC 2006上的F. Muller 和 T. Peyrin “基于 T 函数的散列函数的密码分析”,具有更通用的描述,并进行了一些优化以查找短密码并保存在 RAM 中。
例如,这是一个“恢复”内部状态的 C 代码:
static int
oldpw_rev(uint32_t *pnr, uint32_t *pnr2, uint32_t add,
unsigned char *cc, unsigned len)
{
uint32_t nr, nr2;
uint32_t c, u, e, y;
if (len == 0) {
return 0;
}
nr = *pnr;
nr2 = *pnr2;
c = cc[len - 1];
add -= c;
u = nr2 - nr;
u = nr2 - ((u << 8) ^ nr);
u = nr2 - ((u << 8) ^ nr);
nr2 = nr2 - ((u << 8) ^ nr);
nr2 &= 0x7FFFFFFF;
y = nr;
for (e = 0; e < 64; e ++) {
uint32_t z, g;
z = (e + add) * c;
g = (e ^ z) & 0x3F;
if (g == (y & 0x3F)) {
uint32_t x;
x = e;
x = y ^ (z + (x << 8));
x = y ^ (z + (x << 8));
x = y ^ (z + (x << 8));
nr = y ^ (z + (x << 8));
nr &= 0x7FFFFFFF;
if (oldpw_rev(&nr, &nr2, add, cc, len - 1) == 0) {
*pnr = nr;
*pnr2 = nr2;
return 0;
}
}
}
return -1;
}
当在数组len
中给出的密码字符(和,两个 31 位字,以及密码字符之和的值)之后给出内部状态时,此函数计算插入密码之前和之前的有效解人物。这是有效的。cc[]
nr
nr2
add
nr
nr2
这导致了一个简单的中间相遇攻击。考虑 14 个小写 ASCII 字母的序列,这样每个字母后面跟着它的补码('a' 的补码是 'z','b' 的补码是 'y',等等......)。大约有 80 亿个这样的序列。请注意,任何这些序列的字符总和始终是固定值 1533。取其中N个序列;对于它们中的每一个,用 计算相应的哈希OLD_PASSWORD()
值,并将值累积到一个大文件中:每个条目包含字符序列,以及对应的nr
and nr2
。然后按 62 位nr
/nr2
对对文件进行排序。这个文件是一个大表:“使用这个序列,我们从初始值到那个 内部状态”。
然后再次获取N个序列,这次使用oldpw_rev()
(如上所示)对它们中的每一个,使用实际被攻击的散列作为起点,对于nr
和nr2
2*1533 == 3066 add
。这将为您提供N其他对nr
/ nr2
,每对都有相应的序列。这些值累积在另一个文件中,您再次按 62 位nr
/nr2
对排序。第二个文件是一个大表:“在那个内部状态上使用这个序列,我们获得了我们当前正在攻击的哈希值”。
此时您只需找到两个匹配的对,即第一个文件和第二个文件中的相同nr
/ nr2
。相应的 14 个字符序列是与哈希输出匹配的 28 个字符密码的两半。这可能不是最初使用的密码,但这是一个将哈希到相同值并被 MySQL 接受的密码。当N达到 20 亿左右时,您获得匹配对的可能性很高(我们在大小为2 62的空间中,因此N大约为sqrt(2 62 )就足够了)。
这种攻击的工作因数约为2 37(考虑到排序步骤),远小于理论上可以使用具有 62 位输出的哈希函数实现的2 62工作因数(对于适当的安全性来说,这已经太低了) )。因此,该OLD_PASSWORD()
功能被密码破解。
(可能有比这更好的攻击。)