安全领域有两个非常重要的术语:机密性和加密,其中机密性一般描述我们的业务目标,比如用户账户管理系统中,密码必须具备机密性,而加密是实现机密性的一种手段。在安全加密刚刚起步的时候,研究加密算法占据了科研人员大部分的时间,科研人员经常问自己的问题是:如何让通信双方更加安全?这句话翻译成大白话的意思就是,我们通过什么手段能够让通信双方交换的数据(字节码)和信息(明文信息)不被第三者获取。
安全的研究刚开始属于典型的军用领域,随着时代的发展,这些研究成果逐渐公开,被广泛应用于政府和民用领域,我们现在享受的一切和互联网,数字化相关的便利,有很大一部分功劳应该归于安全领域在过去几十年的发展和沉淀。举个不恰大的例子,如果你使用在线的支付平台导致账户被窃取损失了银子,你还会用在线支付系统吗?答案当然是否定的,除非你不在乎钱。说到加密,很多人用不同的理解,其实科研的本质是要解决实际生活终于到的问题。用大白话说加密(cipher)就是:外交部发言人如何应付corrupted news network记者刁钻的恶意问题,特别是哪些长期不生活在中国大陆的记者们,关键事件节点过来刷脸,可能一时半会听不懂,回去要查表才能解密出明文,亦或者查表之后,还是无法理解(理解歪曲,然后写一堆blabla..恶意攻击中国的fact check文章来糊弄naive的外国友人)。外交部发言人讲话的过程中,对数据进行了加密处理。
当然要把这个事情更加形象的说清楚,还是要请出我们的老朋友爱丽斯女王和鲍勃领主,这次他们要传谁会被选为下一届”王国日报“的总编辑。由于科技发展的很快,爱丽斯女王可以通过邮件,电子邮件,电话以及局域网(逻辑性有点问题,大家就当娱乐版看吧,这个时代还没有互联网)来进行信息交互,并且王国内的人民还都比较单纯,属于路不拾遗,夜不闭户类型的,因此这些线路上并没有什么太强的安全手段,大白话说就是这几个通信方式都不安全。
任务事物都具备两面性,科技的发展也不例外,除了带动文明的发展之外,人们也变得复杂了。具体来说,在王国内,逐渐出现快递员会打开”重要的“信件(比如来自于郡主啊,城堡主啊,王室成员啊)来一探究竟,电话系统的接线员对来自特定号码的电话通信会偷听,而哪些局域网的节点提供者也会对流经服务器的数据,特别是进入操作系统的PREROUTING阶段(Linux操作系统,对网络的处理核心netfiler不是很了解的同学,可以关注笔者后续关于虚拟化网络的相关文章),旁路了数据包,用稍微时髦一点的话说,这叫man-in-the-middle攻击。
由于这人变复杂了,爱丽斯女王和鲍勃领主突然觉得这种信息几乎裸奔的形式非常的不安全了,因此迫切需要解决方案。作为云原生和云计算领域的知名架构师,我们需要服务好爱丽斯女王,给出合理(在预算,风险和可行性,可扩展性,性能,可运维性,灵活性之间找到最优解,这么看起来架构师的职位很快也会被深度学习给解决掉,如果你想保住饭碗,深度学习是上游,赶紧在十一认真学习起来吧。)的解决方案。由于读者看了云攀老师持续更新的安全系列文章,遇到这个场景根本不会觉得陌生:这不就是加密的场景吗?,没错,我们通过引入加密算法(encryption algorithm或者cipher)来保证女王和领主之间的数据不会被非法窃取。
咱们先来脑补一下这个场景:女王和领主各自有一个神奇的宝箱,爱丽斯女王把要发给领主的八卦消息通过自己的宝箱进行加密,生成密文(一串看不出所以然的随机字符串),加密的过程具体来说需要两个输入:
1,秘钥,用来对数据进行加密。秘钥必须不可预测,随机,已经被安全的保护,因为整个安全体系的强度和这个秘钥是否能够安全的受到保护息息相关。
2,八卦信息,这个是废话(为了保证内容的连贯和完整)。比如咱上边说的王国日报的总编辑候选人属于信息,视频,图片等也属于信息(开个玩笑,这里的信息其实也有约束,任何可以被转换成二进制的事物都可以称作信息,数据。不要试图对一只猫进行加密!除非你能把一只活体的猫变成bit,但是这又进入人工智能领域了,对于生物来说,生命之源组成躯体可能只是一堆线路和零件而已。)。
爱丽斯女王将上边的两个信息输入到自己宝箱,然后就产出了密文(ciphertext,这个单词很形象,text被cipher后,就变成了ciphertext),大白话说就是经过加密后产生的密文。由于信息被进行了加密,因为爱丽斯女王可以随意选择合适的通信方式(mailman,email,电话和局域网)来将加密后的密文信息发给领主鲍勃。假设女王选择了邮递的方式,任凭有多少邮差打开敞口的信件,始终无法读懂女王写的哪些奇奇怪怪的0和1。
当领主鲍勃收到邮递员送来的信件后,把信件上的密文,用自己的宝箱上的解密算法(decryption algorithm)进行解密,获取爱丽斯女王发送给自己的她听到的下一任主编的人选,哈哈大笑的同时,使劲的拍大腿,并自言自语到,女王和老臣想到一块去了,想到一块去了。领主夫人翻着白眼说,高兴归高兴,能不能拍自己的大腿?具体来说,解密也需要两个输入信息:
1,秘钥,这个秘钥必须和爱丽斯女王用来加密的秘钥一致。阅读过笔者前边关于对称加密文章的同学,应该随口就能出:这不就是对称加密吗?没错,并且女王和领主使用的这相同的key,我们也叫对称秘钥。
2,密文,邮递员送来信件上的那串奇怪的0和1
解密的过程本质上是加密的逆向操作,用来把密文还原成原始的信息,我们通过下图来总结一下整个过程涉及到的四个步骤。
注:虽然笔者在上图中开玩笑式的说女王和领主在一次线下团建确定了秘钥,但是在实际场景中,特别是现在疫情如此反复不定的情况下,线下交换秘钥无论从安全性和效率都不可取,特别是引入定期key轮换来提升安全强度的项目上,很快就会成为问题。在实际项目中,我们需要使用安全的机制来生产,交换,更新,传输秘钥信息,有时候也叫秘钥管理。阿里云提供了KMS服务,专门针对这种场景,感兴趣的和不感兴趣的都可以了解一下。
看到这里,大家可能会有点疑惑,标题不是说的是认证加密,为啥只看到加密,没有看到认证呢?标题党啊!大家稍安勿躁,从安全的最佳实践和规范的角度来看,光靠加密是无法保证安全性,或者机密性的,因此我们需要先介绍加密,然后在介绍认证加密,逻辑上也合理。
读完上上边看似小说的内容后,在要进入稍微硬核的内容了(安全领域和数学紧密相关,笔者只能尽自己最大的能力将内容写的亲和)。首先我们从加密算法开始,从业界标准AES(Advanced Encrytion Standard)这个算法开始。
美国国家标准与技术研究院(NIST)在1997年举办了一个有关AES(高级加密标准,中文翻译听起来很没有代入感,后边笔者会直接用AES)的安全竞赛,来继承已经日落西山的DES算法的衣钵。这个安全竞赛持续了三年时间,从15个不同的参赛团队提交的算法中,组委会确定了Rijndael算法,由Vincent Rijmen和Joan Daemen设计并提交。2001年,NIST公布了AES的最终标准,即便是在20年后的今天,AES仍然是主要的加密算法,活跃在我们日常生活的周围。
坦白说,AES的内部工作机制不是笔者能驾驭的,能讲清楚的,但是由于任何事物都可以有不同的抽象层次,对于技术来说也是如此,笔者坚信Don Box那句its all about perspective的名言,因此我们来稍微探索一下AES的内容工作原理,为理解认证加密打下基础。
AES算法也提供了多个版本,其中包括:AES-128(秘钥的长度是126bit,也就是16bytes),AES-192(秘钥长度24bytes),以及AES-256(秘钥长度32bytes)。不同秘钥长度不出所料的意味着不同的加密安全强度,简单粗暴的说法就是:秘钥越长,越安全。结合笔者在前边文章介绍的内容,一般我们需要最少保证128bit的安全,因此AES-128是最为常用的版本。
日常的项目中我们经常会听到bit安全(bit security),这个术语通常用来描述加密算法的安全强度。举个例子,AES-128可以提供128bit的安全强度,也就是恶意攻击者需要尝试2^128次方次,才有机会将密文还原成明文。
注:在安全领域,bit security中的数字,比如128bit,说的是上限,因为存在birthday bound,彩虹表,攻击统计分析等手段,因此恶意攻击者一般可能不需要进行2^128次方就能得手,这是最坏情况。那么聪明的你肯定会问,有没有上限?这就取决于安全体系了,比如说流程安全。笔者最近遇到的一个真实的场景是,将数据库连接信息通过AES-128算法加密放到配置文件中,项目组觉得很安全,提供了几乎不可能被窃取的安全保障。但是你有没有想过,解密这个数据库字符串的秘钥放哪里呢?对不起项目组直接写代码里了。安不安全大家考虑一下,这就类似于门上挂着20w售价的5斤大锁,而钥匙就挂载把手上。
2的128次方具体有多大,找个计算机算一下(还需要好一点的,一般计算器很快就约等于了),结果是340282366920938463463374607431768211456,这个数字具体怎么念,笔者也不是很清楚。但是由于笔者是计算机专业人士,我知道的是2的128次方是2的127次方的两倍,按照这逻辑,我们看看稍微小点的2的100次方,大概是1268万亿亿次,这个数字具体如何类比,但是网上有个初中的奥数题,一起来感受一下这个神奇的数字。
题目为假设有一张可以充分折叠,厚度为0.1毫米的纸(读者可以想象为办公室随处可见的A4纸),在不计除了纸张之外任何厚度的情况下(比如对着后,我们假设对这面可以充分的贴合,没有空隙),那么将其对折N次后,对折后的厚度为h=2^N*0.1mm。咱就这么对折,有几个数据非常的有意思:1,对折10次之后,就是1分米,小学生用的尺子的长度;2,对折25次后,大概是3355米,已经把五岳压脚下了;3,对折35次后,厚度大约是3436,已经快离开大气层了;4,对折50次,厚度达到了1.1亿千米,来回火星一次;5,激动人心的时刻到了,对折100次以后,就是12676500000000000000000千米,换个单位就是134亿光年,宇宙大爆炸到现在的全部时间也就是137亿年,使得光从这张折叠纸的顶端到到我们的眼睛中。
上边的这些讨论主要想给大家一个直观的关于128bit加密强度的类比,可以看到这个数字非常大,但是笔者还是要强调,安全是个体系的概念,光靠加密128bit,就算是512bit,秘钥随便写在安全人员的笔记本上,胡乱扔在桌子上的话,和采用8bit没有啥太大的区别(8bit只需要最多32次尝试,就可能破解密文)。
从抽象的角度看,AES-128算法可以有如下描述:
1,AES算法接收一个变长的秘钥
2,输入的待加密文本为128bit
3,加密后输出的密文也为128bit长
从上边的描述可以看出,AES算法加密的明文信息为定长,我们也称这种加密算法为block cipher。在加密算法领域,的确存在接受变长输入数据的算法,笔者会在后续的文章中详细介绍。
在解密阶段,AES通过相同的秘钥,把密文(128bit)的信息还原成明文。AES能够实现加密和解密,特别是解密的特性的一个很重要的原理是:AES具备数学上的确定性特征(deterministic),通过对信息进行加密后,一定能够解密出来原文。因为光看加密,连我们自己都可以设计一套机密性很高的加密算法,但是要保证机密性的同时还需要保证可解密,这就需要高深的数学知识了。
从数学的角度来看,AES这样的block cipher加密算法(使用秘钥),也称作数组变换,或者排列组合计算。数组变化具体来说,就是将所有的输入数据”变换“成密文(ciphertext),而key(秘钥)的核心作用是定会有了mapping(变换)的规则。这就意味着当我们更换了秘钥,整个变化规则发生了变化,因此加密的后的密文也会发生变化。从密文的角度,通过这个key(定义了mapping关系),来将密文映射回原始的明文数据。如下图所示的AES加密过程示意图:
如上图所示,AES-128加密过程本质上就是数组变换,从左边的输入(数组集合)变换到右边的数组集合。当然我们不会把所有的从左边到右边的变换都列出来,因为有2的128次方种可能。因此设计了AES算发,本质上AES的工作原理就是上边的组合变换,通过一个随机的key来定义变换的mapping关系。AES提供的这种特性也叫伪随机置换(pseudorandom permutations)。
到现在为止我们描述还是宏观层面的AES工作原理,接下来我们深入一层,从AES的内部视角,看看加密和解密的过程是如何具体执行的。首先,AES在计算之前,会将128bit的输入,也就是16字节的数据变成4乘4的字节矩阵,如下图所示:
如上图所示,数据会被转换成这样的一个4*4的矩阵。接着AES算法计算密文会迭代多次,最终计算出最后的密文,如下图所示:
上图没有画出秘钥,主要是为了清晰起见,读者需要注意这个细节的缺失。每个round function使用的round key是不同的,那么这个key从哪里来呢?AES算法中,会通过一种叫key scheduler的机制来从秘钥派生出round key。这种机制下,我们传统上称AES为对称加密就不太准确了,因为实际上加密的秘钥是一种随机生成的round key。
让我们把目光聚焦到这个神奇的灰色box上,你肯定很想知道这个box内部的工作原理,我们接下来就来说说。round function的核心职责就是将输入的bytes进行状态变换(mix,transform),并且AES中,round function主要有四个子功能:SubBytes,ShiftRows,MixColunmns,以及AddRoundKey。对于这几个方法的详细介绍我们就不展开了,主要是也说的不专业,不过任何一本关于AES的书籍中,都会有这四个方法的详细介绍。
从解密的角度看,这四个方法的前三个很容易进行逆向操作,而最后一个需要一个round key才能逆向操作,如下图所示:
如上图所示,AES提供的四个子函数会被用在整个加密的流程中,并且每个方法都可可逆,要不然解密无从谈起啊。大家注意最后一步的符号,这里需要进行异或操作。
Round函数具备应该被执行多少次取决于我们对安全强度的诉求,来防止信息泄露。举个例子,如果我们的round函数调用的次数为3的话,那么AES-128版本很容易就会遭受total breaks攻击(通过大量的计算来破解秘钥)。通过多次的迭代调用round function,输入的明文会被转换成和完全不想关的密文。并且如果明文哪怕是发生一个bit的变化,密文的输出也会完全不一样,来防止统计攻击等风险。
注:在真实的项目上,我们选择合适的加密算法一般从安全强度,加密长度,性能等的角度来评估,安全强度和长度强先关,我们就不细说了。而性能和硬件有关,比如主流的CPU厂商Intel和AMD提供了AES-NI指令,来在硬件级别提供对AES加解密的支持。
关于AES的工作原理,其实还有一个现实的问题没有讨论:如果输入数据的长度不足128bit,该如何处理?这是一个很现实问题的原因是大部分待加密的数据都不可能正好是128bit的整数倍,因此我们需要某种机制来解决当长度不够的时候,如何处理。你肯定会脱口而出:padding,这个笔者在哈希算法的时候详细的解释过。
不过AES提供了两种模式,一种是padding,另外一种叫AES操作模式(mode of operation)的机制。我们来举个实际的例子,假设我们有一些信息需要加密,我们可以按16bytes长度对原始的数据进行切分,但是最后剩下的部分不够16bytes,我们可以给最后一部分补充一些数据,来让它正好16bytes长。
虽然说这个原理很好理解,很快你就会发现,选择什么数据会很重要,因为我们在解密的时候,还需要可逆。有些同学可能直接会想到,补0不就行了。其实补0是有问题的,因为在经过AES的加密处理后,首先这些补充的0可能不是0了,另外我们也不知道具体的边界在哪里,无法解密。
针对这个问题,RSA公司在1990年就提出了一种称作是PKCS#7的padding机制。PKCS#7机制的原理很简单:用具体需要padding长度来填充不足16bytes部分。如果字符串刚好能够基于16bytes等分,那么就在的字符串后边增加一个额外的16bytes数据块,这样在解密的时候,只需要对最后一个字节,然后把这个字节对应长度的数据抹掉就是原来的数据长度。
不得不说这个算法太精妙了,大家可以体会一下,特别是我们需要通过分隔符的场景,可以考虑这种方案,特别是分隔符可能出现在原始数据中的场景。如下图所示:
如上图所示,我们通过PKCS#7机制提供的padding功能,解决了长度不够16bytes的问题。不过在高兴之前,我们来聊聊AES这种加密机制的一个缺陷。AES-128算法这种将输入数据切分为16bytes长度来进行加密计算的方式也称作:ECB(electronic codebook)操作模式。由于AES算法的加密必须满足数学的确定性,因此我们如果对相同的输入数据加密两次来此,得到的结果完全一致。这在安全上是好事,反过来看也是坏事:加密后的密文呈现出固定的可重复模式。
从加密原理的角度,这看起来不算太大的问题,但是加密结果有固定的模式是一个安全风险。因为固定模式或多或少会泄漏原始数据的某些特征。关于这个问题业界最著名的案例就是ECB penguin,如下图所示:
从上图中我们看到了啥?对原始的企鹅图片进行加密后,我们还是很容易认识到,这就是一个企鹅图片,这显然是有问题的。为了解决这个问题,AES提供了一种叫CBC(cipher block chaining)的模式,在原始的block cipher之上,增加了一个叫IV(initialization vector)初始化变量的参数,来提供更强的随机性,消除模式。
大家应该不难想到,IV的长度在AES-128版本上也是16bytes长,并且很明显这也是秘钥,因此也必须提供足够的随机性和不可预测性。具体的变化叫就是128bit(16bytes)的数据在进行加密之前,会先和IV进行异或操作,而这个IV必须在加密之前随机产生。这种方式有效的解决了相同的输入数据模式的问题,因为每一块数据在和IV进行异或操作之后,会完全不一样,消除了模式。
第一块数据处理完之后,如果有超过126bit的后续数据需要加密,那么前一个128bit产生的密文,会和第二块128bit的数据先进行异或操作,然后再进行round founction加密操作,这样初始输入的IV就可以继续为第二个数据块的加密注入随机性,以此类推。笔者需要再次强调的是,IV必须和秘钥一样,随机,不可预测。下图是CBC加密模式的流程:
加密的过程理解清楚后,我们来看看具体解密的过程。由于在加密的时候使用了这个IV(可以看成另外一个秘钥),那么解密的时候,也需要这个IV,具体的解密过程从原理上就是加密的逆向操作,由于IV的随机性,因此信息传递的过程中会具备很强的安全性,如下图所示:
在加密的过程中引入某个随机变量来提升强度是一张非常通用的做法。原理很简单,但是在实际的项目中,IV的选择是造成安全隐患的主要原因。IV必须足够的安全,主要体现在唯一性,随机性和不可预知性上。因此很多加密实现框架上,直接在后台把IV给去掉了,框架自己生成,而不是让用户输入(这又再次证明,人才是整个系统最不安全的因素)。
注:当IV的选择出现安全风险,比如说IV容易被预测(用电话号码,名字的品应,邮箱地址等),那么黑客就可以利用著名的BEAST攻击,通过浏览器的漏洞来攻击TLS协议。
好了,关于认证加密的第一部分就这么多了,虽然说我们尚未涉足认证加密,但是希望大家通过这篇文章能对AES, AES CBC模式有更加全面的理解,为理解(下)的内容打好基础。在结束本章的内容之前,不知道大家是否发现一个问题,即便是通过AES-CBC这种模式,仍然存在安全风险?具体是什么,我们下篇文章来解答,敬请期待!