从零开始了解 TLS 1.3 系列笔记(二)—— 实用密码学之「引言」

前言

TLS 协议是一种密码学实践, 其目标如其名曰 “传输层安全”, 在假设完全不可信的信道上提供安全的通信. 这要求 TLS 协议必须满足以下安全目标:

  • 确保数据不会被中间人获取;
  • 确保数据不被中间人篡改;
  • 确定对端的真实身份, 确保通信双方的身份可信.

通俗地说, 我们需要维持消息的机密性 (confidentiality), 以及消息的真实性 (authenticity)、完整性 (integrity) 和不可否认性 (non-repudiation). 为此, TLS 协议使用了大量的密码学算法原语、组件, 如哈希函数, 对称加密算法, 非对称加密算法, 数字签名算法等. 在系统地理解 TLS 协议之前, 我们需要先了解这些密码学基础概念.

什么是密码学

密码学 (Cryptography) 是提供信息安全和保护的科学. 它在我们的数字世界中无处不在, 当你打开网站时、发送电子邮件时、连接到 WiFi 网络时, 使用账号密码登录 APP 时、使用二步认证验证码认证身份时, 都有涉及到密码学相关技术. 因此, 开发人员应该对密码学有基本的了解, 以避免写出不安全的代码. 至少也得知道如何使用密码算法和密码库, 了解哈希、对称密码算法、非对称密码算法与加密方案这些概念, 知晓数字签名及其背后的密码系统和算法.

以下密码学基础概念(术语)将在本文以及后续文章中频繁出现, 需要熟悉.

  • 熵 (entropy) 与安全随机数生成器.
  • 哈希函数 (Hash Function, 也称散列函数), 如 MD5, SHA-1, SHA-2 (主要包括 SHA-256, SHA-384, SHA-512 三个变体) 等.
  • 哈希消息认证码 (Hash-based Message Authentication Code, HMAC), 如 HMAC-SHA-256.
  • 密钥派生函数 (Key Derivation Function, KDF), 如 Scrypt.
  • 密钥交换算法 (Key Exchange Algorithm), 如 Diffie-Hellman (DH) 和 ECDH (椭圆曲线 Diffie-Hellman).
  • 对称密钥加密方案 (Symmetric key encryption schemes), 如 AES-128-GCM.
  • 非对称密钥加密方案 (Asymmetric key encryption schemes), 如 RSA 和 ECC (elliptic curves-based cryptography, 椭圆曲线密码学).
  • 数字签名算法 (Digital Signature Algorithm, DSA).
  • 后量子 (Post-Quantum) 安全.

如果你有过一些开发经验, 可能会很熟悉其中部分名词. 如果不熟也没任何关系, 都会在本系列文章内介绍, 请坐和放宽.

密码学的用途

熵与安全随机数

熵 (entropy, 指不可预测的随机性) 是密码学的重要部分, 大量算法的安全性都仰赖于具备足够熵的随机数.

计算机无法产生真正的随机数, 只能从外部获得 “真” 随机性:

  1. Linux 系统下的 /dev/urandom 的随机性来源于硬件中断、按键输入、鼠标移动、磁盘 IO 等不可预测的系统事件;
  2. Cloudflare 使用一面熔岩墙 获得真随机性…

区别于真随机性, 通过特定算法从一定的随机性种子 (seed) 生成的随机性我们称之为伪随机性, 伪随机性显然由于随机性种子的来源有高低优劣之分. 密码学操作在需求随机性时, 往往要求使用安全伪随机数生成器 (Cryptographically secure pseudo-random number generator, CSPRNG), 基于具备足够熵的随机性种子生成高质量的伪随机数: 通过 CSPRNG 生成的随机数即便攻击者在统计学意义上能收集大量过往产生的随机数进行分析, 或者计算上通过特定手段探知得 CSPRNG 内部状态, 均无法推测出未来的随机数. 而大部分编程语言内置的伪随机数生成器出于性能因素, 在设计上是基于时间戳等可预测性强的随机数种子的, 不具备密码学安全性.

哈希函数与 HMAC

哈希函数, 如 MD5、SHA-1、SHA-2, SHA-3 和 BLAKE2 等, 将任意长消息不可逆地转换固定长度的哈希值, 称消息摘要 (digest). 哈希函数被设计为几乎不可能找到具有相同哈希值的两条不同消息, 违背这一点的哈希函数被认为是不安全的, 如 MD5 和 SHA-1.

基于哈希函数的特性, 可以将特定哈希函数用于验证消息完整性, 称 HMAC.

KDF

文本密码绝大部分情况下不具备足够的熵, 不能直接作加密密钥. KDF (Key Derivation Function, 密钥派生函数) 负责从文本密码安全地派生出具备足够熵的密钥, 且往往还通过注入随机参数 (盐, salt) 和使用大量迭代和计算资源使暴力计算所有可能的密钥变得不可行. 常用的 KDF 包括 PBKDF2、Scrypt 和 Argon2 等.

密钥交换

密钥交换算法、方案允许通信双方经由完全不可信的信道安全地协商共享密钥. TLS 中使用到的密钥交换算法包括传统 Diffie-Hellman (DH) 和基于椭圆曲线的 ECDH (Elliptic Curve DH), 以及后量子安全的密钥交换算法 (如 ML-KEM).

加解密

密码学自诞生之日起最大用途, 就是进行数据的安全存储和安全传输. 按密钥数量, 可将加密算法分为两类:

  • 对称 (Symmetric) 加密: 加密和解密使用相同的密钥.

    如 AES 和 ChaCha20.

  • 非对称 (Asymmetric) 加密: 加密和解密使用成对的不同的密钥.

    非对称加密用到的两个密钥在数学上是关联的, 我们称其为 “密钥对”; 其中一把密钥公开, 另一把密钥保密, 我们分别称其为 “公钥” 和 “私钥”; 公钥可以由私钥计算得到, 但反过来则几乎不可能实现.

    非对称加密体系也称公钥密码学体系.

一般而言, 对称加密比非对称加密更快, 但非对称加密更安全. TLS 等现代加密协议通常会结合使用对称和非对称加密, 以平衡最佳的安全性和性能.

单纯使用加密算法是不够的, 这是因为有的加密算法只能按块进行加密, 而且很多加密算法并不能保证密文的真实性、完整性. 因此, 现实中我们通常会使用一套加密方案进行数据的加解密. 加密方案由一系列加密算法、消息认证算法或数字签名算法、块密码模式等多种密码学原语组合得到, 以同时保证数据的安全性、真实性、完整性;加密方案的名称就是使用到的各种密码算法名称的组合, 如 AES-128-GCM、ChaCha20-Poly1305 等. 后面我们再详细了解.

数字签名和消息认证

密码学当中, 数字签名算法 (Digital Signature Algorithm, DSA) 算法和消息认证 (Message Authentication) 算法提供了对消息真实性、完整性和不可否认性的保证.

DSA 首先是个公钥密码学体系, 大多数数字签名算法使用非对称加密原语: 使用私钥加密特定信息, 此即签名; 由相应的公钥解密, 此即验签 (保证双方持有合法的密钥对).

MAC 跟数字签名的功能实际上是一致的, 区别在于其使用哈希算法 (HMAC), 或者对称加密原语.

现代加密协议通常会结合使用数字签名和消息认证.

混淆与扩散

在密码学当中, 香农提出的「混淆」 (confusion) 与「扩散」 (diffusion) 是设计安全密码学算法的两个原则.

「混淆」使密文和对称加密中密钥的映射关系变得尽可能的复杂, 使之难以分析. 如果使用了混淆, 那么输出密文中的每个比特位都应该依赖于密钥和输入数据的多个部分, 确保两者无法建立直接映射. 混淆常用的方法是「替换」与「排列」.

「扩散」将明文的统计结构扩散到大量密文中, 隐藏明文与密文之间的统计学关系. 使单个明文或密钥位的影响尽可能扩大到更多的密文中去, 确保改变输入中的任意一位都应该导致输出中大约一半的位发生变化, 反过来改变输出密文的任一位, 明文中大约一半的位也必须发生变化. 扩散常用的方法是「置换」.

这两个原则被包含在大多数哈希函数、MAC 算法、随机数生成器、对称和非对称密码算法中.

值得指出, “XOR 加密” 的说法本质上是错误的. XOR 操作本身并不提供混淆或扩散.

关于库的使用

程序员常自嘲为 Ctrl-C / Ctrl-V 工程师, 但在密码学领域反而推荐那么干, 以获得经大量实践验证的当下最优的安全性. 当然, 盲目地从互联网复制粘贴代码也可能会导致安全问题; 曾经安全的代码、算法或者最佳实践, 随着时间的推移也可能变得不再安全.

本章小结

密码学是一个庞大而复杂的领域, 在后续的文章中, 我们将继续深入探讨 TLS 1.3 协议这一密码学最佳实践. 虽然本章很短, 但不管怎么样, 通过本章内容先建立一个全局观念是极好的.

部分参考文献