密码学是数学的一门分支,它最早的出现,是为了保证消息在传输过程中保密。随着计算机科学的发展,人类的数学运算能力得到解放,消息的传输效率和容量也越来越高,密码学也被广泛地应用在各种使用计算机的场景。直至今天,我们所说的密码学,实际上就是计算机密码学。
密码学家的工具箱
《图解密码学》一书里介绍了密码学家的工具箱,里面有6种重要的工具,分别是:
对称密码
非对称密码
单向散列函数
消息认证码
数字签名
随机数生成
本文只介绍这些工具的最佳应用实践,不会详细介绍各种算法的实现原理。
对称密码(Symmetric Cryptography)
对称加密指的是:加密或解密消息时使用相同的密码。
分组加密和流加密
对称加密的密码长度不能随着消息长度的增加而增加,因为当密码的长度达到512个比特时,消息的保密性基本已经达到了天花板,再增加密码长度只会延长加密和解密的运算时间。DES和AES都是固定长度的密码,在使用此类算法进行加密时,需要将明文进行分组并迭代处理,每个分组的大小等于密码的长度。
分组密码每次处理的分组数据长度是固定的,每个分组的比特数被称为分组长度。DES和3DES算法的分组长度都是64;AES的分组长度有128、192、256这3种,分组长度等于所使用的密码长度。有时候,消息的长度不满足分组加密的要求,则需要进行数据填充(Cipher Block Padding)。
流密码可以处理任意长度的分组数据,但通常以“1比特”,“1字节(8比特)”等单位大小来处理。
分组加密模式
分组加密有多种模式,其中推荐的模式有GCM和CTR,它们速度很快且具备足够的安全性;CBC模式在特定条件下存在漏洞(Padding Oracle Attack),不推荐使用;而ECB是应当禁止使用的,它不具备实际有效的安全性。
推荐的算法
DES算法和AES算法都是常见的对称加密算法,其中DES算法比较古老,已逐渐被AES算法取代。
AES算法是最常见的对称加密算法,它是一种分组加密算法,支持128、192、256比特的密码长度,密码长度越长安全性越高,加密和解密运算消耗的时间也越长。临时传输加密数据,不持久化加密数据的话,使用128位长度密码即可。加密模式的选择上,AES-GCM是最佳选择。
ChaCha20算法相对而言比较少见,但是它也是使用非常广泛的对称加密算法。它是一种流加密算法,支持128和256比特的密码长度,一般而言使用128比特长度的密码即可。
AES算法和ChaCha20算法的比较
AES算法知名度较高,但是在没有特殊硬件的支持下,ChaCha20的计算性能要优于AES,因为ChaCha20算法的运算操作对于CPU更为友好;如果硬件对于AES算法提供了支持,那么AES的运算效率可能会占上风。无论如何,除非进行过实测,否则算法的处理速度之争不会得到任何有效的结论。更何况,软件是否支持某种算法比其运算效率的重要性高得多。
还有一个非常重要的因素是它们的加密模式的区别:AES是分组加密,ChaCha20是流加密。在一般的使用场景里,这两种加密模式不会有任何区别。在某些特殊场景会产生一些区别,如消息认证码(后面会提到),但这个场景下这两者也有几乎等效的替换方案,如:AES-GCM和ChaCha-Poly1305。
如果说非要选出一种感觉上更好的算法,那么我会选ChaCha20,现代的软件对其已经提供了良好的支持,且它的综合性能不输于AES。再者,对于像我这样的开发人员来说,它具备了足够的“新鲜感”。
非对称密码(Asymmetric Cryptography)
非对称加密指的是:加密和解密消息使用不同的密码。加密时使用的密码叫做公钥,解密时使用的密码叫做私钥。公钥可以公开给所有人,但私钥只能由自己保管,不能泄露给他人。
推荐的算法
使用最广泛的非对称加密算法是RSA,除此之外也可以考虑EC(椭圆曲线)算法。
RSA算法是基于大质数处理原理设计的,它允许使用2048、3072、4096比特的密码长度,长度越长安全性越高,运算消耗时间也越长。临时传输加密数据,不持久化加密数据的话,使用2048比特即可。
早期的RSA算法允许使用1024比特的密码,但由于计算机性能发展,如此短的密码很容易在有限时间内遭到破解,所以已经被弃用。2048比特的密码的安全性至少还能保证到2030年,大可放心使用。
EC算法是基于椭圆曲线的数学理论设计的算法,它可以指定多种椭圆曲线函数,最常用的3个EC函数模式是:NIST P-256、NIST P-384、NIST P-521(不是512!),对应3种密码长度:256、384、521。临时传输加密数据,不持久化加密数据的话,使用256比特即可。
RSA算法和EC算法的比较
RSA算法生成密码较慢,加密和解密的运算速度很快。而且,它的密码长度要求较高(至少2048位)。
EC算法生成密码很快,加密和解密的运算速度较慢,密码较短(NIST P-256模式下256位)。
如果需要存储大量的密码对,使用EC算法比较合适,因为它的密码较短,能大幅减少存储空间;如果需要使用单一密钥对连续进行大量加密和解密运算,那么采用RSA算法更佳,这样做可以有效提升计算处理的效率。
单向散列函数(Cryptographic Hash Algorithm)
单向散列函数又叫“摘要函数”,它能够将任意长度的原始数据处理成较短的固定长度的摘要,并且无法反向操作,即:不能用摘要恢复出原始数据。
摘要算法主要用来:验证数据完整性、验证数据是否被篡改。
推荐的算法
常用的算法有SHA-256算法、SHA-384算法、SHA-512算法。大多数场景下,使用SHA256算法就能满足需求。
SHA-1已经被证实存在碰撞缺陷,即:存在两组完全不同的数据,它们能产生相同的SHA-1摘要,许多公司已经宣布不再提供SHA-1校验码。综上来看,我们应该避免使用SHA-1算法。
MD5是比SHA-1更早,抗碰撞性更弱的一种算法,但是在中文社区里仍然保持较高的知名度。从安全角度来讲,MD5算法应当被禁止使用。
即使是非安全领域,如普通文件和图片存储、临时数据校验,也不应该使用SHA-1和MD5等算法,哪怕你的使用场景里不存在任何数据碰撞的风险。这是因为,使用老旧工具的习惯也是影响数据安全问题的重要原因。
消息认证码(Message Authentication Code)
消息认证码是一种确认数据完整性并进行认证的技术,它的输入是一组任意长度的数据,以及一个在发送者和接收者之间共享的密码,输出则是一串固定长度的数据,称做MAC值。
从特点来看,它既像单向散列函数,也像对称加密。确实这两种密码学基础技术可以组合起来实现消息认证码。
推荐的算法
消息认证码有两种实现的类型:
基于单向散列函数的方式有:HMAC
基于分组加密的有:OMAC、CCM、GCM、PMAC
MAC在日常开发中较少使用,在OpenSSH等工具内部使用得比较频繁。AES-GCM和ChaCha20-Poly1305是比较常用的算法。
数字签名(Digital Signature)
数字签名是一种验证消息发送者身份的手段,它使用了非对称密码来完成计算。具体做法是:消息发送者用自己的私钥来对原始数据进行签名,接收者用发送者的公钥对签名进行验证。
RSA和ECDSA都是值得使用的签名算法,它们的特点在非对称密码一节已经介绍过了。签名技术是非对称加密技术的公私密钥反过来用的一种技术,并没有额外的计算复杂性。
基于摘要的数字签名
有时候,我们会看到诸如RSAwithSHA1、RSAwithSHA256、ECDSAwithSHA256这样的算法,尽管它们也是数字签名的一种,但实际上这类算法是结合了摘要算法和签名算法的一种组合算法,具体的操作是先计算出原始数据的摘要,然后对摘要进行签名。请注意这种方式d 的签名的输入信息是摘要,而不是原始数据。
随机数生成(Random Number Generation)
一般情况下,操作系统提供了一些工具来产生随机数。不过,无论如何计算机都无法产生真正意义上的随机数。
按照随机强度等级来分的话,随机数分3个等级:真随机数、强伪随机数、弱伪随机数。其中,真随机数表示无论生成多少次随机数,都不会得到重复的结果;强伪随机数表示多次生成的随机数可能存在重复,但产生的数不可被预测;弱伪随机数表示产生的随机数可以被预测到。
在密码学领域中,只要产生的随机数不具备可预测性,即可视为是密码学意义上安全的随机数。
密码学领域的基础软件
在一般的软件开发中,我们很少直接接触密码的运算和处理,因为操作系统和各类安全层的软件为我们完成了大部分的工作。
OpenSSL
OpenSSL是一个针对计算机网络通信应用的安全软件,它实现了SSL/TLS协议,并且支持对称加密、非对称加密、消息摘要、数字签名、数字证书、密码生成等多种功能,它最主要的功能是用来进行基于SSL/TLS协议的安全通信。同时,它还提供了各种密码学处理算法库,包括libcrypto和libssl等,是Unix/Linux操作系统上的重要工具之一。
在Linux系统上,应用程序所使用的加密、摘要、签名、消息认证算法几乎都是由OpenSSL提供的,其中包括cURL、Nginx等常用软件。其他的SSL库也能提供类似的功能,例如yaSSL,MySQL 5.7.28版本以前支持OpenSSL和yaSSL两种SSL库,但相比之下,OpenSSL的使用更为广泛。
OpenSSL目前有3个版本:1.0.2、1.1.1和3.0,主流的版本是1.1.1。在Linux系统上,不同版本的发行版支持的OpenSSL最高版本也不同,无论如何,我们都应该及时将OpenSSL更新到最新版本,以获得最新的安全技术支持
如果想要在Windows操作系统上使用OpenSSL,需要手动进行安装。因为Windows提供了一套安全相关的编程接口SSPI(Security Support Provider Interface),提供SSL/TLS协议支持的组件叫做Schannel SSP,所以Windows上的应用软件不使用OpenSSL。另外,Windows的证书管理程序也是由操作系统提供的。
OpenSSH
OpenSSH是一个远程主机连接工具,它实现了SSH协议,以提供安全的访问连接。它采用了数字签名、对称加密、非对称加密、消息认证码等技术,它的底层基于OpenSSL实现。同时,它还提供了ssh、scp、sftp、ssh-keygen、ssh-add等常用的命令行工具。
OpenSSH最新的版本是9.0.0,在不同的Linux发行版上的可用最新版本也不同,请务必升级到最新的版本。Windows同样需要手动安装OpenSSH应用程序,同时Windows默认未启用SSH客户端,需要手动在系统设置中开启SSH公钥格式。
使用ssh-keygen生成密钥对时,OpenSSH使用了OpenSSL的实现,但是公钥的格式与常规的PEM格式和DER格式都不同,它采用了SSH特有的格式,这种格式有利于在服务器间进行公钥交换并记录。