kaspterio code as a hacker

17 September 2021

密码学可以说是所有计算机学科中科学和工程结合的最紧密的学科之一,并且两者都极其重要。TLS协议作为现代互联网数据安全的基石,自1994年由Netscape首次推出以来(当时叫SSL)发展至今已经有快30年历史了,可以说汇集了现代密码学众多的理论研究成果和安全实践经验,学习TLS的设计一方面对了解现代密码学的应用具有很好的参考价值。另外一面,密码学领域内的轮子区别于其他领域内的轮子,作者需要具备严格的密码学学术训练和大量领域工程实践经验,代码本身也需要经过大量的同行审议,才能算作是可用,这个领域不提倡一言不合就自己造轮子,TLS协议这个有着多年发展迭代历史、经过大量研究人员审议,应该我们在绝大部分场景选择安全通信协议时候的不二选择。这篇blog将会深入TLS协议的细节,记录和学习TLS协议的设计和演进。需要说明的是想要深入学习TLS协议是有一定门槛的,读者需要具备一定的密码学背景知识。

tls的设计目标

  • 密码学安全性:TLS首先是为了给通信的双方建立安全的连接
  • 互操作性:通信双方可能有着不同的协议实现,也能够通过协商达成一致的密码学参数
  • 可扩展性:TLS提供了一个能够有机整合各种密码学算法的可扩展的框架
  • 相对有效性:通常来说密码学算法是计算密集型的,因此TLS协议也提供了一些可选的session重用的机制来减少连接建立所需的计算和时间开销

随着内容的深入,后面我们可以一一看到TLS协议是怎么达成这些设计目标的。

tls CipherSuite

在介绍TLS的密码学算法套件前先简单捋一下常见的密码学算法和作用,常见的算法主要有以下几种

块加密算法 block cipher

工作原理是对固定大小的block的明文进行置换,生成同样大小的密文,明文和密文间是一一映射(置换的性质)。常见的有DES(基本不用了)、3DES、AES(比较主流)等等。

流加密算法 stream cipher:

一种是原生的流加密算法,工作原理是通过生成一个任意长度的伪随机字节序列作为keystream, 将keystream和明文进行XOR得到密文。常见的有RC4, Salsa20、ChaCha20等。

还有一种就是由一种块加密算法通过某种构造模式进行组合,从而将明文流划分为一个个block,每个block应用block cipher加密,block间往往不是独立的,而是通过某种构造模式联系起来,常见的构造模式有:

  • ECB(最naive的构造模式,块和块间完全独立,也是完全不安全的构造模式)
  • CBC(cipher block chaining,应用最多的模式,每个block加密前和上一个block的密文XOR一下)
  • CFB、OFB、CTR等等不一一介绍了。 这种通过block cipher构造的stream cipher的方式涉及到两个概念,Initialization Vector(IV) 和 Padding,需要IV作为对于第一个block的前一个block进行XOR。需要padding是因为明文大小往往不是block size的整数倍。

密钥交换算法 key exchange:

块加密和流加密算法都是对称加密算法,即通信双方有着同样的通信密钥,这对于网络通信的涉及到双方而言,要么双方认识,在通信前就在线下提前确定好了通信密钥 (pre-shared key: PSK),要么就需要通过一种密钥交换算法即时协商出一个通信密钥,密钥交换算法工作的假设是在一个不安全的信道上协商出只有通信双方知道的密钥,所谓的不安全就是可能有窃听者或者中间人。

常见的密钥交换算法有:

RSA based key exchange

RSA作为应用很广的非对称加密算法的典型被人们所熟知,它用来做密钥交换的基本原理是Alice生成一个通信对称密钥,并且用Bob的RSA公钥去加密,Bob收到后用自己的RSA私钥去解密,这样除了Alice和Bob,没人能知道通信的对称密钥,看上去很好。这里我吐槽一句,网上有一大堆介绍TLS的过时文章和blog,里面在介绍密钥协商的时候只提RSA这种方式,导致很多人印象中TLS都是以RSA这种方式来协商密钥的。我在过往的技术面试过程中,但凡问到候选人关于TLS密钥协商的内容,都是回答用非对称加密来加密对称加密的密钥,要知道这种做法已经没人在用了,不具备前向安全。

DH based key exchange

Diffie-Hellman协议是一种通用的密钥交换协议,通信的双方仅通过交换公钥来计算出一个共同的密钥。alice和bob都拥有对方的公钥和自己的私钥,通过这两者双方都能计算出一个共同的密钥。

最简单DH实现是Alice随机生成一个私钥a, 计算A=(G^a) mod P 作为公钥,其中P是很大的质数,G不需要很大,一般就是2或者5。假设另一方Bob生成的私钥是b,那么对应的公钥就是B=(G^b) mod P, 双方交换公钥后Alice计算 B^a mod P == G^(ab) mod P, Bob计算A^b mod P = G^(ab) mod P,于是得到共同的密钥。由于从公钥计算私钥在数学上是个难题(离散对数问题),因此第三方无法仅通过公钥计算得到通信密钥。需要指出的是DH协议本身不能防范MITM攻击,中间人完全可以分别和Alice和Bob进行DH协商出不同的密钥,因此DH需要配合身份认证机制一起才能安全工作,实际的DH交换主要有两种方式

  • Fixed Diffie-Hellman (简称为DH): 对于client server通信来说,我们可以将server端的DH公钥固化在证书文件里,所有和server进行通信的client都使用相同的server DH公钥,这样client只要验证了server端的证书,就可以放心大胆地和server进行DH交换了,但是这样做面临和基于RSA交换密钥同样的问题,就是不具备前向安全性。
  • Ephemeral Diffie-Hellman (简称为DHE): 相对于fixed DH,DHE就是通信的双方都使用动态的DH公私钥对(每次DH会话采用不同的DH key pair),server端除了发送自己的本次会话的DH公钥外还需要发送对DH公钥的签名,client通过验证签名来确认server身份,然后进行DH交换协商会话密钥。

原始DH的密码安全性在数学上是通过离散对数问题来保证的,但是基于离散对数问题的DH做到安全所需要的private key size通常很大。后来数学家们发现可以在一个椭圆曲线上定义一种加法运算(这里省略这个运算的定义),基于这个加法运算和一个零元可以定义出这个椭圆曲线上一个可交换群(省略定义)。数学上认为,给定椭圆曲线上一个点P和任意一个整数n,计算n * P = P + P + … + P = Q是相对容易的,反之对于一个定义在有限域上的椭圆曲线,给定P和Q,计算n是非常困难的。这个难题姑且称为有限域上椭圆曲线的离散对数问题,将这个难题和DH结合就是ECDH、ECDHE。由于这个上椭圆曲线的离散对数问题要比比普通的离散对数问题要困难很多,因此在同等安全性要求下其所需要的private key size要比普通离散对数问题小很多。

没有抽象代数背景的同学估计已经有点懵了,不要怕,这里有篇非常通俗易懂的ECC介绍,这个系列有三篇文章,感兴趣自行查阅。

Hash算法

hash算法基本上每个程序员都会打过交道,在密码学中hash算法是一个非常重要的primitive,通常被用来构造其他密码学算法,比如后面提到的 消息验证码算法、签名算法、key派生算法、随机数生成算法等等都有hash算法的身影。密码学中的hash算法通常指的是具备密码学性质的Cryptographic hash functions,一个Cryptographic hash function需要具备以下几个性质:

  • hash需要具有雪崩效应,改变一点消息内容都会导致hash值发生较大的变动。
  • hash计算是个单向函数,即从hash值不能/很难得到原始消息
  • 很难找到两个消息具有相同的hash,即很难发生hash碰撞。

常见的密码学hash有MD5,SHA-1, SHA-2家族(SHA-256, SHA-512…)。其中MD5,SHA-1都已经被认为不再密码学安全了,SHA-2目前不仅在计算性能上优于SHA-1,也具备更好的安全性和碰撞抗性,目前被广泛应用。

关于MD5再多说一点,MD5被广大程序员们滥用最多的地方是用户密码存储,具体做法是后台数据库里不直接存储用户的密码,而且存储密码的经过MD5计算后的摘要,校验用户身份的时候计算用户请求中的密码的MD5和后台存储的MD5值进行比对。这样做来防止数据库被端时候泄漏所有用户密码。这样做显然早就不安全了,由于用户密码的entropy太低了,攻击者完全可以预计算好一个hash到密码的映射链表(俗称彩虹表),有了这个彩虹表,破解用户密码就是简单的查表操作。

聪明的程序员们为了让彩虹表攻击失效,考虑为了每个用户hash计算加盐,即hash = MD5(salt, password),数据库里不仅存储hash,也存储了用户salt,这样攻击者拿到数据库后也不能使用预计算好的彩虹表破解用户密码。这招在十几年前可能还算有效,毕竟全局的彩虹表失效了,但是再现代强大的计算能力下,攻击者完全可以做到在合理的时间内动态根据salt值生成per user的彩虹表,照样破解用户密码。

那么正确的存储用户密码的做法是什么呢?现在主流的做法是基于Bcrypt这样的密码hash函数,有着non-trivial的计算复杂度,能够在一定程度上抵御暴力破解。Bcrypt算法内置了生成salt和hash,而且计算复杂度可调,这样随着硬件计算能力的提升,使用者可以相对应的调节算法的计算代价。

消息验证码算法(MAC)

在实际应用中,光有加密是不够的,因为密文可能被篡改,可能压根就不是对端发的,此时需要有消息验证机制来识别这些情况,从而丢弃不合法的消息。消息验证码的作用就是为了校验消息的真实性和完整性。MAC算法和对称加解密算法很类似,首先他们工作都需要一个对称密钥,其次他们都由两部分构成。MAC算法的第一部分是MAC生成算法,输入是key和message,输出是一个tag,第二MAC校验算法,输入是key、message和tag,输出是这个tag是否valid(valid表示message是真实且完整的)。HMAC(Hash-based Message Authentication Code)作为一个生成MAC的标准被广泛应用,tls协议使用的mac算法就是hmac标准,从名字也可以知道HMAC基于一个密码学hash函数。

将加密和消息验证码结合起来通常有三种方式:

  • Authenticate and encrypt: 这种是指MAC生成和加密独立进行,即对明文生成MAC,同时对明文进行加密,将MAC和密文一起发给对端。SSH就是这么做的
  • Authenticate, then encrypt: 这种是指先对明文生成MAC,后对明文和MAC一起进行加密得到密文,发给对端,这也意味着对端需要先解密得到明文和MAC,再校验MAC是否有效。TLS过去就是这么做的
  • Encrypt, then authenticate:这种则是指先加密得到密文,再对密文生成MAC,将密文和MAC发给对端,对端在接受到后需要先校验MAC,如果通过再进行解密得到明文。

现在业界已经广泛接受,只有Encrypt, then authenticate才是最安全的选择,其他两种方式都存在已知的攻击方法,以至于密码学家觉得干脆将Encrypt, then authenticate这种模式固化到一个算法里面好了,避免人们做出错误的选择。这也就是AEAD(Authenticated-Encryption With Additional data)模式的motivation。所谓的Additional data通常是指我们要传输的数据不仅仅有消息内容本身,还是一些关于消息内容的metadata,而且这些metadata往往是不能加密的(比如邮件的发送方、接收者信息)我们不仅希望AE算法能够authenticate消息内容本身,还要能够authenticate metadata。AEAD内部在计算MAC时候将metadata通过某种方式和消息密文进行组合才生成MAC,这样对端在校验MAC也就同时验证了metadata以及密文的合法性。AEAD的实现可以基于block ciper进行构造组合,也可以基于native stream ciper。业界目前最广泛应用的AEAD是block ciper进行GCM模式构造。

MAC保证了消息的真实性和完整性,但是MAC本身不能防止攻击者重放攻击,即攻击者保存了此前双端通信的消息和MAC,然后进行重放,接收方收到后能够校验成功、正常解密,所以一个安全的协议还需要别的机制来防止重放,后面我们会看到TLS是怎么做的。

签名算法

签名算法和MAC算法的作用类似,都是为了验证对端身份,不同的是MAC算法工作需要双方已有一个共同的对称密钥,然而在很多场景下,通信双方事先没有这个共同的密钥,比如在双方进行密钥交换前,怎么验证server端的证书、怎么验证server发的DH公钥都会涉及到签名。

基于非对称密钥的签名算法通和非对称密钥的加密算法工作过程刚好相反,签名算法是key pair的持有方用private key来生成对消息的签名(通常会基于一个Cryptographic hash function来生成消息的签名),对端使用public key来验证消息签名(验证过程通常会是用public key计算消息的签名,然后和对端传来的进行对比)。非对称加密算法则是由对端使用public key来对message进行加密,key pair持有方使用private key对密文进行解密。

常见的签名算法有

  • RSA: 这个不用多说了,RSA既可以用来做加密,也可以用来生成签名。
  • DSA: 与RSA不同的是DSA使用了一个Cryptographic hash function来生成签名,
  • ECDSA: DSA算法的椭圆曲线版本

密钥派生算法

密钥派生算法的作用很直观,就是从一个密钥派生多个密钥。比如双方进行DH交换协商出一个密钥后,通常会用一个密钥派生算法派生出多个密钥,用于加解密、生成/验证mac等等。

密钥派生算法主要有两种,一种是针对entropy足够高的输入密钥的,比如DH交换得到的密钥,这种派生算法通常计算代价相对较低,比如主流的HKDF算法,TLS1.2采用的TLS-12-PRF(SHA-256)算法。还有一种则是针对entropy低的密钥,比如用户设置的密码,这类算法则要求派生算法本身需要花费non-trivial的计算资源来派生密钥,否则派生出来的密钥安全性得不到保证,比如PBKDF2,以及前面提到的Bcrypt, Scrypt。

tls CipherSuite 构成

TLS的一个完整的CipherSuite可以认为主要有四个算法组合到一起:

  • key exchange 密钥交换算法
  • authentication/signature 认证签名算法
  • encryption 对称加密算法
  • message authentication code MAC算法 (可能和encryption算法结合到一起)
  • key derivation 密钥派生算法
> openssl ciphers -V
  0xCC,0xA9 - ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=ChaCha20-Poly1305 Mac=AEAD
  0xCC,0xA8 - ECDHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH     Au=RSA  Enc=ChaCha20-Poly1305 Mac=AEAD
  0xCC,0xAA - DHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=DH       Au=RSA  Enc=ChaCha20-Poly1305 Mac=AEAD
  0xC0,0x30 - ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
  0xC0,0x2C - ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
  0xC0,0x28 - ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA384
  0xC0,0x24 - ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA384
  0x00,0x9F - DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(256) Mac=AEAD
  0x00,0x6B - DHE-RSA-AES256-SHA256   TLSv1.2 Kx=DH       Au=RSA  Enc=AES(256)  Mac=SHA256
  0x00,0xC4 - DHE-RSA-CAMELLIA256-SHA256 TLSv1.2 Kx=DH       Au=RSA  Enc=Camellia(256) Mac=SHA256
  0x00,0x9D - AES256-GCM-SHA384       TLSv1.2 Kx=RSA      Au=RSA  Enc=AESGCM(256) Mac=AEAD
  0x00,0x3D - AES256-SHA256           TLSv1.2 Kx=RSA      Au=RSA  Enc=AES(256)  Mac=SHA256
  0x00,0xC0 - CAMELLIA256-SHA256      TLSv1.2 Kx=RSA      Au=RSA  Enc=Camellia(256) Mac=SHA256
  0xC0,0x2F - ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(128) Mac=AEAD
  0xC0,0x2B - ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(128) Mac=AEAD
  0xC0,0x27 - ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(128)  Mac=SHA256
  0xC0,0x23 - ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(128)  Mac=SHA256
  0x00,0x9E - DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(128) Mac=AEAD
  0x00,0x67 - DHE-RSA-AES128-SHA256   TLSv1.2 Kx=DH       Au=RSA  Enc=AES(128)  Mac=SHA256
  0x00,0xBE - DHE-RSA-CAMELLIA128-SHA256 TLSv1.2 Kx=DH       Au=RSA  Enc=Camellia(128) Mac=SHA256

这里举几个openssl中tls1.2的cipherSuite实现为例,AES256-SHA256在tls协议文档中全名叫做TLS_RSA_WITH_AES_256_CBC_SHA256,它的key exchange算法使用的就是RSA,认证签名算法使用的也是RSA(证书中用RSA签名),加密算法中的AES256,并通过CBC模式进行扩展,MAC算法和key派生基于SHA256,这里需要说明下tls中mac算法采用的是HMAC标准,这里说的基于SHA256指的是HMAC中的hash函数使用的是SHA256,另外tls协议自定义一个基于HMAC的PRF函数用于key派生算法,所以它们都基于同一个hash方法。DHE-RSA-AES256-SHA256全称叫做TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,密钥交换使用的DHE,签名使用RSA,加密使用AES256-CBC,MAC和key派生基于SHA256。ECDHE-ECDSA-AES256-GCM-SHA384密钥交换使用ECDHE,签名使用ECDSA,认证加密使用AES256-GCM(GCM是AEAD的一种实现),由于MAC和加密结合到一起,所以Mac值就是AEAD,key派生基于SHA384。

tls工作过程和record协议

tls协议工作在tcp协议之上,连接连接后,首先需要通过握手过程让通信双端协商出一堆密码学状态,握手过程重要且很多细节,准备放到另外一篇blog里介绍。这里先介绍握手完成后双端的状态和tls协议对应用数据的处理过程。

tls record frame

tls record帧格式很简单,由header和content两部分组成,header里面包括以下几个字段

  • content type: 标识content部分的类型是什么,占8位
  • protocal version:标识协议的版本,分为major和minor两部分,共占16位
  • length: 标识content的length,占16位,TLS允许的最大content长度是2^14 + 2048

record frame

content部分取决content type,目前tls定义了以下几种content type

  • handshake: 也就是tls的handshake子协议,在握手阶段使用
  • application_data: tls承载的上层应用数据,在应用数据传输阶段使用
  • change_cipher_spec: 在tls完成握手后,会使用这个type的包通知对端进行内容切换,开始传输应用数据,在tls1.3中已经去掉了
  • alert: 用于通知对端各种错误码

tls application_data processing

tls 状态

tls协议和很多其他有状态协议一样,双端需要通过协商在内存中维护很多一致的状态才能进行工作,这些状态也是tls record协议工作所依赖的环境上下文。状态主要分为两类,1) 通过协商得到的在整个connection生命周期内保持不变的状态,以及2)双方通信的进行,每收发一个record就需要更新的状态。

1) 主要包括:双方协商一致的cipherSuite以及握手完成后得到的SecurityParameters,

      struct {
          ConnectionEnd          entity; //标识是client还是server
          PRFAlgorithm           prf_algorithm; //用于key派生的算法
          BulkCipherAlgorithm    bulk_cipher_algorithm; // 对称加密算法(null, rc4, 3des, aes)
          CipherType             cipher_type; // 密文类型(stream, block, aead)
          uint8                  enc_key_length; //对称密钥长度
          uint8                  block_length; //block大小 (如果有的话)
          uint8                  fixed_iv_length; //固定全局iv长度 (作用是啥)
          uint8                  record_iv_length; //每个record进行block加密的iv长度 (和block_length相等)
          MACAlgorithm           mac_algorithm; // mac算法
          uint8                  mac_length; //mac长度
          uint8                  mac_key_length; //mac密钥长度
          CompressionMethod      compression_algorithm; //压缩算法
          opaque                 master_secret[48]; //握手阶段运行key exchange算法得到的master secret,这也是后面所有对称密钥的base
          opaque                 client_random[32]; //client 随机数
          opaque                 server_random[32]; //server 随机数
      } SecurityParameters;

双方根据得到的SecurityParameters,通过tls自定义的key派生算法从master_secret派生出下面的一堆密钥和iv (client和server的write mac key、write encryption key、write IV),用于后续的应用数据的加解密。具体的key派生算法工作如下:

tls先定义了一个P_hash函数:

P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +                              
                       HMAC_hash(secret, A(2) + seed) +
                       HMAC_hash(secret, A(3) + seed) + ...
其中A() 定义为:       
    A(0) = seed       
    A(i) = HMAC_hash(secret, A(i-1))
    
P_hash可以迭代任意次以产生任意长度的的数据。

tls应用P_hash定义了一个PRF函数:
PRF(secret, label, seed) = P_<hash>(secret, label + seed)

tls的key派生就是使用的这个PRF,具体是:

key_block = PRF(SecurityParameters.master_secret,                       
                "key expansion",
                SecurityParameters.server_random + SecurityParameters.client_random)

得到key_block后按照如下顺序对进行分割得到key和iv:                
client_write_MAC_key[SecurityParameters.mac_key_length]       
server_write_MAC_key[SecurityParameters.mac_key_length]
client_write_key[SecurityParameters.enc_key_length]
server_write_key[SecurityParameters.enc_key_length]
client_write_IV[SecurityParameters.fixed_iv_length]
server_write_IV[SecurityParameters.fixed_iv_length]

值得说明的有:

  • client -> server和server -> client方向加密使用的是不同的encryption key和mac key和IV,这样做对所有加密算法而言都更安全。
  • MAC key不一定用到,对于AEAD来说,不需要MAC key
  • write IV作用目前仅仅是用于构造AEAD模式下的nonce,不用于block-ciphered的record IV。随着record的收发, 每个record都需要随机生成新的IV。

2)主要包括:

  • 压缩算法的状态,需要说明的是虽然tls协议支持压缩,但是一定要禁用压缩,压缩会遭受CRIME攻击。
  • 加密算法的状态,指的是加密算法工作过程中产生的状态。
  • sequence number,序列号是个很重要的状态,同样client -> server和server -> client使用不同的sequence number,从0开始,每发送一个record,seq +1。seq的作用很明显,就是为了防止重放攻击,要知道加密+mac本身不能防重放。另外需要说明的是seq不需要作为数据被传输,只需要参与mac计算就行。由于tls基于tcp,record是顺序交付的,seq在收发双方是保持同步的,收到record包验证mac时候直接用当前seq来验证。

tls 处理应用数据过程

application data process

  • 发送端首先需要对应用层数据进行组合或者分片形成一个个record。tls不保留原始数据的消息边界,由于基于TCP,record会按序依次交付给对端,对端收到record解密后交付应用层,由应用层根据应用层数据协议恢复消息边界。
  • 对每个record,tls再进行可选的数据压缩处理,再次强调,要禁用tls压缩。
  • 最后对上一步的record进行加密处理,依据所采用的加密算法可以分为三种,分别是stream-ciphered加密,block-ciphered加密,aead-ciphered加密。其中需要说明的是除了aead外,tls中加密认证采用的方式是Authenticate then encrypt,先根据plaintext等信息计算mac,再对plaintext和mac等信息一起进行加密。另外mac的计算也很重要,采用以下方式得到:
    MAC(MAC_write_key, seq_num +   //注意mac计算需要seq_num的参与
                      TLSCompressed.type +
                      TLSCompressed.version +
                      TLSCompressed.length +
                      TLSCompressed.fragment);
    

    类似的,seq_num + TLSCompressed.type + TLSCompressed.version + TLSCompressed.length也作为aead加密下的additional_data。

strem-cipher

strem-cipher

block-cipher

block-cipher

aead-cipher

aead-cipher

总结

回顾下tls协议的四个设计目标:密码学安全性、互操作性、可扩展性和相对有效性,这篇blog侧重的是分析tls怎么做到密码学安全性的部分内容,主要是给了一些密码学背景知识,然后介绍了下tls record怎么来保证应用层数据的安全。下一篇blog将继续介绍和分析tls协议的重要且复杂的握手过程,双端通过tls握手才能建立一个安全的连接,tls record协议才能工作。