1、密码学家工具箱:对称密码、公钥密码、单向散列函数、消息认证码、数字签名(证书)、伪随机数,这六类密码技术统称为密码学家工具箱。
2、编码、位运算与加解密
编码:将现实中的东西映射为比特序列的操作称为编码,编码通常是针对文字及图形符号。例如,同样一个字母,用不同的编码方式那么在内存中写入的比特序列也就是不一样的。字母m用ascii编码就是8位的01101101,而用utf-8却是另一串数字。对于人来说可读文字编码为比特序列就像是加密,但对于计算机来说,这就是一串可直视的文字。
位运算:计算机在进行加密解密的过程中,操作的对象都是比特序列,而不会去区分操作对象是文本还是图片以及程序等。(其中使用的最广泛的比特列运算就是XOR异或运算,它的特性类似于黑白棋子的翻转:a⊕b⊕b=a⊕(b⊕b)=a⊕0=a)
加解密:加密就像炒鸡蛋,通过一些方法打乱明文(文本、图片、程序等)的比特序列使其变成看起来一团脏的密文。但是加密不同于炒鸡蛋的一点就是,炒好的鸡蛋无法再还原回原来的鸡蛋状态,而打乱的密文却可以恢复成原本的明文。
3、分组密码与流密码
分组密码:每次只能处理特定长度的一块数据的一类密码算法。其中“一块”就称为分组,分组的比特数就是分组长度,不同算法所使用的分组长度均有所不同,不管分组长度多少,输入明文分组长度总是等于输出密文分组长度。例如,DES、三重DES、AES等大多数对称密码算法都属于分组密码。
流密码:对数据流进行连续处理的一类密码算法。流密码中以1比特、8比特或32比特等为单位进行加密和解密。例如,一次性密码本就属于流密码。
两者对比:分组密码处理完一个分组就结束了,因此不需要通过内部状态来记录加密的进行;而流密码是对一串数据流进行连续处理,因此需要保持内部状态。个人以为,这个内部是否保留完全取决于程序编写者是否有这个需要,非必需。
4、分组密码的5种模式
分组密码算法都只能加密特定长度的明文数据,如果要加密任意长度的明文,就需要对分组密码算法进行迭代,而分组密码的迭代方法就称为分组密码的模式。分组模式有很多种类,但主要模式为以下5种:
(1)ECB模式:ElectronicCodeBookmode(电子密码本模式)
原理:该模式下,将明文分组加密之后的结果将直接成为密文分组。
特征:
(2)CBC模式:CipherBlockChainingmode(密码分组链接模式)
原理:该模式下,首先将明文分组与前一个密文分组进行XOR运算,然后在对结果进行加密。由于密文分组前后之间存在着联系,故称为密文分组链接模式。
(3)CFB模式:CipherFeedBackmode(密文反馈模式)
原理:该模式下,前一个密文分组会被送回到密码算法的输入端。所谓反馈,这里就是指返回输入端的意思。
(4)OFB模式:OutputFeedBackmode(输出反馈模式)
原理:该模式下,通过将明文分组和“密码算法的输出(密码算法对初始化向量循环加密的输出)”进行XOR来产生密文分组的。
(5)CTR模式:CounTeRmode(计数器模式)
原理:该模式下,每个分组对应一个逐次累加的计数器,通过对计数器进行加密来生成密钥流,然后与明文进行XOR运算。
(*)各模式之间的对比。
5、对称密码:用相同的密钥进行加密和解密
(1)一次性密码本--号称绝对不会被破译的密码。
概述:只要通过暴力破解法遍历整个密钥空间,无论任何密文也总有一天都能够被破译。但是一次性密码本却除外,因为在对一次性密码本的密文尝试暴力破解的过程中会产生多种多样看起来“正确”的明文,以至于我们无法去判断到底哪一个“正确”的明文才是我们所需要的,因此一次性密码本是无法破译的。
原理:将明文与一串和明文等长的随机比特序列进行XOR运算,产生的结果即是密文。
(2)Feistel网络
概述:Feistel网络是DES的基本结构,该结构由Feistel所设计,因此也称为Feistel网络。该结构不仅被用于DES,在其它很多密码算法中也有应用。
原理:在Feistel网络中,加密的各个步骤称为轮,整个加密过程就是进行若干次轮的循环。下图为1轮的加解密流程。
在Feistel网络中,每一轮都需要使用一个不同的“子密钥”,子密钥只在一轮中被使用,它只是一个局部密钥,因此才称为子密钥。
综上所述,无论是任何轮数、任何轮函数、Feistel网络都可以用相同的结构实现加解密,且加密的结果一定能被正确解密。
(3)DES(DataEncryptionStandard)
(4)三重DES。
概述:基于DES可被破解,于是为了增加DES的强度,将DES重复3次所得到的一种密码算法就是三重DES。同理三重DES的密钥长度就是64*3=192比特(实际是56*3=168),而它的分组长度还是64比特。
原理:三重DES并不是进行三次DES加密(加密->加密->加密),而是加密->解密->加密的过程,目的是为了兼容普通DES。
(5)AES(AdvancedEncryptionStandard)--Rijndael算法
概述:AES只是一个头衔,只是它在众多候选算法中选择了Rijndael算法作为它的代表。Rijndael算法的分组长度为128比特,密钥长度可以是以32比特为单位在128-256比特范围内进行选择。(不过在AES的规格中,密钥长度只有128、192、256比特三种。)
原理:Rijndael算法也是由众多轮所构成,只不过它的基本结构不是Feistel结构,而是SPN结构。该算法需要进行10-14轮的计算。
Rijndael的输入分组为128比特,也就是16字节。首先需要逐个字节地对16字节的输入数据进行SubBytes处理(所谓SubBytes,就是在对应表的256组对应关系中,根据索引替换对应值的过程),在SubBytes之后需要进行ShiftRows处理(即将SubBytes的输出以字节为单位进行打乱处理,这种打乱是有规律的),ShiftRows之后需要进行MixColumns处理(即对一个4字节的值进行比特运算,将其变为另外一个4字节值),最后进行AddRoundKey处理(即将MixColumns的输出与轮密钥进行XOR)。至此Rijndael的一轮就结束了。
6、公钥密码:公钥加密,私钥解密
(1)密钥配送问题:在对称密码中,由于加密和解密的密钥相同,因此发送者除了要将密文发送给接收者外,也必须给接收者配送密钥。而密钥必须要发送,但又不能发送,这就是对称密码的密钥配送问题。
(2)密钥配送解决方案
(3)公钥密码无法解决的问题
(4)RSA
(4.1)RSA加解密使用的完全就是数学中质数和模运算(时钟运算)之间进行的计算过程,因此要想彻底了解RSA需要明了质数和模运算之间的规律。
(4.2)RSA的加解密。
在RSA中,明文、密文、密钥都是数字,加解密过程就是数学公式的计算。(其中E和N两个数的组合就是公钥,E代表Encryption加密,D代表Decryption解密,N代表Number数字)
(4.3)RSA密钥对的生成
生成步骤分为4个阶段,求N、求L、求E、求D,其中NED是RSA密钥对的组成部分,而L只是在生成过程中需要被使用到,相当于一个临时数。
实例:
(4.4)公私钥生成时,会需要中间数据p、q(质数),根据pq产生NL,通过L生成E(E的值存在若干,但只选一个),之后根据EL产生D,此时EN组成公钥,DN组成私钥。
由上可知:公私钥的产生是先有公钥再有私钥,而公钥EN人人可以获得,那么通过EN是否就可以计算出DN?由于无法知晓L,故不能成功。即便知道N,也不太可能反推出pq(除非N的值很小,那样就可能反推出pq,进而根据公钥得到私钥),也就无法得到L,故无法仅通过EN知道DN,或通过DN计算出EN。
但是实际的公私钥生产中,我们发现是先生成私钥,然后通过私钥来产生公钥,这是什么原因?
猜测:私钥文件中存储的应该不只是DN,它很可能还保留了(pq)LE这些重要信息。
(4.5)其它公钥密码
(4.6)密钥的长度通常都是1024比特即128字节,而编程语言中为整数分配的字节通常都是4字节,可知密钥所代表的这两个数字会有多么大,而对这样大的数进行质因数分解,困难程度可想而知(故一般认为不可能解密)。
7、混合密码系统:将对称密码(处理速度快)和公钥密码(解决密钥配送问题)的优势相结合的密码系统。
8、单向散列函数--获取消息的指纹
(1)完整性,又叫一致性。例如,昨天创建的文件,而今天看到的是否还是昨天的那个文件,文件的内容是否发生了改变,哪怕是一个标点符号或者是一个比特的不同。如果有改变,那么这个文件就不是真的,这种“是真的”的性质就叫做完整性。
(2)完整性比对。文件的内容最终表现在磁盘存储中都是以比特序列的方式存在的,所以即便文件中只是变动了一个标点符号,那么符号所对应的编码序列都会不一样,存储在磁盘中的比特序列也就会改变。因此我们只需要比对昨天文件的比特序列与今天的比特序列是否一致。早先如果没有单向散列函数计算指纹,而仅靠人眼去对比这种差异会非常的困难。(如果内容确实没有改变,但是编码方式进行了改变,那么比特序列也会不一样。)
(3)单向散列函数所处理的对象是比特序列,因此它不需要理会消息的类型是文本还是二进制,统一都当做比特序列来处理。而且散列值的长度都是固定的长度和输入消息的长度、大小无关。
(4)单向散列函数(又叫消息摘要函数messagedigestfunction、哈希函数、杂凑函数)的性质:根据任意长度的消息计算出固定长度的散列值、能够快速计算出散列值、消息不同散列值不同、具备单向性(玻璃可以被砸碎,但是无法将碎片玻璃还原回完整玻璃)。
(5)抗碰撞性。
弱抗碰撞性:当给定某条消息的散列值时,单向散列函数必须确保要找到和该消息具有相同散列值的另外一条消息是非常困难的。(例如,10个随机数,找出值为5的另外一个数)
强抗碰撞性:指要找到散列值相同的两条不同消息是非常困难的。(例如,10个随机数,找出值相同的一对数)
备注:(1)所有单向散列函数可以不具备强抗碰撞性,但必须具备弱抗碰撞性。(2)从上面2个例子来看,10个数中找出值相同的一对数会较为容易一些,从容易度来看:弱抗碰撞性<强抗碰撞性,但是如果强抗碰撞性更困难,那么对应的弱抗碰撞性岂不是更难。
(6)单向散列函数的应用:检测软件是否被篡改、基于口令的加密、消息认证码、数字签名、伪随机数生成器、一次性口令。
(7)单向散列函数的实现:MD4(散列值128比特)、MD5(散列值128比特)、SHA-1(散列值160比特)、SHA-256(散列值256比特)、SHA-384(散列值384比特)、SHA-512(散列值512比特)、RIPEMD-160(散列值160比特)。其中SHA-256、SHA-384、SHA-512合起来统称为SHA-2,SHA系列的算法的输入消息长度均存在上限。
(8)单向散列函数SHA-1处理消息计算散列值的整体流程:
(9)单向散列函数可以实现完整性的检查即辨别是否“篡改”,但是无法辨别“伪装”。
9、消息认证码--消息是否被正确传输
要计算MAC必须持有共享密钥,没有共享密钥就无法计算出MAC,消息认证码正是利用这一特性来完成认证。
此外和单向散列函数的散列值一样,即便消息中发生1比特的变化,MAC的值也会发生变化,消息认证码正是利用这一特性来确认完整性的。
(2)消息认证码的应用:SWIFT、IPsec、SSL/TLS。
(3)消息认证码的实现方式:(1)使用MD5、SHA-1等单向散列函数(2)使用DES、AES之类的分组密码实现。利用CBC模式将消息分组全部加密,然后只取最后一个分组作为的值。
(4)HMAC--一种使用单向散列函数实现的消息认证码,所使用的单向散列函数不局限于一种。如,SHA-1、MD5、RIPEMD-160,所构造的MAC分别称为HMAC-SHA-1、HMAC-MD5、HMAC-RIPEMD。
(5)重放攻击:事先保存正确的消息和对应的MAC值,然后不断重放来发动攻击,使得消息的内容被执行多次。
(6)散列值可以确保消息是否被篡改,但如果攻击者将消息修改并生成新的散列值来替代原来的散列值,此时便无法验证消息是否被更改。而消息验证码的主要作用就是防止消息和散列值被一同篡改。
10、数字签名--可确认消息由谁所写
(1)消息认证码的局限性:无法防止否认。是因为消息认证码需要在双方之间共享同一个密码,而且双方都可以都可以根据消息生成同样的MAC值。这样一来即便是A产生的消息,它也可以否认自己说是B产生的,旁人也无法找到证据来表明A的话是否正确。
而通过使用数字签名,那么A便无法进行否认了,因为这样用私钥对消息进行签名而产生的值,其它人是无法生成的。而且还有一个好处就是,签名的信息可以由第三方拿公钥来验证。
(2)在数字签名中,对签名密钥和验证密钥进行了区分,验证密钥(公钥)是无法生成签名的;同样,在公钥密码中,也对加密密钥和解密密钥进行了区分,用加密密钥(公钥)无法进行解密。
其实,单从公私钥来说,不管是公钥还是私钥,如果一方被用来加密,那么另一方就是解密。但是在公钥密码和数字签名中却是分别对公私钥的使用进行了区分,主要是为了防止混乱,或者是防止被攻击。
(3)数字签名的两种方式
(4)在直接对消息签名的方式中,对消息的签名也相当于是消息的密文,那么密文为什么能作为签名使用?
虽然实际处理的内容是通过用私钥进行加密的,但这里的加密并非是为了保证机密性而进行的。
数字签名是利用了“没有私钥的人事实上无法生成使用该私钥所生成的密文”这一性质来实现的。这里所生成的密文并非用于保证机密性,而是被用于代表一种只有持有该密钥的人才能够生成的信息。
这样的信息一般称为认证符号(相当于对暗号一般),消息认证码也是认证符号的一种,(只不过它只能证明对方不能供第三方去验证,适用范围有限。)数字签名也是一样。
(5)这种签名只不过是计算机上的一种数据,那么这种签名可以随意复制吗?
签名可以被随意复制,但不代表签名就没有意义,因为签名所表达的意义是特定的签名者对特定的消息进行了签名,即便签名被复制,也并不会改变签名者和消息的内容。即便消息的内容被更改而签名不变,但最终还是难免验证签名时会发生失败。
(6)数字签名的应用:安全信息公告、软件下载、公钥证书、SSL/TLS。
(7)数字签名的实现:就是前面使用公私钥对消息进行加密的过程,基本上公私钥的算法都可以实现签名。例如,RSA(可用于公钥密码和签名)、EIGamal(可用于公钥密码和签名)、DSA(只被用于签名)、Rabin(可用于公钥密码和签名)。
(8)攻击:中间人攻击、对单向散列函数的攻击、利用数字签名攻击公钥密码
(9)数字签名无法解决的问题。
用数字签名既可以识别出篡改和伪装,还可以防止否认。然而要想正确使用数字签名,有一个大前提就是:用于验证签名的公钥必须属于真正的发送者,即无法确保公钥是否是伪造的。如果这一前提无法保障,那么后面的处理都将毫无意义,于是便有了证书。
11、证书--为公钥加上数字签名(为公钥做保证)
(1)证书的目的:用一个权威的私钥通过对另一个第三方的公钥进行签名来提升第三方公钥的可信度。
(3)认证机构就是能够认定“公钥确属此人”并生成签名的个人或组织。认证机构中有国际性组织、政府设立的组织、通过提供认证服务来盈利的一般企业、还有可以是个人成立的认证机构。
(4)证书使用的整体流程。
(5)认证机构所遵守的身份确认和认证业务准则。
(6)证书的规范
证书是由认证机构颁发的,使用者需要对证书进行认证,因此如果证书的格式千奇百怪那就不方便了。于是人们制定了多种标准规范,其中以X.509的标准规范被广泛使用。
(7)公钥基础设施(PKI-PublicKeyInfrastructure)
仅制定证书规范还不足以支持公钥进行有效的应用,我们还需要很多其它的规范,例如:证书由谁颁发、如何颁发、私钥泄漏时应该如何作废证书、计算机之间的数据交换应采用怎样的格式等,而针对以上各项问题所制定的一系列规范的总称就叫做公钥基础设施(PKI)。
(7.2)认证机构具体进行的操作
(7.3)证书的层级结构
当用户在认证机构申请到证书之后,它需要对此证书的数字签名进行验证。认证前它需要先对认证机构的公钥证书进行验证,而认证机构的公钥证书可能又是另外一个认证机构颁发的,如此一来我们在验证低层的认证机构证书前需要先认证高一层的认证机构的证书。这样的关系可能会迭代好几层,这种层次就是证书的层级结构。
但是不管层级结构迭代多少层,总不会无线延伸,总会存在一个终点,这个终点就是根CA,它公钥证书的颁发是使用自己的私钥进行签名颁发的,这种行为称为自签名。
从证书验证的最终效果来看,统一都是由低层迭代到根,然后从根开始验证直至末端。(每一个证书都是记录颁发者的信息或颁发者证书的位置,这也就是证书验证软件可以不断迭代的根本所在。)
12、伪随机数--不可预测性的源泉
(1)随机数的用处:生成密钥、生成公私钥、生成初始化向量、生成nonce、生成盐。
(2)随机数的性质
(3)通过硬件设备生成的随机数列,这样的设备叫做随机数生成器。而通过软件生成的随机数列,这样的软件称为伪随机数生成器。
伪随机数生成器具有初始“内部状态(一个值)”,外部输入的“种子”会初始化该内部状态,当外部有随机数请求时,随机算法会根据内部状态来生成随机数输出。随后,为了响应下一个请求,伪随机数生成器会改变自己的内部状态。(种子的信息很重要,如果种子值泄漏,那么攻击者就可以依次种子来生成同样的随机序列,进而可能会猜测处随机密钥。)
(4)伪随机数生成器的几种实现
(5)随机数池:通常随机数的生成并非是在需要的时候才当场生成随机数,而是会事先在一个随机池的文件中积累随机比特序列。当需要时直接从中取出即可。例如,Linux系统中的/dev/random文件就是一个可以根据硬件设备驱动收集的背景噪声储存真随机数的随机数池。(其实计算机本身就可以是一个硬件设备真随机数生成器,无需外设。)
13、密钥--秘密的精华
(1)密钥通常都是一个很巨大的数字,但是数字本身的大小并不重要,重要的是密钥空间的大小,也就是可能出现的密钥的总数量。因为密钥空间越大,进行暴力破解就越困难,而密钥空间的大小是由密钥长度决定的。
(2)会话密钥和主密钥
使用应用层协议HTTPS而建立起来的SSl/TLS加密通道,在这样的通道中所使用的共享密钥是仅限于本次通信的一次性密钥,下次通信时就不能再使用了。这种密钥就叫做会话密钥。相对于会话密钥,那些一直被重复使用的密钥被称为主密钥。
一次性的会话密钥的好处就是,即便攻击者获取了本次通信的密钥,它也只能破译本次通信的内容。由于下次通信中会使用新的密钥,因此其它通信的机密性不会受到破坏。
(3)加密内容的密钥称为CEK(ContentsEncryptingKey),加密密钥的密钥称为KEK(KeyEncryptingKey)。
(4)密钥管理
(4.1)生成密钥:随机数生成密钥、口令生成密钥(PBE基于口令的密码)
(4.2)配送密钥:事先共享密钥、密钥分配中心、公钥密码、DH密钥交换
(4.3)更新密钥:使用共享密钥的过程中,定期(例如每发送1000个字)改变密钥。当然,双方必须同时用同样的方法来改变密钥才行。
更新密钥时,发送者和接收者使用单向散列函数计算当前密钥的散列值,并将这个散列值用作新的密钥。即用当前密钥的散列值作为下一个密钥。
这种防止破译过去的通信内容的机制,称为向后安全。
(4.4)保存密钥:通过加密密钥的密钥KEK,虽然没有解决密钥机密性的问题,但是它大大的减少了需要保管密钥的数量,由原来的多个密钥的保管,变成了一个密钥的保管。
(4.5)作废密钥:不再使用的密钥必须妥善删除,否则如果被窃取了,那么之前的通信内容就都会被解密。如果密钥是一个文件,那么这个文件的删除必须特殊处理,否则文件被修复了就不好了。
(5)Diffie-Hellman密钥交换(配送密钥)
使用这种算法,通信双方仅通过交换一些可以公开的信息就能够生成出共享的秘密数字,而这一秘密数字就可以被用于共享密钥。此法=虽然叫做密钥交换,但实际上双方并未真正交换密钥,而是通过计算生成了相同的密钥,因此这种方法又叫做DH密钥协商。(通信过程即便被监听,也不会泄漏共享密码)
举例如下
(6)基于口令的密码PBE
虽然人们可以使用便于记忆的口令来作为密钥,但实际上很少会直接用口令来作为密钥使用。一般都是将口令用单向散列函数处理,用得到的散列值作为密钥使用。又为了防止字典攻击,需要在口令上面附加一串称为盐的随机数,然后将其输入单向散列函数。这种方法就叫做“基于口令的密码”(PasswordBasedEncryption)
PBE是KEK的一种,算是解决了(4.4)保存密钥中那最后一个加密密钥的保存问题。因为用口令和盐生成的加密密钥,密钥可以直接丢弃,而口令记忆在大脑里就行。
(7)盐的作用:抵御字典攻击。
假设在生成KEK的时候没有加盐,那么攻击者就可以根据字典数据事先生成大量的候选KEK,以供获取到加密的密钥会话密钥之后可以快速尝试破解。而如果加了盐,那么则盐的长度越大,候选KEK的数量也会随之增大,这时事先生成候选KEK就会变得非常困难。因为加盐后的密钥空间=字典空间*盐的空间,而盐是一个随机序列,长度越大,密钥空间也会越大。
如果攻击者也是在本机进行密码爆破,那么似乎只要对口令进行爆破即可,因为被加密的会话密钥和盐也在本地。而如果是远端爆破,因为没有盐的存在那么就会很费劲。
14、PGP--密码技术的完美结合
(1)PGP是一款对文件进行加解密、签名、验证的软件工具,几乎具备现代密码软件所必须的全部功能。同类型的工具还有GPG、Openssl。
(2)PGP的功能:对称密码、公钥密码、数字签名(可以附加到加密文件上、或者单独分离成二进制文件或文本文件)、单向散列函数、证书、压缩(首先对数据压缩然后再加密)、文本数据(通过base64将无法传输二进制的文件编码为文本文件进行传输)、大文件拆分和拼合(文件太大无法传输时可拆分处理)、钥匙串管理(可以管理所生成的密钥对以及外部获取的公钥,用于管理的文件称为钥匙串,GPG的钥匙串在家目录/.gnupg/pubring.kbx)。
(3)PGP加密、签名、加密及签名流程图
(4)信任网
在使用公钥密码的过程中,一个首要问题就是公钥是否合法可信。证书就是确认公钥合法性的方法之一,它通过验证由认证机构签发的数字签名来确认证书合法性;在PGP中没有使用认证机构,而是通过用户互相之间对对方的公钥进行数字签名的方式来建立信任网以此来建立互相之间的信任关系。
信任网的要点就是“不依赖认证机构,而建立起每个人之间的信任关系”,即由自己设置对谁进行何种级别的信任以此来决定要信任哪些公钥。
PGP当初设计的目的是在连国家都不可信的情况下依然能够使用,因此它并不关心有没有可信的认证机构,而是采用“由用户自己来决定信任谁”这样的设计。
(5)信任网中的3个场景:
备注:A导入B的公钥此时的信任级别应该是unknown或undefined,当A对B的公钥进行签名之后,他的默认信任级别可能就是undefined了,当定义了级别之后,就会是2-4这三种状态了。
每个用户可以自己给自己签名,即自签名。例如B自签名之后发给A,A在收到之后会在自己的密钥串中查找对应签名的公钥然后确定信任级别,以此来确认公钥是否可信。
15、SSL/TLS--安全通信
(1)PGP是一款对文件进行加解密、签名、验证的软件工具,几乎具备现代密码软件所必须的全部功能。而SSL/TLS是一个提供安全传输通道的网络协议,它也是综合运用了对称密码、公钥密码、消息认证码、数字签名、伪随机数生成器等技术。
(3)TLS1.0(SSL3.1)协议组成
TLS协议是由“TLS记录协议”和“TLS握手协议”这两层协议叠加而成,低层的记录协议负责确定上层的握手协议数据的封装格式,上层的握手协议则负责加密通道协商及其它应用层数据的加密操作。
(3.1)TLS记录协议:负责确定各种握手协议数据的封装格式。
(3.2)TLS握手协议
(4)记录协议处理流程
(5)握手协议处理流程
备注:数据包流程标识中,不加括号的是必须流程,圆括号是可选,中括号是非握手协议且必须。