扣丁学堂区块链入门解析密码学及公钥基础设施
安全通信正快速成为当今互联网的规范。从2018年7月起,GoogleChrome将对全部使用HTTP传输(而不是HTTPS传输)的站点开始显示“不安全”警告。虽然密码学已经逐渐变广为人知,但其本身并没有变得更容易理解。Let'sEncrypt设计并实现了一套令人惊叹的解决方案,可以提供免费安全证书和周期性续签;但如果不了解底层概念和缺陷,你也不过是加入了类似“货物崇拜cargocult”的技术崇拜的程序员大军。
安全通信的特性
密码学最直观明显的目标是保密性confidentiality:消息message传输过程中不会被窥探内容。为了保密性,我们对消息进行加密:对于给定消息,我们结合一个密钥key生成一个无意义的乱码,只有通过相同的密钥逆转加密过程(即解密过程)才能将其转换为可读的消息。假设我们有两个朋友Alice和Bob,以及他们的八卦nosy邻居Eve。Alice加密类似"Eve很讨厌"的消息,将其发送给Bob,期间不用担心Eve会窥探到这条消息的内容。
对于真正的安全通信,保密性是不够的。假如Eve收集了足够多Alice和Bob之间的消息,发现单词“Eve”被加密为"Xyzzy"。除此之外,Eve还知道Alice和Bob正在准备一个派对,Alice会将访客名单发送给Bob。如果Eve拦截了消息并将“Xyzzy”加到访客列表的末尾,那么她已经成功的破坏了这个派对。因此,Alice和Bob需要他们之间的通信可以提供完整性integrity:消息应该不会被篡改。
而且我们还有一个问题有待解决。假如Eve观察到Bob打开了标记为“来自Alice”的信封,信封中包含一条来自Alice的消息“再买一加仑冰淇淋”。Eve看到Bob外出,回家时带着冰淇淋,这样虽然Eve并不知道消息的完整内容,但她对消息有了大致的了解。Bob将上述消息丢弃,但Eve找出了它并在下一周中的每一天都向Bob的邮箱中投递一封标记为“来自Alice”的信封,内容拷贝自之前Bob丢弃的那封信。这样到了派对的时候,冰淇淋严重超量;派对当晚结束后,Bob分发剩余的冰淇淋,Eve带着免费的冰淇淋回到家。消息是加密的,完整性也没问题,但Bob被误导了,没有认出发信人的真实身份。身份认证Authentication这个特性用于保证你正在通信的人的确是其声称的那样。
信息安全还有其它特性,但保密性、完整性和身份验证是你必须了解的三大特性。
加密和加密算法
加密都包含哪些部分呢?首先,需要一条消息,我们称之为明文plaintext。接着,需要对明文做一些格式上的初始化,以便用于后续的加密过程(例如,假如我们使用分组加密算法blockcipher,需要在明文尾部填充使其达到特定长度)。下一步,需要一个保密的比特序列,我们称之为密钥key。然后,基于私钥,使用一种加密算法将明文转换为密文ciphertext。密文看上去像是随机噪声,只有通过相同的加密算法和相同的密钥(在后面提到的非对称加密算法情况下,是另一个数学上相关的密钥)才能恢复为明文。
(LCTT译注:cipher一般被翻译为密码,但其具体表达的意思是加密算法,这里采用加密算法的翻译)
加密算法使用密钥加密明文。考虑到希望能够解密密文,我们用到的加密算法也必须是可逆的reversible。作为简单示例,我们可以使用XOR。该算子可逆,而且逆算子就是本身(P^K=C;C^K=P),故可同时用于加密和解密。该算子的平凡应用可以是一次性密码本one-timepad,不过一般而言并不可行。但可以将XOR与一个基于单个密钥生成任意随机数据流arbitrarystreamofrandomdata的函数结合起来。现代加密算法AES和Chacha20就是这么设计的。
我们把加密和解密使用同一个密钥的加密算法称为对称加密算法symmetriccipher。对称加密算法分为流加密算法streamciphers和分组加密算法两类。流加密算法依次对明文中的每个比特或字节进行加密。例如,我们上面提到的XOR加密算法就是一个流加密算法。流加密算法适用于明文长度未知的情形,例如数据从管道或socket传入。RC4是最为人知的流加密算法,但在多种不同的攻击面前比较脆弱,以至于最新版本(1.3)的TLS(“HTTPS”中的“S”)已经不再支持该加密算法。Efforts正着手创建新的加密算法,候选算法ChaCha20已经被TLS支持。
分组加密算法对固定长度的分组,使用固定长度的密钥加密。在分组加密算法领域,排行第一的是先进加密标准AdvancedEncryptionStandard(AES),使用的分组长度为128比特。分组包含的数据并不多,因而分组加密算法包含一个工作模式,用于描述如何对任意长度的明文执行分组加密。最简单的工作模式是电子密码本ElectronicCodeBook(ECB),将明文按分组大小划分成多个分组(在必要情况下,填充最后一个分组),使用密钥独立的加密各个分组。
这里我们留意到一个问题:如果相同的分组在明文中出现多次(例如互联网流量中的GET/HTTP/1.1词组),由于我们使用相同的密钥加密分组,我们会得到相同的加密结果。我们的安全通信中会出现一种模式规律pattern,容易受到攻击。
因此还有很多高级的工作模式,例如密码分组链接CipherBlockChaining(CBC),其中每个分组的明文在加密前会与前一个分组的密文进行XOR操作,而第一个分组的明文与一个随机数构成的初始化向量进行XOR操作。还有其它一些工作模式,在安全性和执行速度方面各有优缺点。甚至还有Counter(CTR)这种工作模式,可以将分组加密算法转换为流加密算法。
除了对称加密算法,还有非对称加密算法asymmetricciphers,也被称为公钥密码学public-keycryptography。这类加密算法使用两个密钥:一个公钥publickey,一个私钥privatekey。公钥和私钥在数学上有一定关联,但可以区分二者。经过公钥加密的密文只能通过私钥解密,经过私钥加密的密文可以通过公钥解密。公钥可以大范围分发出去,但私钥必须对外不可见。如果你希望和一个给定的人通信,你可以使用对方的公钥加密消息,这样只有他们的私钥可以解密出消息。在非对称加密算法领域,目前RSA最具有影响力。
非对称加密算法最主要的缺陷是,它们是计算密集型computationallyexpensive的。那么使用对称加密算法可以让身份验证更快吗?如果你只与一个人共享密钥,答案是肯定的。但这种方式很快就会失效。假如一群人希望使用对称加密算法进行两两通信,如果对每对成员通信都采用单独的密钥,一个20人的群体将有190对成员通信,即每个成员要维护19个密钥并确认其安全性。如果使用非对称加密算法,每个成员仅需确保自己的私钥安全并维护一个公钥列表即可。
非对称加密算法也有加密数据长度限制。类似于分组加密算法,你需要将长消息进行划分。但实际应用中,非对称加密算法通常用于建立机密confidential、已认证authenticated的通道channel,利用该通道交换对称加密算法的共享密钥。考虑到速度优势,对称加密算法用于后续的通信。TLS就是严格按照这种方式运行的。
基础
安全通信的核心在于随机数。随机数用于生成密钥并为确定性过程deterministicprocesses提供不可预测性。如果我们使用的密钥是可预测的,那我们从一开始就可能受到攻击。计算机被设计成按固定规则操作,因此生成随机数是比较困难的。计算机可以收集鼠标移动或键盘计时keyboardtimings这类随机数据。但收集随机性(也叫信息熵entropy)需要花费不少时间,而且涉及额外处理以确保均匀分布uniformdistribution。甚至可以使用专用硬件,例如熔岩灯lavalamps墙等。一般而言,一旦有了一个真正的随机数值,我们可以将其用作种子seed,使用密码安全的伪随机数生成器cryptographicallysecurepseudorandomnumbergenerator生成随机数。使用相同的种子,同一个随机数生成器生成的随机数序列保持不变,但重要的是随机数序列是无规律的。在Linux内核中,/dev/random和/dev/urandom工作方式如下:从多个来源收集信息熵,进行无偏处理removebiases,生成种子,然后生成随机数,该随机数可用于RSA密钥生成等。
其它密码学组件
我们已经实现了保密性,但还没有考虑完整性和身份验证。对于后两者,我们需要使用一些额外的技术。
首先是密码散列函数crytographichashfunction,该函数接受任意长度的输入并给出固定长度的输出(一般称为摘要digest)。如果我们找到两条消息,其摘要相同,我们称之为碰撞collision,对应的散列函数就不适合用于密码学。这里需要强调一下“找到”:考虑到消息的条数是无限的而摘要的长度是固定的,那么总是会存在碰撞;但如果无需海量的计算资源,我们总是能找到发生碰撞的消息对,那就令人比较担心了。更严重的情况是,对于每一个给定的消息,都能找到与之碰撞的另一条消息。
另外,哈希函数必须是单向的one-way:给定一个摘要,反向计算对应的消息在计算上不可行。相应的,这类条件被称为碰撞阻力collisionresistance、第二原象抗性secondpreimageresistance和原象抗性preimageresistance。如果满足这些条件,摘要可以用作消息的指纹。理论上不存在具有相同指纹的两个人,而且你无法使用指纹反向找到其对应的人。
如果我们同时发送消息及其摘要,接收者可以使用相同的哈希函数独立计算摘要。如果两个摘要相同,可以认为消息没有被篡改。考虑到SHA-1已经变得有些过时,目前最流行的密码散列函数是SHA-256。
散列函数看起来不错,但如果有人可以同时篡改消息及其摘要,那么消息发送仍然是不安全的。我们需要将哈希与加密算法结合起来。在对称加密算法领域,我们有消息认证码messageauthenticationcodes(MAC)技术。MAC有多种形式,但哈希消息认证码hashmessageauthenticationcodes(HMAC)这类是基于哈希的。HMAC使用哈希函数H处理密钥K、消息M,公式为H(K+H(K+M)),其中+代表连接concatenation。公式的独特之处并不在本文讨论范围内,大致来说与保护HMAC自身的完整性有关。发送加密消息的同时也发送MAC。Eve可以任意篡改消息,但一旦Bob独立计算MAC并与接收到的MAC做比较,就会发现消息已经被篡改。
在非对称加密算法领域,我们有数字签名digitalsignatures技术。如果使用RSA,使用公钥加密的内容只能通过私钥解密,反过来也是如此;这种机制可用于创建一种签名。如果只有我持有私钥并用其加密文档,那么只有我的公钥可以用于解密,那么大家潜在的承认文档是我写的:这是一种身份验证。事实上,我们无需加密整个文档。如果生成文档的摘要,只要对这个指纹加密即可。对摘要签名比对整个文档签名要快得多,而且可以解决非对称加密存在的消息长度限制问题。接收者解密出摘要信息,独立计算消息的摘要并进行比对,可以确保消息的完整性。对于不同的非对称加密算法,数字签名的方法也各不相同;但核心都是使用公钥来检验已有签名。
汇总
现在,我们已经有了全部的主体组件,可以用其实现一个我们期待的、具有全部三个特性的体系system。Alice选取一个保密的对称加密密钥并使用Bob的公钥进行加密。接着,她对得到的密文进行哈希并使用其私钥对摘要进行签名。Bob接收到密文和签名,一方面独立计算密文的摘要,另一方面使用Alice的公钥解密签名中的摘要;如果两个摘要相同,他可以确信对称加密密钥没有被篡改且通过了身份验证。Bob使用私钥解密密文得到对称加密密钥,接着使用该密钥及HMAC与Alice进行保密通信,这样每一条消息的完整性都得到保障。但该体系没有办法抵御消息重放攻击(我们在Eve造成的冰淇淋灾难中见过这种攻击)。要解决重放攻击,我们需要使用某种类型的“握手handshake”建立随机、短期的会话标识符sessionidentifier。
密码学的世界博大精深,希望这篇文章能让你对密码学的核心目标及其组件有一个大致的了解。这些概念为你打下坚实的基础,让你可以继续深入学习。