关于个人钱包安全性方面,一直有个既重要又争议不断的话题,即何为“脑钱包”?——利用个人大脑记忆中的密码生成所得的私钥来储存资金。从理论上看,脑钱包是作为长期安全存储手段的最理想方式:只要在不使用的情况下被保存,就不易被物理偷窃(实物)或被黑客偷窃;别人连你有钱包这件事都不会知道。然而,也有很多人对脑钱包持反对意见。他们认为人类大脑是极为脆弱的,故不适用于生产或存储长期且易碎的密码秘密。此外,要想在现实生活中实现该做法也非易事。到底哪一方是正确的呢?我们的记忆力是否足以保护我们的私钥安全?说到底,一切都取决于脑钱包产生的过程。
关于“熵”
假如目前面临的挑战是创造一个即容易记忆又安全的脑钱包,那么有两个变量值得我们考量:1)人们需要记忆多少信息;2)多长的密码才不容易被黑客破解。事实证明,所面临着的挑战与这两个变量间的关系十分密切。假定一些特定的特殊技巧缺失,而黑客又运行了一组最优算法攻击,且两组完全等效(更确切一点,一组遵循另一组数据大小的变化)。那么我们一开始就应该分别处理这两个问题。
计算机专家、加密学家和数学家常用一段包含“熵”的数据来衡量“信息量”的大小。笼统来说,“熵”被定义为与合理信息量的对数具有相同“形式”的既定信息。例如,数字57035。“57035”看似有五位数字,但其实有10万个。16.6位熵大约包含的数字:log(216.6) ~= 10000(个)。数字61724671282457125412459172541251277是一串35位的长数据,根据log(1035) ~= 116.3(位),故实际包含116.3位熵。一个0和1的随机字符串的位长正好包含n位熵。因此可得出结论,字符越长熵越多,熵越多字符中符号的选择也就越多。
另一方面,数字11111111111111111111111111234567890长度远小于116.3位熵;尽管它拥有35位数,但这串数字并不是35-位数字。35-位数字属于一个相当高的水平;一整张纸的数字上可能罗列有几十亿个数字,但它也许只有30位的熵。
信息理论中有些比较正式的定义,试图理清这个直观概念。一个被称为Kolmogorov复杂性的观点受到广泛热议;一个位数序列的复杂性指可以打印出这个序列,然后停止运行的最短的计算机程序的长度。在Python语言中,上述字符也可表达为1**26+234567890*——长度为18个字符的字符串。而61724671282457125412459172541251277则需要37个字符(实际数字+引号)。这就使我们对“高结构字符串类”的概念有了更加正式的理解:这些字符串仅是简单地对一组少量数据的集取。请注意,我们还能使用其他的数字处理策略;比如,1112111111112211111111111111111112111这样一组不平衡的字符串,;通过创建代表多个1s序列的特殊符号,能至少被切割成二分之一大。霍夫曼编码是创建这样一种交换理论信息的最佳算法的最佳示例。,
最后需注意的是,“熵”依赖于语境。“一直敏捷的棕色狐狸跳过了懒狗(the quick brown fox jumped over the lazy dog)”这句简单的霍夫曼编码序列可能超过100个字节。但是因为我们会英语,又因为有很多理论文章和论文用过上面这句相同的话(即我们对这段话很熟悉),所以熵的实际数量约为25个字节——姑且将其称为“狐狗语(fox dog phrase)”。
那么,熵到底有什么意义呢?从本质上说,熵就是你需要记忆的信息量大小。熵越多就越难记忆。因此,(从设定密码的角度看)人们既想熵尽量的少,又想难以被破解,两者是鱼与熊掌的关系。
强度
现在,我们进入下个问题:做好密码防范措施,防止黑客入侵。最好通过黑客猜出密码的次数作为密码安全性的衡量标准。破解随机生成的密码,最简单粗暴的方法就是使用“蛮力”:先尝试所有可能的1字符的密码,再尝试2个字符,以此类推。鉴于密码可能有n个字母,k个长度,所以破解时间大致需要n*k之久。因此,使用的密码字符越多越好,长度越长越好。
Steve Gibson的草垛密码:密码长又多,且容易记忆。这是怎么做到的呢?
请问:以下哪个密码更安全?哪个更容易被破解?
D0g…………………
PrXyc.N(n4k77#L!eVdAfp9
你可能看出来这是道陷阱题。答案是:第一个。第一个密码不仅“非常”便于使用且容易记忆,重要的是,它比下个密码要强得多!其实,第一个密码是一串较长的字符。其中同时包含了大写字母、小写字母、一个数字和一些特殊符号。故要想破解这类密码需花费比第二个这样不可能记忆的密码多费95倍的时间。
Steve写道:“几乎所有人都一直认为或被告知通过“高熵”密码能派生出密码自身的强度。”但正如我们所看到的,这种“智慧”是。。。不正确的!”理由是,它依赖于那些被广泛使用的特定攻击属性。如果这一做法变得广泛起来,就会促使黑客发明一种专门的方法来解决这个漏洞。此外,还有一个广义的攻击:只要给予一定数量的密码泄露样本就可以自动更新解决一切事物,请参考:马尔科夫链样本。
该算法的工作方式如下:假设你的密码字母符号中仅包含字符0和1。从样本中得知,0之后的一位数有65%的机会是1,有35%的机会是0;1后面的一位数有20%的机会是0,80%的机会是1。随机选取样本,创建一个包含这些概率的有限状态机,并将其放在一个简单额度循环过程中:
Python代码如下:
import random
i = 0
while 1:
if i == 0:
i = 0 if random.randrange(100) < 35 else 1
elif i == 1:
i = 0 if random.randrange(100) < 20 else 1
print i
我们挑出输出信号,将其分解,就能模仿出人们实际使用密码的方式。我们能够将这两种字符总结到一个完整的字母表,甚至可以跟踪这一状态:不只是最后一个字符,也可以是倒数两个,或三个或更多。所以,如果人人都开始使用“D0g…………………”这样的字符,那么在看了数千个马尔科夫链之后,我们可以“学习”人们常使用的长字符串。如果它输出了一段时期,那么它有可能暂时停留在打印出的几个步骤循环周期之内——即具有一定概率性的复制人的行为。
有一个问题被忽略了,即如何终止循环。代码仅是一串包含了0和1的无限字符。我们可以在字母表中引入一个伪符号来表示一个字符串的结尾,并把观测到的符号出现频率放入马尔可夫链概率中,但不适用于以上这个例子——因为越远的密码大多比较短,故其输出的密码也比较段,所以在尝试较长密码前,会对短密码进行数百万次的尝试重复。因此,我们可能想人工将其切断到一定长度,并随着时间推移增加长度。这种方法被称为“语言模式”——按照需要,字符或词的序列既可以简单粗略,也可以错综复杂。
Gibson策略失败、其他类似的策略也不可行的根本原因在于,熵的定义和强度是一对有趣的相等量。熵是可能性数量的对数,而力则是可能性数量。简而言之, 记忆能力和攻击能力完全恒定等量的!无论是从字母表还是从偏向性表中(如“1”的几率为80%,“0”的几率为20%)中随机挑选字符,这条定理都适用。这样看来,想要一个既安全又方便记忆的密码是没有希望了。。。
简化记忆,加强攻击难度
希望么。。。也不一定没有。尽管我们知道需要记忆的熵的数量和攻击者需要闯入的空间大小是完全相同的。现实生活中,我们可以将复杂的等式将其变成我们的优势。
最重要的是,人类储存记忆的方式不像电脑;我们准确记住信息的方式往往取决于记忆方式和形式。例如,潜意识中我们能记住几千字节的人脸,但相同字节数量的狗脸却很难记住,文本形式的信息更是难上加难——但如果同时在视觉和口头上记忆的话,会相对容易点。
有些人已尝试利用这一优势来生成随机脑钱包,并用一系列数字将其编码;例如,我们会看到如下这句话:
witch collapse practice feed shame open despair creek road again ice least
有一组热门漫画XCD说明了这一原理:用户通过生成4个随机单词来创建密码。这种方法看似简洁,也不需要我们记住复这些随机的符号和语言。但事实证明,这种方法行不通。
近期来自卡内基梅隆大学的Richard Shay和其他一些学者发表了以下这份报告:
以1,476人为样本做了一份在线调查。调查结果显示3-4位字符的系统分配密码、5-6位的系统随机分配密码及8位 的系统分配的发音密码。出人意料的是,系统分配密码口令与我们之前调查的可用量熵系统结果相似。口令及密码被遗忘的速率相当,导致用户困难和烦恼的程度也相当。然而,参与者通过口令方式登录需花费更多的时间。口令输入错误的话,还得花费更长时间进行重新登录。看来减少字符使用选择、降低口令数量或允许用户更改密码顺序的可用性似乎还是没有提高。
然而,报告中还是给我们留了一丝希望。其中指出,可以有办法通过提高熵来提密码的高密码的安全性,同时又方便记忆。随机、发音的字符串类似“zelactudet”(通过某种抽样语言模型建立的词)似乎不仅能提供一个适当的单词列表还能随机生成字符串。
一个可能的解释是,发音密码能同时作为声音和一系列字母被记忆,从而增加了字符长度。这样看来,在不缩减密码长度的前提下,我们至少能有一种提高记忆力的方法。
另一种策略则是对另一端产生的问题进行攻击:在不增加熵的前提下,是密码尽可能难的被破解。我们不能通过加入更多的组合使密码难以破解,因为这会增加熵的数量,但如果我们利用一种被称为硬密钥导出函数的东西。例如,假设人们记忆中的脑钱包为b,不适用私钥sha256(b) 或 sha3(b),将其称为为F(b, 1000),F的定义如下:
def F(b, rounds):
x = b
i = 0
while i < rounds:
x = sha3(x + b)
i += 1
return x
从本质上看,我们一遍又一遍的把b代回哈希函数,直到1000个循环后,将数值输出。
每个循环中,将原始数据代回不是必须严格执行的,但密码学家们推荐这样做以限制预先被计算的“彩虹表”遭到攻击时受到的影响。这样一来,检查一组独立密码需要经过很多次运算。你,作为一名合法用户,不会注意到其中的差别——是20微秒而不是20毫秒——在无需记住任何东西的情况下,就可以免费获得10位熵。如果达到30000次循环,那么能得到15位熵,但计算一次密码需费时约1秒,20位需费时20秒,超过最高限额23位的话就不能使用了。
现在,我们有一个能走得更远的办法:可外包的超级土豪——KDFs。该办法利用一组函数,而运行这组函数代价非常昂贵(如,240计算步骤),但我们也可以在不计算实体功能的前提下得到输出数据。最简便,但密码也是最复杂的。利用“已盲”函数,即 unblind(F(blind(x))) = F(x),“致盲”和“解盲”需要一个一次性的随机生成密码。随后计算“盲(即密码)”,然后将工作交给第三方最好是和ASIC合作。最后当你得到结果的时候再“解盲。”
这方面的一个例子是使用椭圆曲线加密:在仅为80位而非256位的“值”处生成一条弱曲线。即通过取一个值的哈希函数,来计算值X,并在曲线上找到相关联的y,然后我们通过添加一个随机生成的点N(点N与私钥相关),“致盲”(x,y)点,最后将结果交给一台服务器破解。一旦服务器得出与私钥相对应的N + (x,y),减去n,便可得出私钥所对应的(x,y)点——即我们想要的结果。服务器不会知道这个值包含了什么信息,甚至连(x,y)是什么也不会知道——理论上任何东西都有可能和N因素相关。请注意,用户能即时验证工作——只需将得到的私钥转换到一个“点”,并确保该点为(x,y).
另一种方法则不怎么依赖于弱椭圆曲线的代数特性:利用哈希函数从一组密码中导出20个seeds,对每个都使用一个非常难的工作证明问题(如,计算f(h) = n,n能使sha3(n+h) < 2^216),在最后使用一个中等强度的KDF和值绑定。除非20个服务器都串通好(如果用户使用Tor的话就可以避免这种情况发生。因为,攻击者不可能掌控或100%关注网络从相同用户处产生的结果),否则该协议就是十分安全的。
这两种协议有意思的地方在于,它们很容易对区块链转化成一种”有益的工作证明”的共识算法;任何人都可以在链上提交工作,区块链将执行计算,两个椭圆离散曲线对数和基于哈希函数的工作证明都很容易被证明。这个计划最棒的部分在于,用户利用计算机计算函数产生的费用变成社会使用,且攻击者的成本更加昂贵。如果区块链对工作证明提供资助,那么通过提交工作给区块链是攻击者尝试破解用户密码的最佳方式。但现实生活中,像计算一个密码需进行240次工作这种级别的安全性,脑钱包个其他的密码会变得非常安全以至没人愿意花费时间和精力去破解。
熵“差”
现在到了最后一步,也是最有意思的一步:记忆方法。从上面讨论中可知,熵是一段信息中的信息量,信息量等于攻击的复杂性——除非你使用昂贵的KDFs故意降低处理过程。然而,关于熵还有一点需要被提及,这点至关重要:熵依赖于语境。对我们而言,“Mahmoud Ahmadjinejad”这个名字可能有10到15位熵。但对那些生活在伊朗的人,总统“Mahmoud Ahmadjinejad”可能只有4位熵——在VIP名人榜单中他很有可能排在前16位。我不了解你的父母或配偶,所以对我而言他们的名字可能有20位熵,但对你而言可能只有2-3位熵。
这是怎么一回事呢?从形式上看,最好的办法就是想想每个人 之前的生活经验创造 某种压缩算法,更具不同的压缩算法或不同的编程语言,相同的字符串可以得到不同的柯尔莫哥洛夫复杂性。在Python语言中,111111111111111111* 即1**18,但在Java脚本中111111111111111111*是Array(19).join(“1*)。在Python算法的一个假象版本中,将变量x预设为111111111111111111*,就只是个“x”。最后再举个例子,虽然挺起来比较做做,但其实最能说明现实世界:人的心灵就像是一台基于我们过去经验,有着许多不同预设的机器。
现在,我们继续深入地来看一下这个问题。现在,选择书中的一个短语或歌曲作为自己的密码被普遍嘲笑为是一个不值钱的方法。但为什么这个方法曾经很诱人呢?因为它看似善于利用差异:一组短语可能有超过100位的熵,但你只需要记得书名、书页和行数即可。但问题是,别人也能看到这本书。黑客要想做一个能强行攻击与该信息相关的所有书籍、歌曲和电影的程序是件非常简单的事。
这个建议其实不值钱。为什么这么说?如果仅作为密码的一部分,那么从书、歌曲或者电影中截取信息是一个不错的选择。理由很简单:它制造了差异。从你最喜欢的歌曲里摘选一句歌词对你而言只有几位熵。但不是所有人都喜欢这首歌,所以对其他人来说这句歌词可能有10或20为熵。最佳策略是挑选你真的很喜欢的书或歌曲,但也最大限度晦涩难懂的(小众)——降低自己的熵从而提高他人的熵。当然,在你的用户名前追加一些随机的字符(甚至一些随意组成的单词,如“zelactudet”),并利用安全的KDF。
结论
拥有多少位熵才算是安全的?眼下,破解密码的芯片每秒可尝试236次破解,比特币矿工每秒可以运行约240次哈希函数(即1 terahash)。整个比特币网络,总计进行 250次/tahashes,即约257次哈希函数/秒。密码学家普遍认为,280是可接受的最小安全水平。要想有80位熵,你需要约17个随机英文字母或12个随机字母、数字和符号。然而,我们可以降低点标准:一个用户名有15位,一个好的KDF有15位,从歌曲或书籍中摘选的所写能有10位,剩下的40多位仍用旧计划中的随机选择。如果你用的KDF不是很好,也可以选择其他密码成分。
信息安全专家普遍认为取消密码必然是不安全的,他们主张要对密码设定方案进行彻头彻尾的更换。一种常见的说法是,基于摩尔定律我们知道攻击者的力量没2年会增加1位熵,故为保护密码安全,人们不得不记住越来越长的密码。但是,这一说法不完全正确。如果你使用强力KDF,那么基于摩尔定律,一旦攻击者增长攻击力量,用户便能获取增长的这部分力量。
若真如上述说法,除KDFs(较温和的,不是可被外包的那种)外,暂时还没有其他选择。总而言之,密码目前依然保持着过去所拥有的安全性,并继续作为一种强大的安全策略要素存在——但不是唯一要素。像同时使用硬件钱包、可信赖的第三方和脑钱包这组温和的方式最终可能成为主流。