试提出一种【强制耗时】的网站密码存储方式
lucifer2011/12/28软件综合 IP:北京
按:最近几天各种网站被曝库的事件让咱大跌眼镜。密码最基本的存储方式是取hash,但是CSDN直到09年才搞……
然而hash的问题也有很多,求碰撞的能力也在逐渐提高。下面打算提出一种改进的密码存储方式。最基本的思想见于XXXXXXyce在人人上分享的资料,但是我没看具体的实现,知道它是需要破解者消耗时间的而已。我尚没有进行详细研究我的算法就匆忙发出来,希望大家一起进行。

先看代码,用PHP实现的:
function myhash($source,$key=''){
    $hash = hash_hmac('whirlpool',$source,$key);
    $match = substr($hash,0,5);
    $padding0 = md5(rand());
    $padding1 = 0;
    while(substr($got = sha1("$hash$padding0$padding1"),0,5)!=$match){
        $padding1++;
    }
    return array("checkstr"=>substr($got,5),"padding"=>"$padding0$padding1");
}
function verify($source,$key,$chkstr,$padding){
    $hash = hash_hmac('whirlpool',$source,$key);
    $match = substr($hash,0,5);
    $sechash = sha1("$hash$padding");
    return ($sechash == "$match$chkstr");
}
print_r($hashresult = myhash("test","key"));
print_r(verify("test","key",$hashresult['checkstr'],$hashresult['padding']));

代码分两部分,myhash函数用于生成一组接受用户密码后需要存储的参数(checkstr,padding)。verify函数用于接受用户稍后给出的输入,然后根据数据库或者什么中记录的(checkstr,padding)信息验证用户的输入是否是之前记录过的信息。

myhash函数的原理如下:
1)根据用户输入,使用HMAC方法生成对应此输入的hash(记作H)。
2)取H的前5字节,记作F。
3)生成一个可以根据一定规律迭代变化的参数P,使得计算 P+H 的 SHA1值时,能存在某个P,使得S=SHA1(P+H)的前5字节等于F。
这一段实际上是借鉴了hashcash算法中的耗时方案。5个16进制字母=20位二进制,为了生成满足这个条件的P,需要平均计算2^19次SHA1才可以找到一个。这就消耗了大量的时间(数个毫秒至数百毫秒,最多一秒,但是不会太短)。
4)将S去除前5字节的数据记作checkstr,满足条件的P记作padding,记录下来以备稍后验证之用。

verify验证函数的原理:
1)同样,根据用户输入,取HMAC,记作H。
2)同样,取H的前5字节,记作F。
3)根据记录的(checkstr,padding),计算S'=SHA1(H+padding)
4)验证S'=H+checkstr。

-------------------------------------
原理讲解完毕。下面我简要分析一下。
首先,myhash函数消耗的时间远远大于verify验证函数消耗的时间。这是可以容忍的,因为网站登录的请求一般大于注册请求。控制注册请求的负载也有很多方法。

其次,根据数据库中的checkstr,padding值能否推出可以登录的密码?我认为困难:
根据刚才的验证机制,我们看到,padding是贴在用户输入的首次hash后面,进行第二次hash的字符串。必须满足如下“方程”:

SHA1(padding+HMAC)==HMAC[0:5]+checkstr(认为padding和checkstr是常数)

才可能登录。也就是说,试图登录而不知道密码的人,必须构造一个密码,使得它通过了HMAC函数(值得注意的是,这里采用了whirlpool进行HMAC方法,这个算法的输出长度与SHA-512相当;此外,对于不同的新注册用户,HMAC的另一个参数key也完全可以不同。不同key下的HMAC函数简直相当于不同的散列函数,对于破解者的要求还有提高)后,满足如上条件。具体这种概率有多少,我也不清楚,直观上似乎比构造碰撞的概率低(因为checkstr几乎具有和SHA1一样的长度——实际上是少了5个字节——而且SHA1相当于是加了salt=padding的)。这里请大家分析。
+200  科创币    科创网    2011/12/28 赞扬
来自:计算机科学 / 软件综合
5
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
lucifer 作者
13年1个月前 IP:未同步
348542
引用第1楼ltl于2011-12-28 15:53发表的  :
我觉得最简单的方法就是拿3个不同的Hash函数(MD5,SHA1,再加一个非常规Hash函数),并分别截取一截,接起来记录即可

密码学第一定律:Eve(偷窥者)永远知道Alice和Bob采用的算法。或者说,不要将安全性寄托在算法的保密上。
如果考虑这个定律,这个方法只要能做到N字长输出,那么50%概率产生碰撞的机会就是在原文中修改2^(N-1)处(生日攻击,应该说是比较通用的)。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
lucifer作者
13年1个月前 IP:未同步
348548
引用第2楼婺源寻芳于2011-12-28 19:07发表的  :
一般设计原则不是让倒推密码困难(基本必须不可能),而是让verify花时间。

我的反而是让计算花了时间。但——这样至少避免了制作大量的字典的可能——而且如果让验证花时间多,对负载大的服务器的影响又是如何呢?
我的设计思想是让穷举破解我那个方程:

SHA1(padding+X)=X[0:5]+checkstr

时浪费时间。因为X的选取修改了SHA1给出的解。如果想要让方程右侧保持不变,X至少是5位十六进制字符串。此时方程右面为(偷窥者自己定出的常数),需要产生一个碰撞的话,方程左面相当于给定salt(=padding)碰撞SHA1。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
lucifer
学者 笔友
文章
12
回复
119
学术分
1
2010/09/13注册,6年11个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}