<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="https://i.han.rs/feed_style.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh">
    <tabi:metadata xmlns:tabi="https://github.com/welpo/tabi">
        <tabi:base_url>https:&#x2F;&#x2F;i.han.rs</tabi:base_url>
        <tabi:separator>
            •
        </tabi:separator>
        <tabi:about_feeds>这是Web Feed，又称为Atom Feed，把现在的网址复制到新闻阅读器即可订阅本站文章。造访「About Feeds」来了解更多资讯。</tabi:about_feeds>
        <tabi:visit_the_site>造访网站</tabi:visit_the_site>
        <tabi:recent_posts>近期文章</tabi:recent_posts>
        <tabi:last_updated_on>更新于 $DATE</tabi:last_updated_on>
        <tabi:default_theme></tabi:default_theme>
        <tabi:post_listing_date>date</tabi:post_listing_date>
        <tabi:current_section>Cryptography</tabi:current_section>
    </tabi:metadata><link rel="extra-stylesheet" href="https://i.han.rs/skins/sakura.css?h=2d9c69af51135683e3bd" /><title>i.han.rs - Cryptography</title>
        <subtitle>Emmm?</subtitle>
    <link href="https://i.han.rs/tags/cryptography/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://i.han.rs/tags/cryptography/" rel="alternate" type="text/html"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-02-10T00:00:00+00:00</updated>
    <id>https://i.han.rs/tags/cryptography/atom.xml</id><entry xml:lang="zh">
        <title>从零开始了解 TLS 1.3 系列笔记 (六) —— 实用密码学之「对称加密、AEAD 与非对称密码学」</title>
        <published>2025-09-17T00:00:00+00:00</published>
        <updated>2025-09-25T00:00:00+00:00</updated>
        <author>
            <name>Hantong Chen</name>
        </author>
        <link rel="alternate" href="https://i.han.rs/blog/25-09-17-tls-series-cryptography-5/" type="text/html"/>
        <id>https://i.han.rs/blog/25-09-17-tls-series-cryptography-5/</id>
        
            <content type="html">&lt;blockquote&gt;
&lt;p&gt;一些密码学高频英文术语需要我们了解&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;加密 (encrypt), 解密 (decrypt)&lt;&#x2F;li&gt;
&lt;li&gt;密文 (ciphertext), 明文 (plaintext)&lt;&#x2F;li&gt;
&lt;li&gt;对称加密 (symmetric encryption), 非对称加密 (asymmetric encryption)&lt;&#x2F;li&gt;
&lt;li&gt;“cipher”: 一般指 “加密算法”, 但有些翻译会直译为 “密码”, 需要和 “password” 区分.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;密码学中, 依据加解密密钥是否相同, 可以将加密算法分为对称加密和非对称加密两大类.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;dui-cheng-jia-mi&quot;&gt;对称加密&lt;&#x2F;h2&gt;
&lt;p&gt;对称加密, 即加密和解密使用相同的密钥. 这种加密方式的优点是加解密速度快, 适合处理大量数据. 常见的对称加密算法包括 AES 和 Chacha20 等.
其中绝大多数都是 “块密码算法 (Block Cipher)” 或者叫 “&lt;strong&gt;分组密码算法&lt;&#x2F;strong&gt;”, 这种算法&lt;strong&gt;一次只能加密固定大小的块&lt;&#x2F;strong&gt; (例如 128 位), 少部分是 “&lt;strong&gt;流密码算法&lt;&#x2F;strong&gt; (Stream Cipher)”, 流密码算法允许将数据逐字节地加密为密文流.
可以使用称为&lt;em&gt;分组密码工作模式&lt;&#x2F;em&gt;的技术, 让分组密码算法也能做到流式加密, 我们会在后文详细了解.&lt;&#x2F;p&gt;
&lt;p&gt;用于加密&#x2F;解密的密钥也被称为共享密钥(需要在通信双方之间共享). 可以是 PSK, 如从密码利用 KDF 派生得到, 或编码为 Base58 &#x2F; Base64 格式; 或者通过密钥交换方案协商或传输.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;小贴士&lt;&#x2F;p&gt;
&lt;p&gt;对称加密所使用的密钥一般是 128 &#x2F; 192 &#x2F; 256 位的二进制数据, 直接使用不便于存储和传输, 因此通常会编码为 Base58 &#x2F; Base64 格式.&lt;&#x2F;p&gt;
&lt;p&gt;原始 (按 HEX 格式给出):&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;02c324648931b89e3e8a0fc42c96e8e3be2e42812986573a40d46563bceaf75110
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Base58 编码:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;pbPRqYDxnKZfs8j4KKiqYmx6nzipAjTJf1oCD1WKgy99
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Base64 编码:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;AsMkZIkxuJ4+ig&#x2F;ELJbo474uQoEphlc6QNRlY7zq91EQ
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;大多数现代对称密钥密码算法都是抗量子的 (quantum-resistant), 当使用长度足够的密钥时 (如 AES-256), 即便是量子计算机也无法破坏其安全性.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;dui-cheng-jia-mi-fang-an&quot;&gt;对称加密方案&lt;&#x2F;h3&gt;
&lt;p&gt;我们知道, 单纯使用加密算法只能保证数据的安全性, 并不能满足我们对消息真实性、完整性与不可否认性的需求, 因此通常我们会将对称加密算法跟其他算法组合成一个对称加密方案来使用:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;KDF (如果是密码作 PSK 的模式, 需要使用 KDF 从密码学强度低的密码派生出密码学强度高的伪随机密钥)&lt;&#x2F;li&gt;
&lt;li&gt;分组密码工作模式 (如 CBC 或 CTR) + 消息填充算法 (如 PKCS7): 分组密码算法, 如 AES, 需要借助这两种算法, 才能加密任意大小的数据 (即所谓的数据流). 而一个流密码加密方案本身就能加密任意长度的数据, 因此不需要分组密码模式与消息填充算法.&lt;&#x2F;li&gt;
&lt;li&gt;密码算法.&lt;&#x2F;li&gt;
&lt;li&gt;消息认证算法: 如 HMAC, 用于验证消息的真实性、完整性、不可否认性.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;如 AES-256-CTR-HMAC-SHA256 就表示一个使用 AES-256 与 Counter 分组模式 (CTR) 进行加密, 使用 HMAC-SHA256 进行消息认证的加密方案.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;fen-zu-mi-ma-gong-zuo-mo-shi&quot;&gt;分组密码工作模式&lt;&#x2F;h3&gt;
&lt;p&gt;前面我们提到分组密码工作模式可以让分组密码算法也能加密任意长度的数据. 其中涉及一些概念值得我们了解.&lt;&#x2F;p&gt;
&lt;p&gt;加密方案的名称中就带有具体的分组模式名称, 如:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;AES-256-GCM - AES 密码算法 + 256 位加密密钥 + Galois Counter Mode (GCM) 分组模式&lt;&#x2F;li&gt;
&lt;li&gt;AES-128-CTR - AES 密码算法 + 128 位加密密钥 + Counter (CTR) 分组模式&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;分组密码工作模式背后的主要思想是把明文分成多个长度固定的组, 再在这些分组上重复应用分组密码算法进行加密&#x2F;解密, 以实现安全地加密&#x2F;解密任意长度的数据.
某些分组模式 (如 CBC) 要求将输入拆分为分组, 并使用填充算法将最末尾的分组填充到块大小, 也有些分组模式 (如 CTR、CFB、OFB、CCM、EAX 和 GCM) 不需要, 因为它们在每个步骤中, 都直接在明文部分和内部密码状态之间执行异或 (XOR) 运算.&lt;&#x2F;p&gt;
&lt;p&gt;使用 “分组模式” 加密大量数据的流程基本如下:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;使用加密密钥 + IV (Initialization Vector, 初始向量) 初始化加密算法状态&lt;&#x2F;li&gt;
&lt;li&gt;加密数据的第一个分组&lt;&#x2F;li&gt;
&lt;li&gt;使用加密密钥和其他参数转换加密算法的当前状态&lt;&#x2F;li&gt;
&lt;li&gt;加密下一个分组&lt;&#x2F;li&gt;
&lt;li&gt;再次转换加密状态&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;依此类推, 直到处理完所有输入数据. 解密的流程类似.&lt;&#x2F;p&gt;
&lt;p&gt;值得注意的是, 显然, 使用 CTR &#x2F; GCM 分组模式时, &lt;strong&gt;密文的大小与明文相同&lt;&#x2F;strong&gt;, 必要时应当进行填充 (padding) 以掩盖明文的真实长度.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;iv&quot;&gt;IV&lt;&#x2F;h4&gt;
&lt;p&gt;IV 也被称作 salt 或者 &lt;strong&gt;nonce&lt;&#x2F;strong&gt;, 通常是一个随机数, 主要作用是往密文中添加随机性, 使同样的明文被多次加密也会产生不同的密文, 从而确保密文的不可预测性.&lt;&#x2F;p&gt;
&lt;p&gt;IV 的大小应与密码块大小相同.&lt;&#x2F;p&gt;
&lt;p&gt;IV 通常无需保密, 但应当足够随机 (GCM 模式下除外). 绝不允许重用 (nonce 即 number once, 一次性的数字).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;gcm-fen-zu-mo-shi&quot;&gt;GCM 分组模式&lt;&#x2F;h4&gt;
&lt;p&gt;GCM (Galois Counter Mode) 是一种广泛使用的分组密码工作模式, 结合了 CTR 模式的加密和 Galois 域上的&lt;strong&gt;消息认证&lt;&#x2F;strong&gt;. GCM 模式下的 AES 加密过程除了得到密文外, 还会得到一个&lt;strong&gt;认证标签&lt;&#x2F;strong&gt; (authentication tag), 一般附在密文后面.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ae-ad&quot;&gt;AE(AD)&lt;&#x2F;h3&gt;
&lt;p&gt;AE(AD) 即 Authenticated Encryption (with Associated Data), (带关联数据的)认证加密, 我们前面已经提到过这个名词, 其包含了 “认证” 和 “加密” 两大部分.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;认证 (Authentication): 通常使用 HMAC, Poly1305, 或者 GCM 分组模式自带.&lt;&#x2F;li&gt;
&lt;li&gt;加密 (Encryption): 使用对称加密算法, 如 AES 或 ChaCha.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;正确实现了消息认证的对称加密方案, 如 AES-256-CTR-HMAC-SHA256, AES-128-GCM, AES-256-GCM 或 ChaCha20-Poly1305 等, 均可称为 AE(AD) 加密方案. 今天的大多数应用程序应该优先选用 AEAD 加密方案进行对称加密, 而不是自己造轮子, 由于密码学的复杂性, 自己造轮子往往会出错.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;性能小贴士: AES 和 Chacha 怎么选择?&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;机器 CPU 支持 AES 硬件加速 (大部分现代 CPU 都支持), 使用 AES.&lt;&#x2F;li&gt;
&lt;li&gt;机器 CPU 不支持 AES 硬件加速, 如 2014 年以前的 x86 架构处理器, 或者移动端相当一部分 ARM 架构处理器, 或者路由器所使用的大部分的 MIPS 架构处理器. 此时使用 ChaCha 会更快 (本来就是为移动端特别优化的).&lt;&#x2F;li&gt;
&lt;li&gt;如果机器 CPU 足够现代且性能强劲, AES 和 ChaCha 差别不大, 在 HTTPS 场景下基本不可能是加密能力瓶颈, 任选其一即可.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;如果想测试, 可以尝试运行:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;openssl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; speed&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;evp&lt;&#x2F;span&gt; aes-128-gcm&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;openssl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; speed&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;evp&lt;&#x2F;span&gt; chacha20-poly1305&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;参考输出:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; openssl &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;speed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;evp&lt;&#x2F;span&gt; chacha20-poly1305&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; (略&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;The&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;numbers&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; are in 1000s of bytes per second processed.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-type z-shell&quot;&gt;type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;              2 bytes     31 bytes    136 bytes   1024 bytes   8192 bytes  16384 bytes&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ChaCha20-Poly1305&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;   135090.41k   398677.07k   685502.68k  4633523.20k  5013787.99k  5053565.35k&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; openssl &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;speed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;evp&lt;&#x2F;span&gt; aes-128-gcm&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; (略&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;The&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;numbers&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; are in 1000s of bytes per second processed.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-type z-shell&quot;&gt;type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;              2 bytes     31 bytes    136 bytes   1024 bytes   8192 bytes  16384 bytes&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;AES-128-GCM&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;      16855.33k   246339.19k  1061738.45k  4942513.83k 13130011.57k 14806788.78k&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;结果显示, 在笔者的机器上, AES-128-GCM 的加密速度 (14.8 GB&#x2F;s) 明显快于 ChaCha20-Poly1305 (5.1 GB&#x2F;s).
然而, 5 GB&#x2F;s 是 40 Gbps 的网络带宽才能达到的速度了, 还只用到了一个核心.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;dui-cheng-jia-mi-suan-fa&quot;&gt;对称加密算法&lt;&#x2F;h3&gt;
&lt;p&gt;以下列举一些常见的对称加密算法.&lt;&#x2F;p&gt;
&lt;p&gt;安全的:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;AES (Advanced Encryption Standard, 高级加密标准): 目前最流行的对称加密算法, 由 NIST 于 2001 年发布. 支持 128, 192 和 256 位密钥长度. AES 是一种分组密码算法, 块大小为 128 位, 使用 128 位的 IV. AES-GCM 是目前最常用的对称加密方案之一.&lt;&#x2F;li&gt;
&lt;li&gt;ChaCha: Salsa 改进版变种, 包括 Chacha20 等. 使用 128 &#x2F; 256 位密钥和 64 位 IV. ChaCha20-Poly1305 也是一种流行的对称加密方案, 结合了 ChaCha20 流密码和 Poly1305 消息认证码.&lt;&#x2F;li&gt;
&lt;li&gt;其他: 包括但不限于 RC5, RC6, 韩国的 ARIA (类似 AES), 中国的 SM4 (类似 AES) 等.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;由于出现安全问题已弃用的:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;DES&lt;&#x2F;li&gt;
&lt;li&gt;3DES&lt;&#x2F;li&gt;
&lt;li&gt;RC4&lt;&#x2F;li&gt;
&lt;li&gt;Blowfish&lt;&#x2F;li&gt;
&lt;li&gt;…&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;在介绍完对称加密后, 我们来了解一下非对称加密. 在此之前, 我们先了解一下非对称密码学(公钥密码学)的基本概念.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;gong-yao-mi-ma-xue&quot;&gt;公钥密码学&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;公钥密码系统的密钥始终以公钥&#x2F;私钥对(&lt;strong&gt;密钥对&lt;&#x2F;strong&gt;, Key Pair)的形式出现, 公钥密码系统提供数学框架和算法来生成密钥对. 公钥通常与所有人共享, 而私钥则保密. 公钥密码系统在设计时就确保了在预期的算力下, 几乎不可能从其公开的公钥逆向演算出对应的私钥.&lt;&#x2F;li&gt;
&lt;li&gt;公钥密码系统主要有三大用途: &lt;strong&gt;加密与解密&lt;&#x2F;strong&gt;、&lt;strong&gt;签名与验证&lt;&#x2F;strong&gt;、&lt;strong&gt;密钥交换&lt;&#x2F;strong&gt;. 每种算法都需要使用到公钥和私钥, 比如由公钥加密的消息只能由私钥解密, 由私钥签名的消息需要用公钥验证. 由于加密解密、签名验证均需要两个不同的密钥, 故公钥密码学也被称为非对称密码学.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;比较著名的公钥密码系统有: RSA、ECC、(EC)DH. 不同的公钥密码系统可以提供以下一项或多项功能:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;执行密钥对生成: 随机生成私钥和对应的公钥;&lt;&#x2F;li&gt;
&lt;li&gt;执行加解密: 通过公钥加密, 通过私钥解密;&lt;&#x2F;li&gt;
&lt;li&gt;作为密钥交换算法;&lt;&#x2F;li&gt;
&lt;li&gt;执行数字签名 (消息认证): 通过私钥对消息进行签名, 通过公钥验证签名.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;公钥密码系统的密钥交换功能, 我们已经在前面的文章讲述过, 在此不再赘述; 公钥密码系统的数字签名功能, 我们会在后文单独介绍.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;fei-dui-cheng-jia-mi&quot;&gt;非对称加密&lt;&#x2F;h3&gt;
&lt;p&gt;应用公钥密码系统的加(解)密功能即称非对称加(解)密. 非对称加密安全性相对于对称加密高, 但缺点也明显:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;算法更为复杂, 加解密速度比对称加密慢非常多.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;只能加密&#x2F;解密很短的消息.&lt;&#x2F;p&gt;
&lt;p&gt;如在 RSA 系统中, 输入消息需要被转换为大整数, 例如使用 OAEP 填充, 然后才能被加密为密文. (密文实质上就是另一个大整数.)&lt;&#x2F;p&gt;
&lt;p&gt;一些非对称密码系统, 如 ECC, 不直接提供加密能力, 需要结合使用更复杂的方案才能实现加解密.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;为此, 现代密码学协议一般&lt;strong&gt;混合使用对称加密和非对称加密&lt;&#x2F;strong&gt; 以发挥各自的优势, 如使用非对称加密方案来安全地生成、交换对称加密所需的共享密钥, 然后使用对称加密方案来加密实际的消息内容.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;KEM: 仅使用非对称加密算法加密另一个密钥, 实际数据的加解密由该密钥完成. 前面介绍 TLS 1.3 后量子密码学改进时提到过 ML-KEM, 这就是一个典型的 KEM.&lt;&#x2F;p&gt;
&lt;p&gt;RSA-OAEP, RSA-KEM, ECIES-KEM 和 PSEC-KEM. 都是 KEM 加密方案.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;IKS: 集成加密方案, 在 KEM 技术上添加 KDF 等其他密码学算法达成更高安全性, 此处不展开.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;rsa-gong-yao-mi-ma-xi-tong&quot;&gt;RSA 公钥密码系统&lt;&#x2F;h3&gt;
&lt;p&gt;RSA 密码系统是最早的公钥密码系统之一, 它基于模幂的数学和 RSA 问题的计算难度以及密切相关的整数分解问题 (IFP). RSA 算法以其作者的首字母命名, 并在计算机密码学的早期广泛使用.&lt;&#x2F;p&gt;
&lt;p&gt;RSA 密码系统是典型的公钥密码系统, 完整提供了密钥对生成、加解密、密钥交换和数字签名等功能.&lt;&#x2F;p&gt;
&lt;p&gt;RSA 私钥长度可以是 1024, 2048, 3072 或 4096 位及更长, 但 3072 位是目前的推荐最小长度, 过长的密钥也会导致加解密速度过慢.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;shi-li&quot;&gt;示例&lt;&#x2F;h4&gt;
&lt;p&gt;2048 位 RSA 公钥示例 (表示为 2048 位十六进制整数模数 n 和 24 位公指数 e):&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;n = 0xa709e2f84ac0e21eb0caa018cf7f697f774e96f8115fc2359e9cf60b1dd8d4048d974cdf8422bef6be3c162b04b916f7ea2133f0e3e4e0eee164859bd9c1e0ef0357c142f4f633b4add4aab86c8f8895cd33fbf4e024d9a3ad6be6267570b4a72d2c34354e0139e74ada665a16a2611490debb8e131a6cffc7ef25e74240803dd71a4fcd953c988111b0aa9bbc4c57024fc5e8c4462ad9049c7f1abed859c63455fa6d58b5cc34a3d3206ff74b9e96c336dbacf0cdd18ed0c66796ce00ab07f36b24cbe3342523fd8215a8e77f89e86a08db911f237459388dee642dae7cb2644a03e71ed5c6fa5077cf4090fafa556048b536b879a88f628698f0c7b420c4b7
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;e = 0x010001
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;以 RSA PKCS#8 PEM ASN.1 格式编码:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----BEGIN PUBLIC KEY-----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApwni+ErA4h6wyqAYz39p
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;f3dOlvgRX8I1npz2Cx3Y1ASNl0zfhCK+9r48FisEuRb36iEz8OPk4O7hZIWb2cHg
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;7wNXwUL09jO0rdSquGyPiJXNM&#x2F;v04CTZo61r5iZ1cLSnLSw0NU4BOedK2mZaFqJh
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;FJDeu44TGmz&#x2F;x+8l50JAgD3XGk&#x2F;NlTyYgRGwqpu8TFcCT8XoxEYq2QScfxq+2FnG
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;NFX6bVi1zDSj0yBv90uelsM226zwzdGO0MZnls4AqwfzayTL4zQlI&#x2F;2CFajnf4no
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;agjbkR8jdFk4je5kLa58smRKA+ce1cb6UHfPQJD6+lVgSLU2uHmoj2KGmPDHtCDE
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;twIDAQAB
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----END PUBLIC KEY-----
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;2048 位 RSA 私钥示例, 对应于上述给定的公钥 (表示为十六进制 2048 位整数模数 n 和 2048 位秘密指数 d):&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;n = 0xa709e2f84ac0e21eb0caa018cf7f697f774e96f8115fc2359e9cf60b1dd8d4048d974cdf8422bef6be3c162b04b916f7ea2133f0e3e4e0eee164859bd9c1e0ef0357c142f4f633b4add4aab86c8f8895cd33fbf4e024d9a3ad6be6267570b4a72d2c34354e0139e74ada665a16a2611490debb8e131a6cffc7ef25e74240803dd71a4fcd953c988111b0aa9bbc4c57024fc5e8c4462ad9049c7f1abed859c63455fa6d58b5cc34a3d3206ff74b9e96c336dbacf0cdd18ed0c66796ce00ab07f36b24cbe3342523fd8215a8e77f89e86a08db911f237459388dee642dae7cb2644a03e71ed5c6fa5077cf4090fafa556048b536b879a88f628698f0c7b420c4b7
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;d = 0x10f22727e552e2c86ba06d7ed6de28326eef76d0128327cd64c5566368fdc1a9f740ad8dd221419a5550fc8c14b33fa9f058b9fa4044775aaf5c66a999a7da4d4fdb8141c25ee5294ea6a54331d045f25c9a5f7f47960acbae20fa27ab5669c80eaf235a1d0b1c22b8d750a191c0f0c9b3561aaa4934847101343920d84f24334d3af05fede0e355911c7db8b8de3bf435907c855c3d7eeede4f148df830b43dd360b43692239ac10e566f138fb4b30fb1af0603cfcf0cd8adf4349a0d0b93bf89804e7c2e24ca7615e51af66dccfdb71a1204e2107abbee4259f2cac917fafe3b029baf13c4dde7923c47ee3fec248390203a384b9eb773c154540c5196bce1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;以传统的 RSA PKCS#1 PEM ASN.1 格式编码, 看起来更长一些:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----BEGIN RSA PRIVATE KEY-----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;MIIEowIBAAKCAQEApwni+ErA4h6wyqAYz39pf3dOlvgRX8I1npz2Cx3Y1ASNl0zf
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;hCK+9r48FisEuRb36iEz8OPk4O7hZIWb2cHg7wNXwUL09jO0rdSquGyPiJXNM&#x2F;v0
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;4CTZo61r5iZ1cLSnLSw0NU4BOedK2mZaFqJhFJDeu44TGmz&#x2F;x+8l50JAgD3XGk&#x2F;N
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;lTyYgRGwqpu8TFcCT8XoxEYq2QScfxq+2FnGNFX6bVi1zDSj0yBv90uelsM226zw
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;zdGO0MZnls4AqwfzayTL4zQlI&#x2F;2CFajnf4noagjbkR8jdFk4je5kLa58smRKA+ce
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;1cb6UHfPQJD6+lVgSLU2uHmoj2KGmPDHtCDEtwIDAQABAoIBABDyJyflUuLIa6Bt
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ftbeKDJu73bQEoMnzWTFVmNo&#x2F;cGp90CtjdIhQZpVUPyMFLM&#x2F;qfBYufpARHdar1xm
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;qZmn2k1P24FBwl7lKU6mpUMx0EXyXJpff0eWCsuuIPonq1ZpyA6vI1odCxwiuNdQ
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;oZHA8MmzVhqqSTSEcQE0OSDYTyQzTTrwX+3g41WRHH24uN479DWQfIVcPX7u3k8U
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;jfgwtD3TYLQ2kiOawQ5WbxOPtLMPsa8GA8&#x2F;PDNit9DSaDQuTv4mATnwuJMp2FeUa
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;9m3M&#x2F;bcaEgTiEHq77kJZ8srJF&#x2F;r+OwKbrxPE3eeSPEfuP+wkg5AgOjhLnrdzwVRU
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;DFGWvOECgYEAyIk7F0S0AGn2aryhw9CihDfimigCxEmtIO5q7mnItCfeQwYPsX72
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;1fLpJNgfPc9DDfhAZ2hLSsBlAPLUOa0Cuny9PCBWVuxi1WjLVaeZCV2bF11mAgW2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;fjLkAXT34IX+HZl60VoetSWq9ibfkJHeCAPnh&#x2F;yjdB3Vs+2wxNkU8m8CgYEA1Tzm
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mjJq7M6f+zMo7DpRwFazGMmrLKFmHiGBY6sEg7EmoeH2CkAQePIGQw&#x2F;Rk16gWJR6
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;DtUZ9666sjCH6&#x2F;79rx2xg+9AB76XTFFzIxOk9cm49cIosDMk4mogSfK0Zg8nVbyW
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;5nEb&#x2F;&#x2F;9JCrZ18g4lD3IrT5VJoF4MhfdBUjAS1jkCgYB+RDIpv3+bNx0KLgWpFwgN
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Omb667B6SW2ya4x227KdBPFkwD9HYosnQZDdOxvIvmUZObPLqJan1aaDR2Krgi1S
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;oNJCNpZGmwbMGvTU1Pd+Nys9NfjR0ykKIx7&#x2F;b9fXzman2ojDovvs0W&#x2F;pF6bzD3V&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;FH5HWKLOrS5u4X3JJGqVDwKBgQCd953FwW&#x2F;gujld+EpqpdGGMTRAOrXqPC7QR3X5
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Beo0PPonlqOUeF07m9&#x2F;zsjZJfCJBPM0nS8sO54w7ESTAOYhpQBAPcx&#x2F;2HMUsrnIj
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;HBxqUOQKe6l0zo6WhJQi8&#x2F;+cU8GKDEmlsUlS3iWYIA9EICJoTOW08R04BjQ00jS7
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;1A1AUQKBgHlHrV&#x2F;6S&#x2F;4hjvMp+30hX5DpZviUDiwcGOGasmIYXAgwXepJUq0xN6aa
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;lnT+ykLGSMMY&#x2F;LABQiNZALZQtwK35KTshnThK6zB4e9p8JUCVrFpssJ2NCrMY3SU
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;qw87K1W6engeDrmunkJ&#x2F;PmvSDLYeGiYWmEKQbLQchTxx1IEddXkK
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----END RSA PRIVATE KEY-----
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;rsa-mi-yao-sheng-cheng&quot;&gt;RSA 密钥生成&lt;&#x2F;h4&gt;
&lt;p&gt;略, 相关应用参见加密库的文档.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;rsa-jia-jie-mi&quot;&gt;RSA 加解密&lt;&#x2F;h4&gt;
&lt;p&gt;RSA 一次只能加密&#x2F;解密一个(大)整数, 一般采用 OAEP 对消息编码为一个个整数再逐个加解密.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;rsa-qian-ming-yu-yan-zheng&quot;&gt;RSA 签名与验证&lt;&#x2F;h4&gt;
&lt;p&gt;参见后文介绍数字签名算法.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ecc-gong-yao-mi-ma-xi-tong&quot;&gt;ECC 公钥密码系统&lt;&#x2F;h3&gt;
&lt;p&gt;ECC 椭圆曲线密码学于 1985 年被首次提出, 并于 2004 年开始被广泛应用. ECC 被认为是 RSA 的继任者, 新一代的非对称加密算法. 其最大的特点在于相同密码强度下, ECC 的密钥和签名的大小都要显著低于 RSA. 256 位的 ECC 密钥, 安全性与 3072 位的 RSA 密钥安全性相当. ECC 的密钥对生成、密钥交换与签名算法的速度都要比 RSA 快.&lt;&#x2F;p&gt;
&lt;p&gt;ECC 中的椭圆曲线可以以多种形式呈现, 这些形式被证明是&lt;strong&gt;同构&lt;&#x2F;strong&gt;的:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;魏尔施特拉斯 (Weierstrass) 形式: 这是最常见的椭圆曲线形式, 其方程为 $y^2=x^3+ax+b$&lt;&#x2F;p&gt;
&lt;p&gt;如: $y^2=x^3+7$ (secp256k1, 加密货币领域常用).&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;需要指出, NSA 推荐的 secp256r1 (NIST P-256, prime256v1, nist256p1) 和 secp256k1 名称只有一字之差, k 和 r 的不同. 其中 k 表示 Koblitz (ECC 发明人), 而 r 表示随机, 即参数是随机选取的, 但美国国家安全局 NSA 并没有公布随机数的挑选规则, 有质疑称 NSA 可能对随机数动过手脚, 让破解难度大幅降低.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;蒙哥马利 (Montgomery) 形式: 其方程为 $By^2=x^3+Ax^2+x$&lt;&#x2F;p&gt;
&lt;p&gt;如 Curve25519: $y^2 = x^3+486662x^2+x$.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;爱德华兹 (Edwards) 形式: 其方程为 $x^2+y^2=1+dx^2y^2$&lt;&#x2F;p&gt;
&lt;p&gt;如 Ed448: $x^2+y^2=1-39081x^2y^2$. (也可以写成蒙哥马利形式, 称 Curve448).&lt;&#x2F;p&gt;
&lt;p&gt;一般而言, Edwards 形式性能更好, 如 Ed25519 是基于 Curve25519 同构地 “扭曲” 而来, 专为计算速度优化而设计的.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;我们推荐使用 Curve52219 &#x2F; Ed25519 以及 Curve448 &#x2F; Ed448, 其性能和安全性均优于 NSA 推荐的 NIST P-256 (secp256r1), NIST P-384 (secp384r1), NIST P-521 (secp521r1) 等曲线. 参见 &lt;a href=&quot;https:&#x2F;&#x2F;safecurves.cr.yp.to&quot;&gt;https:&#x2F;&#x2F;safecurves.cr.yp.to&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;轶事一则&lt;&#x2F;p&gt;
&lt;p&gt;参考: &lt;a href=&quot;https:&#x2F;&#x2F;www.cnblogs.com&#x2F;greencollar&#x2F;p&#x2F;14363535.html&quot;&gt;https:&#x2F;&#x2F;www.cnblogs.com&#x2F;greencollar&#x2F;p&#x2F;14363535.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Daniel J. Bernstein 是世界著名的密码学家, 他在大学曾经开设过一门 UNIX 系统安全的课程给学生, 结果一学期下来, 发现了 UNIX 程序中的 91 个安全漏洞; 他早年在美国依然禁止出口加密算法时, 曾因为把自己设计的加密算法发布到网上遭到了美国政府的起诉, 他本人抗争六年, 最后美国政府撤销所有指控, 目前另一个非常火的高性能安全流密码 ChaCha20 也是出自 Bernstein 之手.&lt;&#x2F;p&gt;
&lt;p&gt;Curve25519 自 2006 年发表以来, 除了学术界无人问津. 但自 2013 年斯诺登曝光棱镜计划后, 该算法突然大火. Curve25519 安全性高, 不同于 NIST 推荐的 P-256 等曲线, Curve25519 的参数是公开透明的, 任何人都可以验证其安全性, 而 NSA 推荐的 NIST P-256 等曲线方程的系数使用了来历不明的随机种子, 在密码学上难以验证其安全性; 此外, Curve25519 的设计也充分考虑了缓存攻击等, 尽可能避免分支跳转, 在实践上安全性也非常高.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;shu-zi-qian-ming-suan-fa-digital-signature-algorithm-dsa&quot;&gt;数字签名算法 (digital signature algorithm, DSA)&lt;&#x2F;h2&gt;
&lt;p&gt;在密码学中, 数字签名为数字文档提供消息身份验证、完整性和不可否认性. 数字签名基于公钥密码系统, 消息签名由私有密钥执行, 消息验证由相应的公钥执行.&lt;&#x2F;p&gt;
&lt;p&gt;数字签名的过程本质还是加解密, 但是加解密的对象变成了消息的哈希值: 使用私钥签名 (加密哈希值), 公钥验证 (解密后比对实际的哈希值).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;rsa-shu-zi-qian-ming-suan-fa&quot;&gt;RSA 数字签名算法&lt;&#x2F;h3&gt;
&lt;p&gt;即使用 RSA 公钥密码系统的数字签名算法.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;刚刚好, 哈希值就是一个大整数.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;ecc-shu-zi-qian-ming-suan-fa&quot;&gt;ECC 数字签名算法&lt;&#x2F;h3&gt;
&lt;p&gt;即使用 ECC 公钥密码系统的数字签名算法. ECC 相对于 RSA, 在相同的安全强度下, 使用更短的密钥长度, 因此在计算和存储方面更为高效.&lt;&#x2F;p&gt;
&lt;p&gt;常用的 ECC 数字签名算法包括:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;ECDSA: 在经典 Weierstrass 形式的有限域上使用加密椭圆曲线.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;出于特定实体影响, 目前的 ECC 证书一般使用 ECDSA 数字签名算法.&lt;&#x2F;p&gt;
&lt;p&gt;需要指出, DSA 是 digital signature algorithm (数字签名算法) 的缩写, 但也可能特指 FIPS 186 Digital Signature Standard (DSS) 中定义的数字签名算法. 一般地, ECDSA 特指使用了 NIST P-256, NIST P-384 或 NIST P-521 曲线的 NIST DSA 的椭圆曲线实现.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;EdDSA: 在 Edwards 形式的有限域上使用加密椭圆曲线.&lt;&#x2F;p&gt;
&lt;p&gt;常用变体包括 Ed25519 (使用 Ed25519 曲线, SHA512 哈希算法) 或 Ed448 (使用 Ed448 曲线, SHAKE256 哈希算法).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;我们推荐使用 EdDSA 作为数字签名算法, 原因前面已经提到过.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;shu-zi-zheng-shu&quot;&gt;数字证书&lt;&#x2F;h2&gt;
&lt;p&gt;(本节内容大部分摘录自 &lt;a href=&quot;https:&#x2F;&#x2F;thiscute.world&#x2F;posts&#x2F;about-tls-cert&quot;&gt;https:&#x2F;&#x2F;thiscute.world&#x2F;posts&#x2F;about-tls-cert&lt;&#x2F;a&gt;) 的总结, 向原作者表示感谢!)&lt;&#x2F;p&gt;
&lt;p&gt;我们已经熟悉了对称密码与非对称密码两个密码学体系:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;对称密码算法: 计算速度快、安全强度高, 但是缺乏安全保存、管理乃至交换密钥的手段 (PSK 一旦泄露, 则所有使用该密钥加密的通信均不再安全).&lt;&#x2F;li&gt;
&lt;li&gt;非对称密码算法: 计算速度慢, 但是它给出了安全的密钥交换算法 DHE&#x2F;ECDHE, 且公钥是可公开的, 这降低了密钥的保存与管理难度.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;但是问题来了:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;公钥该如何分发? 比如 Alice 跟 Bob 交换公钥时, 如何确定收到的确实是对方的公钥, 也就是说如何确认公钥的真实性、完整性、认证其来源身份? (DH 是匿名的无认证的, 无法防止中间人攻击)&lt;&#x2F;li&gt;
&lt;li&gt;如果 Alice 的私钥泄漏了, 她该如何作废自己旧的公钥?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;数字证书与公钥基础架构就是为了解决上述问题而设计的.&lt;&#x2F;p&gt;
&lt;p&gt;首先简单介绍下 PKI (Public Key Infrastructure, 公钥基础架构), 它是一组由硬件、软件、参与者、管理政策与流程组成的基础架构, 其目的在于创造、管理、分配、使用、存储以及撤销数字证书. PKI 是一个总称, 而并非指单独的某一个规范或标准, 因此显然数字证书的规范 (X.509)、存储格式等都是 PKI 的一部分.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;gong-yao-zheng-shu&quot;&gt;公钥证书&lt;&#x2F;h3&gt;
&lt;p&gt;前面我们介绍了公钥密码系统存在的一个问题是 “在分发公钥时, 难以确认公钥的真实性、完整性及其来源身份”. PKI 通过数字证书和证书认证机构来解决这个问题.&lt;&#x2F;p&gt;
&lt;p&gt;数字证书指的其实就是公钥证书 (也可直接简称为证书). 在现代网络通讯中通行的公钥证书格式标准名为 X.509 v3, 由 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc5280&quot;&gt;RFC5280&lt;&#x2F;a&gt; 定义, 被广泛应用在 TLS 等众多加密通讯协议中.&lt;&#x2F;p&gt;
&lt;p&gt;一个公钥证书内容应当包括:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;证书&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;序列号 (Serial Number): 用以识别每一张证书, 在作废证书的时候会用到它.&lt;&#x2F;li&gt;
&lt;li&gt;版本: 证书的规范版本.&lt;&#x2F;li&gt;
&lt;li&gt;公钥 (Public Key): 证书所包含的公钥.&lt;&#x2F;li&gt;
&lt;li&gt;公钥指纹: 即公钥的 Hash 值, 当前大部分证书都使用 SHA256 计算此指纹.&lt;&#x2F;li&gt;
&lt;li&gt;公钥用途 (Key Usage + Extended Key Usage): 记录了此证书可用于哪些用途, 如数字签名、身份认证等.&lt;&#x2F;li&gt;
&lt;li&gt;主体 (Subject): 即姓名、组织、邮箱、地址等证书拥有者的个人信息.&lt;&#x2F;li&gt;
&lt;li&gt;证书有效期的开始时间、结束时间 (Not Before + Not After): 为了确保安全性, 每个证书都会记录一个自身的有效期.&lt;&#x2F;li&gt;
&lt;li&gt;签发者 (Issuer): 签发此证书的实体.&lt;&#x2F;li&gt;
&lt;li&gt;其他拓展信息.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;数字签名 (Signature): 对整个证书计算数字签名, 来确保这些数据的真实性、完整性, 确保证书未被恶意篡改&#x2F;伪造.&lt;&#x2F;p&gt;
&lt;p&gt;此数字签名由证书签发者使用其私钥+证书内容计算得出.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;数字签名算法 (Signature Algorithm): 证书所使用的签名算法, 常用的有 RSA-SHA-256 与 ECDSA-SHA-256.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;每个证书都有唯一的 ID, 这样在私钥泄漏的情况下, 我们可以通过公钥基础设施的 OCSP (Online Certificate Status Protocol) 协议吊销某个证书. 吊销证书的操作还是比较罕见的, 毕竟私钥泄漏并不容易遇到, 因此这里就略过不提了, 有需要的可以自行搜索.&lt;&#x2F;p&gt;
&lt;p&gt;感兴趣的, 可以使用浏览器查看证书详情的功能查看一下自己常用网站的证书, 了解一下证书的具体内容, 这里是旧版 Firefox 查看谷歌网站的示例:&lt;&#x2F;p&gt;
&lt;div align=&quot;center&quot;&gt;
  &lt;img src=&quot;.&#x2F;google-cert-content.webp&quot; alt=&quot;Google&#x27;s Cert&quot; style=&quot;max-width: 50%;&quot;&gt;
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;zheng-shu-qian-fa-ji-gou-ca-yu-zheng-shu-lian&quot;&gt;证书签发机构 (CA) 与证书链&lt;&#x2F;h3&gt;
&lt;p&gt;前面介绍证书内容时, 提到了签发者会使用签发者私钥和证书内容生成数字签名, 显然需要使用签发者公钥来验证被签发证书中的签名. 但是问题又来了, 签发者的公钥该如何分发? 这不又回到了最初的问题吗?&lt;&#x2F;p&gt;
&lt;p&gt;为此, PKI 引入了一个可信第三方 (Trusted third party, TTP) 来解决这个问题.&lt;&#x2F;p&gt;
&lt;p&gt;在 Alice 与 Bob 的案例中, 就是说还有个可信第三方 Eve, 他使用自己的私钥为自己的公钥证书签了名, 生成了一个&lt;em&gt;自签名&lt;&#x2F;em&gt;证书, 并且已经提前将这个自签名证书分发(比如当面交付、预置在操作系统中等手段)给了 Alice 跟 Bob.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;现在 Alice 首先使用自己的公钥以及个人信息制作了自己的公钥证书, 但是这个证书还缺乏一个 Issuer 以及数字签名.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Alice 找到 Eve, 将这个 CSR 文件提交给 Eve, 希望 Eve 为自己的证书签名. 此时, 我们称之为提交&lt;strong&gt;CSR&lt;&#x2F;strong&gt; (Certificate Signing Request, CSR)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Eve 验证了 Alice 的身份后, 再使用这个 CSR 签发出完整的证书文件 (Issuer 就填 Eve, 然后 Eve 使用自己的私钥计算出证书的数字签名, 这样就得到了最终的证书), 交付给 Alice.&lt;&#x2F;p&gt;
&lt;p&gt;Eve 曾经 “跨越千里之遥”, 将自己的公钥证书分发给了 Bob, 所以在给 Alice 签发证书时, 他显然可能会要求 Alice 给付&lt;em&gt;签名费&lt;&#x2F;em&gt;. 目前许多证书机构就是靠这个赚钱的, 当然也有非盈利的证书颁发机构, 如 ZeroSSL 等 (真的是做慈善么).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;现在 Alice 再将经 Eve 签名的证书发送给 Bob&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Bob 收到证书后, 看到 Issuer 是 Eve, 于是找出以前 Eve 给他的&lt;em&gt;自签名&lt;&#x2F;em&gt;证书, 然后使用其中的公钥验证收到的证书.&lt;&#x2F;p&gt;
&lt;p&gt;如果验证成功, 就说明证书的内容是经过 Eve 认证的. 如果 Eve 没老糊涂了, 那这个证书应该确实就是 Alice 的. 否则, 这是某个攻击者伪造的证书.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;在现实世界中, Eve 这个角色被称作 CA (Certification Authority, 证书认证机构), 全世界只有几十家这样的权威机构, 它们&lt;em&gt;都通过了各大软件厂商的严格审核&lt;&#x2F;em&gt;, 从而将根证书(CA 证书)直接内置于主流操作系统与浏览器中, 也就是说早就提前分发给了因特网世界的几乎所有用户. 由于许多操作系统或软件的更新迭代缓慢, 根证书的有效期通常都在十年以上.&lt;&#x2F;p&gt;
&lt;p&gt;但是, 如果 CA 机构直接使用自己的私钥处理各种证书签名请求, 这将是非常危险的. 因为全世界有海量的 HTTPS 网站, 也就是说有海量的证书需求, 可一共才几十家 CA 机构. 频繁的动用私钥会产生私钥泄漏的风险, 如果这个私钥泄漏了, 那将直接影响海量网站的安全性.&lt;&#x2F;p&gt;
&lt;p&gt;PKI 架构使用数字证书链的机制来解决这个问题:&lt;&#x2F;p&gt;
&lt;div align=&quot;center&quot;&gt;
  &lt;img src=&quot;.&#x2F;chain-of-trust.webp&quot; alt=&quot;Chain of trust&quot; style=&quot;max-width: 50%;&quot;&gt;
&lt;&#x2F;div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;CA 机构首先生成自己的根证书与私钥, 并使用私钥给根证书签名&lt;&#x2F;p&gt;
&lt;p&gt;因为私钥跟证书本身就是一对, 因此根证书也被称作自签名证书.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;CA 交付根证书给各大软硬件厂商, 内置在主流的操作系统与浏览器中.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;CA 使用私钥签发一些所谓的中间证书, 之后就把私钥雪藏了, 非必要不会再拿出来使用.&lt;&#x2F;p&gt;
&lt;p&gt;根证书的私钥通常离线存储在安全地点; 中间证书的有效期通常会比根证书短一些; 部分中间证书会被作为备份使用, 平常不会启用.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;CA 机构使用这些中间证书的私钥, 为用户提交的所有 CSR 请求签名.&lt;&#x2F;li&gt;
&lt;li&gt;CA 机构也可以使用中间证书的私钥, 为子一级 CA 机构签发中间证书, 形成更长的证书链.&lt;&#x2F;li&gt;
&lt;li&gt;不同 CA 机构也可能执行交叉签名, 共同为对方的中间证书签名. 客户端只要安装有其中任何一个根证书, 就能验证该中间证书.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;上述这个全球互联网上, 由证书认证机构、操作系统与浏览器内置的根证书、TLS 加密认证协议、OCSP 证书吊销协议等等组成的架构, 我们可以称它为 &lt;strong&gt;Web PKI&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Web PKI 通常是&lt;em&gt;可信&lt;&#x2F;em&gt;的, 但是并不意味着它们&lt;em&gt;可靠&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;可以说, 谁&lt;em&gt;掌握&lt;&#x2F;em&gt;了 CA, 谁就能对如今互联网安全所仰赖的 TLS 通信执行 MitM.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;在更高安全性要求的场景中, 搭建私有 PKI 架构是有必要的, 如支付场景下银行 APP 等要求安装特定数字证书, 即安装了一个由支付机构控制的私有 CA 证书, 或者以 U 盾形式存在的硬件介质的证书; 又或者内部通讯系统, 也会使用私有 CA 证书来签发内部服务器的证书. 这种情况下, 私有 CA 证书需要被提前手动安装在客户端设备上, 否则会提示不受信任的证书错误.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tls-zheng-shu-zhu-ti-subject&quot;&gt;TLS 证书主体 (Subject)&lt;&#x2F;h3&gt;
&lt;p&gt;TLS 证书的主体字段包含了证书持有者的身份信息, 我们主要关注其中的通用名称 (Common Name, CN) 和主体备用名称 (Subject Alternative Name, SAN).&lt;&#x2F;p&gt;
&lt;p&gt;CN 是证书的 “主域名”, SAN 则是该证书所覆盖的所有域名或 IP 地址. 由于 CN 字段只能有一个, 无法满足单证书保护多个子域的需求, 实际上已被弃用, 我们通过 SAN 字段来指定证书所覆盖的域名&#x2F;IP 地址.&lt;&#x2F;p&gt;
&lt;p&gt;一般地, 我们使用的证书均为域名证书, 但也有 IP 证书 (只能是公网 IP, 难以自动化申请, 而且收费一般不便宜, 目前应该只有 ZeroSSL 提供了&lt;em&gt;免费&lt;&#x2F;em&gt;的 IP 证书), 如著名的 &lt;code&gt;https:&#x2F;&#x2F;1.1.1.1&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;SAN 支持配置泛域名, 即 &lt;code&gt;*.example.com&lt;&#x2F;code&gt; 的形式, 但不支持多级泛域名, 即 &lt;code&gt;*.*.example.com&lt;&#x2F;code&gt; 的形式; &lt;code&gt;*.example.com&lt;&#x2F;code&gt; 只能匹配到同级子域名 &lt;code&gt;a.example.com&lt;&#x2F;code&gt;, 不能匹配 &lt;code&gt;a.b.example.com&lt;&#x2F;code&gt; 等.&lt;&#x2F;p&gt;
&lt;p&gt;SAN 可以设置很多个, 如:&lt;&#x2F;p&gt;
&lt;div align=&quot;center&quot;&gt;
  &lt;img src=&quot;.&#x2F;1.1.1.1-cert.webp&quot; alt=&quot;1.1.1.1 Cert&quot; style=&quot;max-width: 50%;&quot;&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;bu-chong-nei-rong-zheng-shu-yi-ji-gong-si-yao-de-wen-ben-bian-ma&quot;&gt;补充内容: 证书以及公私钥的(文本)编码&lt;&#x2F;h2&gt;
&lt;p&gt;由于历史原因, 实践上对证书以及公私钥的存储格式可谓五花八门, 这里参考了 RFC 7468 以及 &lt;a href=&quot;https:&#x2F;&#x2F;thiscute.world&#x2F;posts&#x2F;about-tls-cert&#x2F;#pki&quot;&gt;https:&#x2F;&#x2F;thiscute.world&#x2F;posts&#x2F;about-tls-cert&#x2F;#pki&lt;&#x2F;a&gt;, 试图做一个实用意义上比较全面的总结.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ji-ben-gai-nian&quot;&gt;基本概念&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;X.509: PKI 标准, 规定了证书应该包含哪些信息 (但是未定义证书该如何存储). PKIX 即 “Public Key Infrastructure X.509”.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ASN.1 (Abstract Syntax Notation One, 抽象语法标记法第 1 部分): 一种用于描述数据结构的标准, 广泛应用于通信协议和加密标准中. ASN.1 定义了数据的语法和语义, 使得不同系统之间能够理解和交换数据. 被应用于 X.509 证书、PKCS 标准等.&lt;&#x2F;p&gt;
&lt;p&gt;感兴趣的, 可以参考 &lt;a href=&quot;https:&#x2F;&#x2F;letsencrypt.org&#x2F;zh-cn&#x2F;docs&#x2F;a-warm-welcome-to-asn1-and-der&#x2F;&quot;&gt;https:&#x2F;&#x2F;letsencrypt.org&#x2F;zh-cn&#x2F;docs&#x2F;a-warm-welcome-to-asn1-and-der&#x2F;&lt;&#x2F;a&gt; 的总结.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;DER (Distinguished Encoding Rules, 可辨别编码规则): ASN.1 的一种序列化规则, 用于将 ASN.1 数据结构编码为二进制格式. 定义于 X.690 标准中.&lt;&#x2F;p&gt;
&lt;p&gt;DER 编码的证书&lt;em&gt;通常&lt;&#x2F;em&gt;使用 &lt;code&gt;.cer&lt;&#x2F;code&gt; 或 &lt;code&gt;.der&lt;&#x2F;code&gt; 作为文件扩展名, 但也有使用 &lt;code&gt;.crt&lt;&#x2F;code&gt; 的 (RFC 7468 要求使用此拓展名保存文本格式), 更有使用 &lt;code&gt;.cer&lt;&#x2F;code&gt; 保存 PEM 格式的证书的. 在实践上, 尝试以纯文本形式打开看看就知道了.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;PEM (Privacy-Enhanced Mail, 隐私增强邮件): “隐私增强邮件” 自身已鲜少使用, 但其定义的基于文本的编码格式, 如今被广泛应用于证书(链)和公私钥的文本编码中. PEM 格式可以理解为对 DER 编码的证书或密钥进行 Base64 编码并添加封装边界.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;PKCS (Public Key Cryptography Standards, 公钥密码学标准).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;pem-ge-shi&quot;&gt;PEM 格式&lt;&#x2F;h3&gt;
&lt;p&gt;(以下来自 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc7468&quot;&gt;RFC7468&lt;&#x2F;a&gt;, 但是由于历史因素, 实践中 PEM 格式的使用也存在不完全符合 RFC 7468 的定义的情况)&lt;&#x2F;p&gt;
&lt;p&gt;文本编码以一行包含 “&lt;code&gt;-----BEGIN &lt;&#x2F;code&gt;”、标签和 “&lt;code&gt;-----&lt;&#x2F;code&gt;” 开始, 并以一行包含 “&lt;code&gt;-----END &lt;&#x2F;code&gt;”、标签和 “&lt;code&gt;-----&lt;&#x2F;code&gt;” 结束. 在这些行 (或称“封装边界“) 之间, 是根据 RFC4648 第 4 节进行 Base64 编码的数据 (PEM &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc1421&quot;&gt;RFC1421&lt;&#x2F;a&gt; 称这部分数据为 “封装文本部分”). 封装边界之前允许存在数据, 解析器在处理此类数据时&lt;strong&gt;绝不能&lt;&#x2F;strong&gt;出错. 此外, 解析器&lt;strong&gt;必须&lt;&#x2F;strong&gt;忽略空白字符及其他非 Base64 字符, 且&lt;strong&gt;必须&lt;&#x2F;strong&gt;支持不同的换行规范.&lt;&#x2F;p&gt;
&lt;p&gt;编码数据的类型由 “&lt;code&gt;-----BEGIN &lt;&#x2F;code&gt;” (前置封装边界) 行中的类型标签决定. 例如, “&lt;code&gt;-----BEGIN CERTIFICATE-----&lt;&#x2F;code&gt;” 表示内容是一个 PKIX 证书. 生成器&lt;strong&gt;必须&lt;&#x2F;strong&gt;在 “&lt;code&gt;-----END &lt;&#x2F;code&gt;” (后置封装边界) 行使用与对应 “&lt;code&gt;-----BEGIN &lt;&#x2F;code&gt;” 行相同的标签. 标签由区分大小写的、全大写的零个或多个字符组成; 不得包含连续空格或连字符, 首尾也不得出现空格或连字符. 若标签不匹配, 解析器&lt;strong&gt;可以&lt;&#x2F;strong&gt;选择忽略后置封装边界中的标签而非报错: 现存实现中部分要求标签匹配, 部分不作要求.&lt;&#x2F;p&gt;
&lt;p&gt;“BEGIN” 或 “END” 与标签之间必须严格用一个空格字符 (SP) 分隔. 封装边界两端的连字符 (即短横线 “-”) 必须正好五个, 不能多也不能少.&lt;&#x2F;p&gt;
&lt;p&gt;标签类型暗示编码数据遵循特定语法. 解析器&lt;strong&gt;必须&lt;&#x2F;strong&gt;能够优雅处理不符合规范的数据. 但需注意本文档发布前的解析器或生成器行为并不统一. 合法的解析器&lt;strong&gt;可能&lt;&#x2F;strong&gt;将内容解释为其他标签类型, 但应注意安全考量章节讨论的潜在风险. 本文档描述的标签标识的容器格式不与特定加密算法绑定, 这符合算法敏捷性原则. 这些格式采用 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc5280&quot;&gt;RFC5280&lt;&#x2F;a&gt; 第 4.1.1.2 节所述的 ASN.1 AlgorithmIdentifier 结构.&lt;&#x2F;p&gt;
&lt;p&gt;与传统 PEM 编码 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc1421&quot;&gt;RFC1421&lt;&#x2F;a&gt;、OpenPGP ASCII armor 及 OpenSSH 密钥文件格式不同, 文本编码&lt;em&gt;不&lt;&#x2F;em&gt;定义也不允许在数据旁编码头信息. 前置封装边界与 Base64 数据之间允许存在空白, 但生成器&lt;strong&gt;绝不能&lt;&#x2F;strong&gt;产生此类空白 (保留此空白区域是对 PEM “封装头部分” 定义的沿袭).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pkcs-1-biao-zhun&quot;&gt;PKCS #1 标准&lt;&#x2F;h3&gt;
&lt;p&gt;专用于编码 RSA 公私钥, PEM 标签为 “RSA PUBLIC KEY” 和 “RSA PRIVATE KEY”.&lt;&#x2F;p&gt;
&lt;p&gt;示例:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----BEGIN RSA PUBLIC KEY-----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;MIIBCgKCAQEApwni+ErA4h6wyqAYz39pf3dOlvgRX8I1npz2Cx3Y1ASNl0zfhCK+
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;9r48FisEuRb36iEz8OPk4O7hZIWb2cHg7wNXwUL09jO0rdSquGyPiJXNM&#x2F;v04CTZ
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;o61r5iZ1cLSnLSw0NU4BOedK2mZaFqJhFJDeu44TGmz&#x2F;x+8l50JAgD3XGk&#x2F;NlTyY
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;gRGwqpu8TFcCT8XoxEYq2QScfxq+2FnGNFX6bVi1zDSj0yBv90uelsM226zwzdGO
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;0MZnls4AqwfzayTL4zQlI&#x2F;2CFajnf4noagjbkR8jdFk4je5kLa58smRKA+ce1cb6
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;UHfPQJD6+lVgSLU2uHmoj2KGmPDHtCDEtwIDAQAB
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----END RSA PUBLIC KEY-----
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----BEGIN RSA PRIVATE KEY-----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;MIIEowIBAAKCAQEApwni+ErA4h6wyqAYz39pf3dOlvgRX8I1npz2Cx3Y1ASNl0zf
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;hCK+9r48FisEuRb36iEz8OPk4O7hZIWb2cHg7wNXwUL09jO0rdSquGyPiJXNM&#x2F;v0
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;4CTZo61r5iZ1cLSnLSw0NU4BOedK2mZaFqJhFJDeu44TGmz&#x2F;x+8l50JAgD3XGk&#x2F;N
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;lTyYgRGwqpu8TFcCT8XoxEYq2QScfxq+2FnGNFX6bVi1zDSj0yBv90uelsM226zw
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;zdGO0MZnls4AqwfzayTL4zQlI&#x2F;2CFajnf4noagjbkR8jdFk4je5kLa58smRKA+ce
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;1cb6UHfPQJD6+lVgSLU2uHmoj2KGmPDHtCDEtwIDAQABAoIBABDyJyflUuLIa6Bt
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ftbeKDJu73bQEoMnzWTFVmNo&#x2F;cGp90CtjdIhQZpVUPyMFLM&#x2F;qfBYufpARHdar1xm
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;qZmn2k1P24FBwl7lKU6mpUMx0EXyXJpff0eWCsuuIPonq1ZpyA6vI1odCxwiuNdQ
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;oZHA8MmzVhqqSTSEcQE0OSDYTyQzTTrwX+3g41WRHH24uN479DWQfIVcPX7u3k8U
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;jfgwtD3TYLQ2kiOawQ5WbxOPtLMPsa8GA8&#x2F;PDNit9DSaDQuTv4mATnwuJMp2FeUa
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;9m3M&#x2F;bcaEgTiEHq77kJZ8srJF&#x2F;r+OwKbrxPE3eeSPEfuP+wkg5AgOjhLnrdzwVRU
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;DFGWvOECgYEAyIk7F0S0AGn2aryhw9CihDfimigCxEmtIO5q7mnItCfeQwYPsX72
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;1fLpJNgfPc9DDfhAZ2hLSsBlAPLUOa0Cuny9PCBWVuxi1WjLVaeZCV2bF11mAgW2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;fjLkAXT34IX+HZl60VoetSWq9ibfkJHeCAPnh&#x2F;yjdB3Vs+2wxNkU8m8CgYEA1Tzm
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;mjJq7M6f+zMo7DpRwFazGMmrLKFmHiGBY6sEg7EmoeH2CkAQePIGQw&#x2F;Rk16gWJR6
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;DtUZ9666sjCH6&#x2F;79rx2xg+9AB76XTFFzIxOk9cm49cIosDMk4mogSfK0Zg8nVbyW
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;5nEb&#x2F;&#x2F;9JCrZ18g4lD3IrT5VJoF4MhfdBUjAS1jkCgYB+RDIpv3+bNx0KLgWpFwgN
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Omb667B6SW2ya4x227KdBPFkwD9HYosnQZDdOxvIvmUZObPLqJan1aaDR2Krgi1S
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;oNJCNpZGmwbMGvTU1Pd+Nys9NfjR0ykKIx7&#x2F;b9fXzman2ojDovvs0W&#x2F;pF6bzD3V&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;FH5HWKLOrS5u4X3JJGqVDwKBgQCd953FwW&#x2F;gujld+EpqpdGGMTRAOrXqPC7QR3X5
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Beo0PPonlqOUeF07m9&#x2F;zsjZJfCJBPM0nS8sO54w7ESTAOYhpQBAPcx&#x2F;2HMUsrnIj
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;HBxqUOQKe6l0zo6WhJQi8&#x2F;+cU8GKDEmlsUlS3iWYIA9EICJoTOW08R04BjQ00jS7
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;1A1AUQKBgHlHrV&#x2F;6S&#x2F;4hjvMp+30hX5DpZviUDiwcGOGasmIYXAgwXepJUq0xN6aa
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;lnT+ykLGSMMY&#x2F;LABQiNZALZQtwK35KTshnThK6zB4e9p8JUCVrFpssJ2NCrMY3SU
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;qw87K1W6engeDrmunkJ&#x2F;PmvSDLYeGiYWmEKQbLQchTxx1IEddXkK
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----END RSA PRIVATE KEY-----
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;如今已经统一转向使用 PKCS #8 格式保存私钥, 公钥则按 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc7468&quot;&gt;RFC7468&lt;&#x2F;a&gt; Section 13 所述的格式保存.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ansi-x9-62-itu-t-x-894-biao-zhun&quot;&gt;ANSI X9.62 (ITU-T X.894) 标准&lt;&#x2F;h3&gt;
&lt;p&gt;类似 PKCS #1 标准, 但此标准仅用于编码 ECC 私钥, PEM 标签为 “EC PRIVATE KEY”.&lt;&#x2F;p&gt;
&lt;p&gt;示例 (使用 &lt;code&gt;openssl ecparam -name secp384r1 -genkey -noout -out privkey.pem&lt;&#x2F;code&gt; 生成):&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----BEGIN EC PRIVATE KEY-----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;MIGkAgEBBDDhhKJcKC7jnRbKLYKAzY1f&#x2F;9aC9JGGuqqo2d4FejHSi&#x2F;TOZiLf3JhP
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;xAb+IJdQYEqgBwYFK4EEACKhZANiAARPyjgUZlw+IWfP&#x2F;+PD8m1HZRWbEvUB+ai9
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;pTV63SI7MWw5OzM3qKwTUNP+NK3xFt14A5lJwFMzl5AB7QhJYarW5ra3e2yhP8Vn
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;oC9E7Om31FLwVX+AHTM4Rg0ZQQoqH0c=
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----END EC PRIVATE KEY-----
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;类似地, 如今已经统一转向使用 PKCS #8 格式保存私钥.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pkcs-7-cms-biao-zhun&quot;&gt;PKCS #7 &#x2F; CMS 标准&lt;&#x2F;h3&gt;
&lt;blockquote&gt;
&lt;p&gt;PKCS #7 &#x2F; CMS, 是一个多用途的证书描述格式. 它包含一个数据填充规则, 这个填充规则常被用在需要数据填充的分组加密、数字签名等算法中.&lt;&#x2F;p&gt;
&lt;p&gt;由于历史原因, 有使用 PKCS #7 标准保存证书的, 后缀通常使用 &lt;code&gt;.p7b&lt;&#x2F;code&gt; 或者 &lt;code&gt;.p7c&lt;&#x2F;code&gt;, 可以使用 DER 或 PEM 格式保存:&lt;&#x2F;p&gt;
&lt;div align=&quot;center&quot;&gt;
 &lt;img src=&quot;.&#x2F;p7b.png&quot; alt=&quot;.p7b in real world&quot; style=&quot;max-width: 50%;&quot;&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;以下内容摘抄自 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc7468&quot;&gt;RFC7468&lt;&#x2F;a&gt; Section 8 和 Section 9.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;PKCS #7 加密消息语法结构使用 “PKCS7” 标签进行编码. 编码内容&lt;strong&gt;必须&lt;&#x2F;strong&gt;是 BER (强烈推荐 DER 格式) 编码的 ASN.1 ContentInfo 结构, 如 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc2315&quot;&gt;RFC2315&lt;&#x2F;a&gt; 所述.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----BEGIN PKCS7-----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;MIHjBgsqhkiG9w0BCRABF6CB0zCB0AIBADFho18CAQCgGwYJKoZIhvcNAQUMMA4E
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;CLfrI6dr0gUWAgITiDAjBgsqhkiG9w0BCRADCTAUBggqhkiG9w0DBwQIZpECRWtz
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;u5kEGDCjerXY8odQ7EEEromZJvAurk&#x2F;j81IrozBSBgkqhkiG9w0BBwEwMwYLKoZI
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;hvcNAQkQAw8wJDAUBggqhkiG9w0DBwQI0tCBcU09nxEwDAYIKwYBBQUIAQIFAIAQ
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;OsYGYUFdAH0RNc1p4VbKEAQUM2Xo8PMHBoYdqEcsbTodlCFAZH4=
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----END PKCS7-----
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;标签 “CERTIFICATE CHAIN” 曾用于表示仅包含证书列表的退化 (degenerated) PKCS #7 结构 (参见 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc2315&quot;&gt;RFC2315&lt;&#x2F;a&gt; 第 9 节). 多个现代工具已不再支持此标签. 生成器&lt;strong&gt;绝不能&lt;&#x2F;strong&gt;生成 “CERTIFICATE CHAIN” 标签. 解析器&lt;strong&gt;绝不能&lt;&#x2F;strong&gt;将 “CERTIFICATE CHAIN” 视为等同于 “PKCS7”. PKCS #7 是一个已被 CMS &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc5652&quot;&gt;RFC5652&lt;&#x2F;a&gt; 长期取代的旧规范. 在 CMS 可作为替代方案时, 实现&lt;strong&gt;绝不能&lt;&#x2F;strong&gt;生成 PKCS #7.&lt;&#x2F;p&gt;
&lt;p&gt;CMS 结构使用 “CMS” 标签进行编码. 编码内容&lt;strong&gt;必须&lt;&#x2F;strong&gt;是 BER (强烈推荐 DER 格式) 编码的 ASN.1 ContentInfo 结构, 如 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc5652&quot;&gt;RFC5652&lt;&#x2F;a&gt; 所述.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----BEGIN CMS-----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;MIGDBgsqhkiG9w0BCRABCaB0MHICAQAwDQYLKoZIhvcNAQkQAwgwXgYJKoZIhvcN
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;AQcBoFEET3icc87PK0nNK9ENqSxItVIoSa0o0S&#x2F;ISczMs1ZIzkgsKk4tsQ0N1nUM
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dvb05OXi5XLPLEtViMwvLVLwSE0sKlFIVHAqSk3MBkkBAJv0Fx0=
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----END CMS-----
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;CMS 是 IETF 对 PKCS #7 的继承. &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc5652&quot;&gt;RFC5652&lt;&#x2F;a&gt; 第 1.1.1 节描述了自 PKCS #7 v1.5 以来的变更. 实现方案在可选时&lt;strong&gt;必须&lt;&#x2F;strong&gt;生成 CMS 格式, 以促进互操作性和前向兼容性.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pkcs-8-biao-zhun&quot;&gt;PKCS #8 标准&lt;&#x2F;h3&gt;
&lt;blockquote&gt;
&lt;p&gt;此标准专用于编码私钥, 且允许对私钥加密, 是现代非对称密钥存储的事实标准.&lt;&#x2F;p&gt;
&lt;p&gt;私钥建议使用 &lt;code&gt;.key&lt;&#x2F;code&gt; 作为文件扩展名, 但也有相当一部分人使用通用拓展名 &lt;code&gt;.pem&lt;&#x2F;code&gt; 的.&lt;&#x2F;p&gt;
&lt;p&gt;可以使用 &lt;code&gt;openssl pkcs8 -topk8 -inform PEM -in private-key.pem -outform PEM -nocrypt -out private-key-pkcs8.pem&lt;&#x2F;code&gt; 来将传统私钥转换为 PKCS #8 格式.&lt;&#x2F;p&gt;
&lt;p&gt;以下内容摘抄自 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc7468&quot;&gt;RFC7468&lt;&#x2F;a&gt; Section 10 和 Section 11.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;未加密的 PKCS #8 私钥信息语法结构 (PrivateKeyInfo, 现更名为非对称密钥包 OneAsymmetricKey) 使用 “PRIVATE KEY” 标签编码. 编码内容&lt;strong&gt;必须&lt;&#x2F;strong&gt;是 BER (强烈推荐 DER 格式) 编码的 ASN.1 PrivateKeyInfo 结构, 如 PKCS #8 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc5208&quot;&gt;RFC5208&lt;&#x2F;a&gt; 所述, 或 OneAsymmetricKey 结构, 如 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc5958&quot;&gt;RFC5958&lt;&#x2F;a&gt; 所述. 两者语义相同, 可通过版本号区分.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----BEGIN PRIVATE KEY-----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;MIGHTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQglQanBRiYVPX7F2Rd
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;4CqyjEN0K4qfHw4tM&#x2F;yMIh21wamhRANCAARsxaI4jT1b8zbDlFziuLngPcExbYzz
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ePAHUmgWL&#x2F;ZCeqlODF&#x2F;l&#x2F;XvimkjaWC2huu1OSWB9EKuG+mKFY2Y5k+vF
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----END PRIVATE KEY-----
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;加密的 PKCS #8 私钥信息语法结构 (EncryptedPrivateKeyInfo, &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc5958&quot;&gt;RFC5958&lt;&#x2F;a&gt; 中名称相同) 使用 “ENCRYPTED PRIVATE KEY” 标签编码. 编码内容&lt;strong&gt;必须&lt;&#x2F;strong&gt;是 BER (强烈推荐 DER 格式) 编码的 ASN.1 PrivateKeyInfo 结构, 如 PKCS #8 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc5208&quot;&gt;RFC5208&lt;&#x2F;a&gt; 和 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc5958&quot;&gt;RFC5958&lt;&#x2F;a&gt; 所述.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----BEGIN ENCRYPTED PRIVATE KEY-----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;MIHNMEAGCSqGSIb3DQEFDTAzMBsGCSqGSIb3DQEFDDAOBAghhICA6T&#x2F;51QICCAAw
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;FAYIKoZIhvcNAwcECBCxDgvI59i9BIGIY3CAqlMNBgaSI5QiiWVNJ3IpfLnEiEsW
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Z0JIoHyRmKK&#x2F;+cr9QPLnzxImm0TR9s4JrG3CilzTWvb0jIvbG3hu0zyFPraoMkap
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;8eRzWsIvC5SVel+CSjoS2mVS87cyjlD+txrmrXOVYDE+eTgMLbrLmsWh3QkCTRtF
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;QC7k0NNzUHTV9yGDwfqMbw==
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----END ENCRYPTED PRIVATE KEY-----
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;pkcs-12-biao-zhun&quot;&gt;PKCS #12 标准&lt;&#x2F;h3&gt;
&lt;p&gt;PKCS #12 是一个归档文件格式, 不是文本编码, 但这里也顺带说一下了. 主要用于存储多个私钥及相关的 X.509 证书, 常用拓展名为 &lt;code&gt;.p12&lt;&#x2F;code&gt;, &lt;code&gt;.pfx&lt;&#x2F;code&gt;. 因为保存了私钥, 为了安全性它通常是加密的, 需要解密后才能使用.&lt;&#x2F;p&gt;
&lt;p&gt;安卓开发者应该比较熟悉, APK 签名证书通常就是使用 PKCS #12 格式存储的, 拓展名为 &lt;code&gt;.keystore&lt;&#x2F;code&gt; 或者 &lt;code&gt;.jks&lt;&#x2F;code&gt; 而已.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;gong-yao-public-key-pem-bian-ma-biao-zhun-rfc-7468-section-13&quot;&gt;公钥 (Public Key) PEM 编码标准 (RFC 7468 Section 13)&lt;&#x2F;h3&gt;
&lt;p&gt;公钥信息结构 (SubjectPublicKeyInfo) 使用 “PUBLIC KEY” 标签进行编码. 编码内容&lt;strong&gt;必须&lt;&#x2F;strong&gt;是 BER (强烈推荐 DER 格式) 编码的 ASN.1 SubjectPublicKeyInfo 结构, 如 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc5280&quot;&gt;RFC5280&lt;&#x2F;a&gt; 第 4.1.2.7 节所述.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----BEGIN PUBLIC KEY-----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEn1LlwLN&#x2F;KBYQRVH6HfIMTzfEqJOVztLe
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;kLchp2hi78cCaMY81FBlYs8J9l7krc+M4aBeCGYFjba+hiXttJWPL7ydlE+5UG4U
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Nkn3Eos8EiZByi9DVsyfy9eejh+8AXgp
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----END PUBLIC KEY-----
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;zheng-shu-certificate-pem-bian-ma-biao-zhun-rfc-7468-section-5&quot;&gt;证书 (Certificate) PEM 编码标准 (RFC 7468 Section 5)&lt;&#x2F;h3&gt;
&lt;blockquote&gt;
&lt;p&gt;这里的 “证书”, 指互联网 X.509 公钥基础设施证书及证书吊销列表 (Certificate Revocation Lists, CRL) 规范 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc5280&quot;&gt;RFC5280&lt;&#x2F;a&gt; 中的 “证书”.&lt;&#x2F;p&gt;
&lt;p&gt;以下内容摘抄自 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc7468&quot;&gt;RFC7468&lt;&#x2F;a&gt; Section 5.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;5.1. 编码&lt;&#x2F;p&gt;
&lt;p&gt;公钥证书使用 “CERTIFICATE” 标签进行编码.&lt;&#x2F;p&gt;
&lt;p&gt;编码内容&lt;strong&gt;必须&lt;&#x2F;strong&gt;是 BER (强烈推荐 DER 格式) 编码的 ASN.1 Certificate 结构, 如 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc5280&quot;&gt;RFC5280&lt;&#x2F;a&gt; 第 4 节所述.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----BEGIN CERTIFICATE-----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;MIICLDCCAdKgAwIBAgIBADAKBggqhkjOPQQDAjB9MQswCQYDVQQGEwJCRTEPMA0G
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;A1UEChMGR251VExTMSUwIwYDVQQLExxHbnVUTFMgY2VydGlmaWNhdGUgYXV0aG9y
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;aXR5MQ8wDQYDVQQIEwZMZXV2ZW4xJTAjBgNVBAMTHEdudVRMUyBjZXJ0aWZpY2F0
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ZSBhdXRob3JpdHkwHhcNMTEwNTIzMjAzODIxWhcNMTIxMjIyMDc0MTUxWjB9MQsw
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;CQYDVQQGEwJCRTEPMA0GA1UEChMGR251VExTMSUwIwYDVQQLExxHbnVUTFMgY2Vy
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dGlmaWNhdGUgYXV0aG9yaXR5MQ8wDQYDVQQIEwZMZXV2ZW4xJTAjBgNVBAMTHEdu
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dVRMUyBjZXJ0aWZpY2F0ZSBhdXRob3JpdHkwWTATBgcqhkjOPQIBBggqhkjOPQMB
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;BwNCAARS2I0jiuNn14Y2sSALCX3IybqiIJUvxUpj+oNfzngvj&#x2F;Niyv2394BWnW4X
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;uQ4RTEiywK87WRcWMGgJB5kX&#x2F;t2no0MwQTAPBgNVHRMBAf8EBTADAQH&#x2F;MA8GA1Ud
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;DwEB&#x2F;wQFAwMHBgAwHQYDVR0OBBYEFPC0gf6YEr+1KLlkQAPLzB9mTigDMAoGCCqG
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;SM49BAMCA0gAMEUCIDGuwD1KPyG+hRf88MeyMQcqOFZD0TbVleF+UsAGQ4enAiEA
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;l4wOuDwKQa+upc8GftXE2C&#x2F;&#x2F;4mKANBC6It01gUaTIpo=
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----END CERTIFICATE-----
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;以上为示例.&lt;&#x2F;p&gt;
&lt;p&gt;历史上曾使用过 “X509 CERTIFICATE” 标签, 以及较少使用的 “X.509 CERTIFICATE” 标签. 符合本文件的生成器&lt;strong&gt;必须&lt;&#x2F;strong&gt;生成 “CERTIFICATE” 标签, &lt;strong&gt;绝不能&lt;&#x2F;strong&gt;生成 “X509 CERTIFICATE” 或 “X.509 CERTIFICATE” 标签. 解析器&lt;strong&gt;绝不能&lt;&#x2F;strong&gt;将 “X509 CERTIFICATE” 或 “X.509 CERTIFICATE” 视为等同于 “CERTIFICATE”, 但有效的例外可能是为了向后兼容性 (可能附带警告).&lt;&#x2F;p&gt;
&lt;p&gt;5.2. 说明性文本&lt;&#x2F;p&gt;
&lt;p&gt;已知许多工具在 PKIX 证书的 BEGIN 行之前和 END 行之后会输出说明性文本, 比其他类型的证书更为常见. 如果输出此类文本, 应使其与证书相关, 例如提供证书中关键数据元素的文本表示.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Subject: CN=Atlantis
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Issuer: CN=Atlantis
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Validity: from 7&#x2F;9&#x2F;2012 3:10:38 AM UTC to 7&#x2F;9&#x2F;2013 3:10:37 AM UTC
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----BEGIN CERTIFICATE-----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;MIIBmTCCAUegAwIBAgIBKjAJBgUrDgMCHQUAMBMxETAPBgNVBAMTCEF0bGFudGlz
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;MB4XDTEyMDcwOTAzMTAzOFoXDTEzMDcwOTAzMTAzN1owEzERMA8GA1UEAxMIQXRs
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;YW50aXMwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAu+BXo+miabDIHHx+yquqzqNh
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Ryn&#x2F;XtkJIIHVcYtHvIX+S1x5ErgMoHehycpoxbErZmVR4GCq1S2diNmRFZCRtQID
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;AQABo4GJMIGGMAwGA1UdEwEB&#x2F;wQCMAAwIAYDVR0EAQH&#x2F;BBYwFDAOMAwGCisGAQQB
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;gjcCARUDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDAzA1BgNVHQEE
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;LjAsgBA0jOnSSuIHYmnVryHAdywMoRUwEzERMA8GA1UEAxMIQXRsYW50aXOCASow
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;CQYFKw4DAh0FAANBAKi6HRBaNEL5R0n56nvfclQNaXiDT174uf+lojzA4lhVInc0
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ILwpnZ1izL4MlI9eCSHhVQBHEp2uQdXJB+d5Byg=
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----END CERTIFICATE-----
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;5.3. 文件扩展名&lt;&#x2F;p&gt;
&lt;p&gt;尽管 PKIX 结构的文本编码可以出现在任何地方, 但已知许多工具在序列化 PKIX 结构时会提供输出此编码的选项. 为了促进互操作性并将 DER 编码与文本编码分开, 证书的文本编码应使用 “.crt” 扩展名. 实现应意识到, 尽管有此建议, 许多工具仍默认使用 “.cer” 扩展名对证书进行此类文本编码.&lt;&#x2F;p&gt;
&lt;p&gt;本节不会以任何方式干扰官方的 application&#x2F;pkix-cert 注册 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc2585&quot;&gt;RFC2585&lt;&#x2F;a&gt; (其中规定 “每个 ‘.cer’ 文件包含一个 DER 格式编码的证书”), 而仅是阐明一种广泛存在的事实上的替代方案.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;证书链 (Certificate chain) 通常是多个证书的集合, 但似乎并没有一个统一的标准来表示它.&lt;&#x2F;p&gt;
&lt;p&gt;实践上, 可以将多个 PEM 编码的证书直接串联在一个文件中, &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc7468&quot;&gt;RFC7468&lt;&#x2F;a&gt; 也允许这么干.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;pkcs-10-biao-zhun&quot;&gt;PKCS #10 标准&lt;&#x2F;h3&gt;
&lt;blockquote&gt;
&lt;p&gt;这个标准是为证书请求语法 (Certificate Request Syntax) 准备的, 不过笔者个人没怎么见过, 但还是顺带说一下了.&lt;&#x2F;p&gt;
&lt;p&gt;以下内容摘抄自 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc7468&quot;&gt;RFC7468&lt;&#x2F;a&gt; Section 7.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;PKCS #10 证书请求使用 “CERTIFICATE REQUEST” 标签进行编码. 编码内容&lt;strong&gt;必须&lt;&#x2F;strong&gt;是 BER (强烈推荐 DER 格式) 编码的 ASN.1 CertificationRequest 结构, 如 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc2986&quot;&gt;RFC2986&lt;&#x2F;a&gt; 所述.&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----BEGIN CERTIFICATE REQUEST-----
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;MIIBWDCCAQcCAQAwTjELMAkGA1UEBhMCU0UxJzAlBgNVBAoTHlNpbW9uIEpvc2Vm
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;c3NvbiBEYXRha29uc3VsdCBBQjEWMBQGA1UEAxMNam9zZWZzc29uLm9yZzBOMBAG
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ByqGSM49AgEGBSuBBAAhAzoABLLPSkuXY0l66MbxVJ3Mot5FCFuqQfn6dTs+9&#x2F;CM
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;EOlSwVej77tj56kj9R&#x2F;j9Q+LfysX8FO9I5p3oGIwYAYJKoZIhvcNAQkOMVMwUTAY
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;BgNVHREEETAPgg1qb3NlZnNzb24ub3JnMAwGA1UdEwEB&#x2F;wQCMAAwDwYDVR0PAQH&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;BAUDAwegADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDATAKBggqhkjOPQQDAgM&#x2F;ADA8
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;AhxBvfhxPFfbBbsE1NoFmCUczOFApEuQVUw3ZP69AhwWXk3dgSUsKnuwL5g&#x2F;ftAY
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;dEQc8B8jAcnuOrfU
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-----END CERTIFICATE REQUEST-----
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;标签 “NEW CERTIFICATE REQUEST” 也被广泛使用. 符合本文档的生成器&lt;strong&gt;必须&lt;&#x2F;strong&gt;生成 “CERTIFICATE REQUEST” 标签. 解析器&lt;strong&gt;可以&lt;&#x2F;strong&gt;将 “NEW CERTIFICATE REQUEST” 视为等同于 “CERTIFICATE REQUEST”.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bu-chong-nei-rong-2-an-interface-and-algorithms-for-authenticated-encryption-rfc-5116&quot;&gt;补充内容 2: An Interface and Algorithms for Authenticated Encryption (RFC 5116)&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;为了更好地理解 AEAD, 这里提供 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc5116&quot;&gt;RFC5116&lt;&#x2F;a&gt; 的翻译, 供读者参考学习.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;1-yin-yan&quot;&gt;1. 引言&lt;&#x2F;h3&gt;
&lt;p&gt;认证加密 (Authenticated Encryption) 是一种加密形式, 除了为加密的明文提供机密性之外, 还提供了一种检查其完整性和真实性的方法.
带关联数据的认证加密 (Authenticated Encryption with Associated Data), 或简称 &lt;strong&gt;AEAD&lt;&#x2F;strong&gt;, 增加了检查某些关联数据 (AD) 的完整性和真实性的能力, 这些关联数据也被称为 “附加认证数据” (&lt;strong&gt;AAD&lt;&#x2F;strong&gt;, Additional Authenticated Data), 且未被加密.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-aead-jie-kou&quot;&gt;2. AEAD 接口&lt;&#x2F;h3&gt;
&lt;p&gt;AEAD 算法具有两种操作: 认证加密和认证解密. 这些算法的输入和输出在下面以八位字节字符串的形式定义.&lt;&#x2F;p&gt;
&lt;p&gt;实现&lt;strong&gt;可以&lt;&#x2F;strong&gt;接受额外的输入. 例如, 可以提供一个输入来允许用户在不同的实现策略之间进行选择. 然而, 此类扩展&lt;strong&gt;绝不能&lt;&#x2F;strong&gt;影响与其他实现的互操作性.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;2-1-ren-zheng-jia-mi&quot;&gt;2.1. 认证加密&lt;&#x2F;h4&gt;
&lt;p&gt;认证加密操作具有四个输入, 每个输入都是一个八位字节字符串:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;一个秘密密钥 (&lt;strong&gt;secret key&lt;&#x2F;strong&gt;) K, 它&lt;strong&gt;必须&lt;&#x2F;strong&gt;以均匀随机或伪随机的方式生成.&lt;&#x2F;li&gt;
&lt;li&gt;一个随机数 (&lt;strong&gt;nonce&lt;&#x2F;strong&gt;) N. 对于密钥的任何特定值, 提供给认证加密操作不同调用的每个随机数&lt;strong&gt;必须&lt;&#x2F;strong&gt;是不同的, 除非每个随机数都是零长度. 能够生成不同随机数的应用程序&lt;strong&gt;必须&lt;&#x2F;strong&gt;使用第 3.2 节中定义的随机数形成方法, 并可以使用任何其他满足唯一性要求的方法. 其他应用程序&lt;strong&gt;必须&lt;&#x2F;strong&gt;使用零长度随机数.&lt;&#x2F;li&gt;
&lt;li&gt;一个明文 (plaintext) P, 其中包含要要认证且需要被加密的数据.&lt;&#x2F;li&gt;
&lt;li&gt;关联数据 (associated data) A, 其中包含要认证但不需要被加密的数据.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;敲黑板: nonce 必须唯一, 但不必保密.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;有一个单一输出:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;一个密文 C, 其长度至少与明文一样长, 或者&lt;&#x2F;li&gt;
&lt;li&gt;一个指示请求的加密操作无法执行的指示.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;所有输入和输出都是可变长度的八位字节字符串, 其长度遵守以下限制:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;密钥 K 中的八位字节数在 1 到 255 之间. 对于每个 AEAD 算法, K 的长度&lt;strong&gt;必须&lt;&#x2F;strong&gt;是固定的.
对于密钥的任何特定值, 要么 1) 提供给认证加密操作不同调用的每个随机数必须是不同的, 要么 2) 每个随机数必须是零长度. 如果使用零长度随机数与特定密钥一起, 则与该密钥一起使用的每个随机数必须具有零长度. 否则, 随机数的八位字节数应为十二 (12). 可以与特定密钥一起使用不同长度的随机数. 有些算法不能与零长度随机数一起使用, 但其他算法可以; 参见第 4 节. 符合推荐随机数长度的应用程序将避免根据所使用的算法构造不同长度的随机数. 此指导有助于将算法特定逻辑保持在应用程序之外.&lt;&#x2F;li&gt;
&lt;li&gt;明文 P 中的八位字节数可以为零.&lt;&#x2F;li&gt;
&lt;li&gt;关联数据 A 中的八位字节数可以为零.&lt;&#x2F;li&gt;
&lt;li&gt;密文 C 中的八位字节数可以为零.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;本规范不对随机数、明文、密文或附加认证数据设置最大长度限制. 然而, 特定 AEAD 算法可以进一步限制这些输入和输出的长度. 特定 AEAD 实现可以进一步限制其输入和输出的长度. 如果特定 AEAD 算法的实现被要求处理超出可接受长度范围的输入, 或超出该实现支持的长度范围的输入, 它必须返回错误代码, 并且不得输出任何其他信息. 特别是, 不得返回部分加密或部分解密的数据.&lt;&#x2F;p&gt;
&lt;p&gt;明文 P 同时提供机密性和消息认证. 当 P 的长度为零时, AEAD 算法充当输入 A 的消息认证码.&lt;&#x2F;p&gt;
&lt;p&gt;关联数据 A 用于保护需要认证但不需要保密的信息. 例如, 在使用 AEAD 保护网络协议时, 此输入可以包括地址、端口、序列号、协议版本号以及其他指示如何处理、转发或处理明文或密文的字段. 在许多情况下, 希望认证这些字段, 尽管它们必须保持明文以允许网络或系统正常运行. 当此数据包含在输入 A 中时, 可以在不将数据复制到明文中提供认证.
秘密密钥 K 不得包含在任何其他输入 (N、P 和 A) 中. (此限制并不意味着必须检查这些输入的值以确保它们不包含匹配密钥的子字符串; 相反, 它意味着密钥不得明确复制到这些输入中. )&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;敲黑板: TLS 里面, TLS Record 的 TLV 结构, 类型和长度是不能加密的, 故作为 AAD.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;随机数在算法内部被认证, 因此没有必要将其包含在 AD 输入中. 如果对应用程序方便, 可以将随机数包含在 P 或 A 中.&lt;&#x2F;p&gt;
&lt;p&gt;随机数可以与密文一起存储或传输, 或者可以在认证解密操作之前立即重建. 只需向解密模块提供足够的信息以允许其构造随机数即可. (例如, 系统可以使用特定格式的序列号作为随机数, 在这种情况下, 可以从密文的顺序推断出来.) 由于认证解密过程会检测不正确的随机数值, 如果随机数被不正确重建并输入到认证解密操作中, 不会导致安全失败. 任何随机数重建方法都需要考虑加密和解密过程之间密文丢失或重新排序的可能性.&lt;&#x2F;p&gt;
&lt;p&gt;应用程序不得假设密文的任何特定结构或格式.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;2-2-ren-zheng-jie-mi&quot;&gt;2.2. 认证解密&lt;&#x2F;h4&gt;
&lt;p&gt;认证解密操作具有四个输入: K、N、A 和 C, 如上定义. 它只有一个单一输出, 要么是明文值 P, 要么是一个特殊符号 FAIL, 表示输入不是认证的. 当使用输入 K、N、P 和 A 通过加密操作生成 C (对于 N、P 和 A 的某些值) 时, 密文 C、随机数 N 和关联数据 A 对于密钥 K 是认证的. 认证解密操作将以高概率返回 FAIL, 只要输入 N、P 和 A 是由遵守随机数的对手精心制作的, 且该对手不知道秘密密钥(假设 AEAD 算法是安全的).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;2-3-shu-ju-ge-shi&quot;&gt;2.3. 数据格式&lt;&#x2F;h4&gt;
&lt;p&gt;本文档未指定 AEAD 输入和输出的任何特定编码, 因为编码不影响 AEAD 算法提供的安全服务.&lt;&#x2F;p&gt;
&lt;p&gt;在选择应用程序数据格式时, 应用程序应将密文 C 放置在认证解密操作的其他输入所需的任何其他数据之后. 例如, 如果随机数和密文都出现在数据包中, 前者应先于后者. 此规则有助于 AEAD 算法的高效和简单的硬件实现.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-aead-suan-fa-de-shi-yong-zhi-dao&quot;&gt;3. AEAD 算法的使用指导&lt;&#x2F;h3&gt;
&lt;p&gt;本节提供必须遵循的建议, 以安全地使用 AEAD 算法.&lt;&#x2F;p&gt;
&lt;p&gt;如果应用程序无法满足随机数生成的唯一性要求, 则它必须使用零长度随机数. 下面定义的随机化或有状态算法适合与此类应用程序一起使用. 否则, 应用程序应使用长度为十二个八位字节的随机数. 由于鼓励算法支持该长度, 应用程序应使用该长度以辅助互操作性.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;3-1-nonce-sheng-cheng-yao-qiu&quot;&gt;3.1. Nonce 生成要求&lt;&#x2F;h4&gt;
&lt;blockquote&gt;
&lt;p&gt;略, 简要总结: 重复使用 nonce 会有严重的安全问题, 具体因特定 AEAD 算法而异; nonce 必须唯一, 但不必保密, 可以将 nonce 直接附加在密文前面, 又或者像 TLS 那样, 通过握手协商出一个初始值, 然后每次加密时依据顺序号生成.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h4 id=&quot;3-2-tui-jian-de-nonce-gou-zao-fang-fa&quot;&gt;3.2. 推荐的 Nonce 构造方法&lt;&#x2F;h4&gt;
&lt;p&gt;(略)&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4-aead-suan-fa-gui-fan-yao-qiu&quot;&gt;4. AEAD 算法规范要求&lt;&#x2F;h3&gt;
&lt;p&gt;每个 AEAD 算法必须只接受固定密钥长度 K_LEN 的密钥, 并且不得要求所提供的密钥具有任何特定的数据格式. 需要这种结构 (例如, 包含特定奇偶校验格式子密钥的算法) 的算法将需要在内部提供它.&lt;&#x2F;p&gt;
&lt;p&gt;每个 AEAD 算法必须接受长度在零到 P_MAX Bytes (含零和 P_MAX) 之间的任何明文, 其中 P_MAX 值是该算法特有的. P_MAX 的值必须大于零, 并且应至少为 65536 (2^16) Bytes. 此大小是网络数据包的典型上限. 其他应用程序可能使用更大的 P_MAX 值,  因此通用算法支持更高的值是可取的.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;某些 AEAD 算法存在 “漏洞”, 一旦发送了一定数量的消息, 它们就不再安全, 为此, TLS 1.3 引入了 KeyUpdate 机制.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;每个 AEAD 算法必须接受长度在零到 A_MAX Bytes (含零和 A_MAX) 之间的任何关联数据,  其中 A_MAX 值是该算法特有的. A_MAX 的值必须大于零, 并且应至少为 65536 (2^16) Bytes. 其他应用程序可能使用更大的 A_MAX 值,  因此通用算法支持更高的值是可取的.&lt;&#x2F;p&gt;
&lt;p&gt;每个 AEAD 算法必须接受长度在 N_MIN 和 N_MAX Bytes (含 N_MIN 和 N_MAX) 之间的任何随机数 (nonce), 其中 N_MIN 和 N_MAX 的值是该算法特有的. N_MAX 和 N_MIN 的值可以相等. 每个算法应接受长度为 12 Bytes 的随机数. 下面描述的随机化或有状态算法的 N_MAX 值可以为零.&lt;&#x2F;p&gt;
&lt;p&gt;AEAD 算法可以以任何方式构造其密文输出; 例如, 密文可以包含一个认证标签. 每个算法都应选择一种有利于高效处理的结构.
认证加密算法可以包含或使用随机源, 例如, 用于生成包含在密文输出中的内部初始化向量. 这种 AEAD 算法被称为随机化算法; 但请注意, 只有加密是随机的, 而解密始终是确定性的. 随机化算法的 N_MAX 值可以为零.&lt;&#x2F;p&gt;
&lt;p&gt;认证加密算法可以包含在加密操作的调用之间维护的内部状态信息, 例如, 允许构造用作算法内部随机数的不同值. 这种 AEAD 算法被称为有状态算法. 即使应用程序输入零长度随机数, 此方法也可以用于算法以提供良好的安全性. 有状态算法的 N_MAX 值可以为零.&lt;&#x2F;p&gt;
&lt;p&gt;AEAD 算法的规范必须包含上面定义的 K_LEN、P_MAX、A_MAX、N_MIN 和 N_MAX 值. 此外, 它必须指定最大可能密文的八位字节数, 我们将其表示为 C_MAX.&lt;&#x2F;p&gt;
&lt;p&gt;每个 AEAD 算法必须提供一个描述, 说明明文长度与密文长度之间的关系. 这种关系不得依赖于外部参数, 例如认证强度参数 (例如, 认证标签长度). 这种依赖性会通过创建一种情况来使算法的使用复杂化, 即 AEAD 注册表中的信息不足以确保互操作性.&lt;&#x2F;p&gt;
&lt;p&gt;每个 AEAD 算法规范应描述由于意外重复使用随机数值而导致的安全降级.&lt;&#x2F;p&gt;
&lt;p&gt;每个 AEAD 算法规范应提供详细安全分析的参考文献. 本文档未指定特定的安全模型, 因为文献中已使用了几种不同的模型. 安全分析应定义或引用一个安全模型.&lt;&#x2F;p&gt;
&lt;p&gt;如上所述, 随机化或有状态的算法应使用这些术语来描述自己.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;5-aead-suan-fa&quot;&gt;5. AEAD 算法&lt;&#x2F;h3&gt;
&lt;p&gt;(以下简要总结, 不再翻译原文)&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: center&quot;&gt;K_LEN&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;P_MAX&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;A_MAX&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;N_MIN&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;N_MAX&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;C_MAX&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center&quot;&gt;密钥长度&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;明文最大长度&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;AAD 最大长度&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;Nonce 最低长度&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;Nonce 最大长度&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;密文最大长度&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;单位均为 Bytes (即 &lt;code&gt;&amp;lt;&amp;amp;[u8]&amp;gt;::len&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;5-1-aes-128-gcm&quot;&gt;5.1. AES-128-GCM&lt;&#x2F;h4&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: center&quot;&gt;K_LEN&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;P_MAX&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;A_MAX&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;N_MIN&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;N_MAX&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;C_MAX&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center&quot;&gt;16&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;2^36 - 31&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;2^61 - 1&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;12&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;12&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;2^36 - 15&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;blockquote&gt;
&lt;p&gt;对于 GCM, C.len = P.len + 16, 多出来的 16 Bytes 是认证标签.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;GCM 模式下, 加密操作重复使用 nonce 值会严重削弱安全性, 必须保证 nonce 的唯一性.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;5-2-aes-256-gcm&quot;&gt;5.2. AES-256-GCM&lt;&#x2F;h4&gt;
&lt;p&gt;除 K_LEN 为 32 Bytes 外, 其他均与 AES-128-GCM 相同.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;5-3-aes-128-ccm&quot;&gt;5.3. AES-128-CCM&lt;&#x2F;h4&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: center&quot;&gt;K_LEN&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;P_MAX&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;A_MAX&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;N_MIN&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;N_MAX&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;C_MAX&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center&quot;&gt;16&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;2^24 - 1&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;2^64 - 1&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;12&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;12&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;2^24 + 15&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;blockquote&gt;
&lt;p&gt;对于 CCM, C.len = P.len + 16, 多出来的 16 Bytes 是认证标签.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;CCM 模式下, 加密操作重复使用 nonce 值会严重削弱安全性, 必须保证 nonce 的唯一性.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;5-4-aes-256-ccm&quot;&gt;5.4. AES-256-CCM&lt;&#x2F;h4&gt;
&lt;p&gt;除 K_LEN 为 32 Bytes 外, 其他均与 AES-128-CCM 相同.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;5-5-fei-rfc-5116-suo-lie-ci-chu-jian-yao-bu-chong-chacha20-poly1305-rfc-8439&quot;&gt;5.5. (非 RFC 5116 所列, 此处简要补充) Chacha20-Poly1305 (RFC 8439)&lt;&#x2F;h4&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: center&quot;&gt;K_LEN&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;P_MAX&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;A_MAX&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;N_MIN&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;N_MAX&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;C_MAX&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center&quot;&gt;32&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;274,877,906,880 (2^38 - 64)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;2^64 - 1&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;12&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;12&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;274,877,906,896 (2^38 - 48)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;blockquote&gt;
&lt;p&gt;C.len = P.len + 16, 多出来的 16 Bytes 是认证标签.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;类似地, 加密操作重复使用 nonce 值会严重削弱安全性, 必须保证 nonce 的唯一性.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;5-6-fei-rfc-5116-suo-lie-ci-chu-jian-yao-bu-chong-xchacha20-poly1305-draft-irtf-cfrg-xchacha-03&quot;&gt;5.6. (非 RFC 5116 所列, 此处简要补充) XChacha20-Poly1305 (draft-irtf-cfrg-xchacha-03)&lt;&#x2F;h4&gt;
&lt;blockquote&gt;
&lt;p&gt;XChacha20 是 Chacha20 的变种, 使用 192-bit (24 Bytes) 的 nonce.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: center&quot;&gt;K_LEN&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;P_MAX&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;A_MAX&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;N_MIN&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;N_MAX&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;C_MAX&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center&quot;&gt;32&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;~2^80 (TBD)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;2^64 - 1&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;24&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;24&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;~2^80 (TBD)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;blockquote&gt;
&lt;p&gt;C.len = P.len + 16, 多出来的 16 Bytes 是认证标签.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;类似地, 加密操作重复使用 nonce 值会严重削弱安全性, 必须保证 nonce 的唯一性.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;6-iana-considerations&quot;&gt;6. IANA Considerations&lt;&#x2F;h3&gt;
&lt;p&gt;(略)&lt;&#x2F;p&gt;
&lt;h3 id=&quot;7-qi-ta-kao-lu&quot;&gt;7. 其他考虑&lt;&#x2F;h3&gt;
&lt;p&gt;可以使用 &lt;code&gt;encrypt-then-MAC&lt;&#x2F;code&gt; (加密后 MAC) 策略组合加密算法和消息认证码算法提供 AEAD.&lt;&#x2F;p&gt;
&lt;p&gt;(其余略)&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;xiao-jie&quot;&gt;小结&lt;&#x2F;h2&gt;
&lt;p&gt;阅读完本文, 我们应当已经熟悉了对称加密和非对称密码学(公钥密码学)的基本概念, 以及下面这些术语:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;RSA 公钥密码系统&lt;&#x2F;li&gt;
&lt;li&gt;ECC 公钥密码系统&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;使用到的椭圆曲线: Curve25519 &#x2F; Ed25519, Curve448 &#x2F; Ed448 等&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;X25519 (ECDH) &#x2F; X448 (EdDH).&lt;&#x2F;li&gt;
&lt;li&gt;ECDSA&lt;&#x2F;li&gt;
&lt;li&gt;EdDSA (Ed25519 &#x2F; Ed448).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;此外, 我们还应熟悉 PEM 格式下证书、公私钥的文本编码方式, 以及其与 DER 的关系.&lt;&#x2F;p&gt;
&lt;p&gt;再有, 我们应当熟悉 AEAD 算法基本流程, 了解 AAD, nonce 的概念与作用, 熟记常用的 AEAD 算法, 铭记对于绝大多数 (本文所列全部) AEAD 算法来说, nonce 必须唯一.&lt;&#x2F;p&gt;
</content>
        <summary type="html">本文介绍了对称加密和非对称密码学, 重点介绍了 AEAD 加密方案, 以及公钥密码系统在数字签名领域的应用. 最后补充介绍了数字证书相关内容.</summary>
        </entry><entry xml:lang="zh">
        <title>从零开始了解 TLS 1.3 系列笔记 (五) —— 实用密码学之「密钥交换, Diffie–Hellman 与后量子加密」</title>
        <published>2025-09-16T00:00:00+00:00</published>
        <updated>2025-09-16T00:00:00+00:00</updated>
        <author>
            <name>Hantong Chen</name>
        </author>
        <link rel="alternate" href="https://i.han.rs/blog/25-09-16-tls-series-cryptography-4/" type="text/html"/>
        <id>https://i.han.rs/blog/25-09-16-tls-series-cryptography-4/</id>
        
            <content type="html">&lt;h2 id=&quot;dao-yu&quot;&gt;导语&lt;&#x2F;h2&gt;
&lt;p&gt;在密码学中, &lt;a href=&quot;http:&#x2F;&#x2F;cacr.uwaterloo.ca&#x2F;hac&#x2F;about&#x2F;chap12.pdf&quot;&gt;密钥建立 (key establishment)&lt;&#x2F;a&gt;, 或称&lt;strong&gt;密钥交换&lt;&#x2F;strong&gt; (key exchange, KE), 是一个过程或协议. 通过该过程或协议, 通信双方共享密钥.&lt;&#x2F;p&gt;
&lt;p&gt;密钥交换过程一定基于公私钥加密, 也就是非对称加密, 我们将在后续章节详细介绍.&lt;&#x2F;p&gt;
&lt;p&gt;密钥交换可以分为两类:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在&lt;strong&gt;密钥协商&lt;&#x2F;strong&gt;中, 双方都对密钥的生成做出贡献, 因此没有一方能单独决定最终的密钥.&lt;&#x2F;p&gt;
&lt;p&gt;如 Diffie-Hellman 密钥交换协议 (DH), 或 ECDH (Elliptic-Curve DH, 椭圆曲线 DH). 大多数不严谨的场景, 密钥交换和密钥协商指的是一件事.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;在&lt;strong&gt;密钥传输&lt;&#x2F;strong&gt;中, 一方生成密钥并将其传输给另一方.&lt;&#x2F;p&gt;
&lt;p&gt;如 RSA 密钥交换过程, 一方通过私钥加密随机会话密钥, 并将其发送到另一方, 另一方使用相应公钥将其解密.&lt;&#x2F;p&gt;
&lt;p&gt;由于此过程是静态的, 高度依赖 RSA 的安全性, 在 TLS 1.3 中已被弃用, 即便是 TLS 1.2 中也不推荐使用.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;通过密码学设计, 密钥交换方案 (Key exchange schemes) 允许通信双方安全地交换加密密钥, 通常这个过程发生在加密通讯开始时, 例如在 TLS 握手阶段.&lt;&#x2F;p&gt;
&lt;p&gt;大体上, 密钥协商可以基于匿名(&lt;strong&gt;无认证&lt;&#x2F;strong&gt;)的密钥交换协议 (如 DH), 密码或预共享密钥 (pre-shared key, PSK), 数字证书或许多元素的组合. 某些通信协议仅建立并从头到尾使用同一个共享密钥, 而另一些通信协议随着时间的流逝不断更改共享密钥.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;小贴士&lt;&#x2F;p&gt;
&lt;p&gt;由于密钥交换协议自身是匿名的, 密钥协商在一些需要消息完整性的场景 (如 TLS) 会配合签名算法组成最终的加密方案, 如 TLS 1.2 的加密套件有 &lt;code&gt;TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384&lt;&#x2F;code&gt;, 即:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ECDHE: Ephemeral ECDH, 密钥交换方案;&lt;&#x2F;li&gt;
&lt;li&gt;ECDSA: 数字签名方案;&lt;&#x2F;li&gt;
&lt;li&gt;AES-256-GCM: 对称加密方案;&lt;&#x2F;li&gt;
&lt;li&gt;SHA384: 消息摘要算法.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;这里超前提一下, 后面会继续介绍相关内容.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;diffie-hellman-mi-yao-jiao-huan-dhke&quot;&gt;Diffie-Hellman 密钥交换 (DHKE)&lt;&#x2F;h2&gt;
&lt;p&gt;DHKE 是最早的公钥协议之一, 允许两个没有事先了解的当事方在不安全的渠道上安全地交换共享密钥. 请注意, DHKE 可以对抗嗅探攻击 (即直接读取数据包), 但无法对抗中间人攻击 MitM (无认证, 中间人可以冒充).&lt;&#x2F;p&gt;
&lt;p&gt;DHKE 的实现包括经典的基于离散对数的 DH, 和基于椭圆曲线的 ECDH.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cong-hun-he-yan-se-jie-shi&quot;&gt;从混合颜色解释&lt;&#x2F;h3&gt;
&lt;p align=&quot;center&quot;&gt;
  &lt;img src=&quot;.&#x2F;Diffie-Hellman_Key_Exchange.svg&quot; alt=&quot;Diffie-Hellman key exchange&quot; style=&quot;max-width: 50%;&quot;&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;这是来自维基百科的一幅经典图片, 利用混合颜色来解释 DH 的工作原理:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Alice 和 Bob 公开同意使用黄色;&lt;&#x2F;li&gt;
&lt;li&gt;Alice 选择一个秘密的红色, 并将其与黄色混合, 得到橙色;&lt;&#x2F;li&gt;
&lt;li&gt;Bob 选择一个秘密的海洋绿色, 并将其与黄色混合, 得到浅天蓝色;&lt;&#x2F;li&gt;
&lt;li&gt;Alice 和 Bob 交换他们混合后的颜色, 我们依然假设混合颜色难以分离出原始颜色;&lt;&#x2F;li&gt;
&lt;li&gt;Alice 将 Bob 交换过来的浅天蓝色与她的秘密颜色混合, 得到黄褐色;&lt;&#x2F;li&gt;
&lt;li&gt;Bob 将 Alice 交换过来的橙色与他的秘密颜色混合, 也得到黄褐色;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;到此, Alice 和 Bob 都得到了相同的颜色, 即共享密钥, 而中间人 Eve 只能看到黄色, 橙色和浅天蓝色, 无法计算出黄褐色.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;jing-dian-dh&quot;&gt;经典 DH&lt;&#x2F;h3&gt;
&lt;p&gt;对于传统基于离散对数的 DH, 其过程类似于前面的颜色混合解释.&lt;&#x2F;p&gt;
&lt;p&gt;首先介绍一点数学背景知识:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;模幂: 是指求 $g$ 的 $a$ 次幂模 $p$ 的值 $c$ 的过程, 记作 $c = g^a \mod p$, 其中 $p$ 是一个质数;&lt;&#x2F;li&gt;
&lt;li&gt;离散对数, 即模幂的逆运算, 是指已知 $g$, $p$, $c$, 求 $a$ 的过程&lt;&#x2F;li&gt;
&lt;li&gt;模幂运算律: $g^{ab} \mod p = {(g^a \mod p)}^b \mod p$&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;模幂过程计算非常快, 然而离散对数求解被认为在 $p$ 足够大的情况下是在现有计算能力下无法完成的, 此即&lt;strong&gt;离散对数难题&lt;&#x2F;strong&gt; (discrete logarithm problem, DLP). 经典的 DHKE 就是基于 DLP 设计的.&lt;&#x2F;p&gt;
&lt;p&gt;那么类似地就有 DHKE 的过程:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Alice 和 Bob 公开同意使用一个大质数 $p$ 和一个生成元 $g$ (通常 $g$ 是 2 或 5, 不需要很大), 在代码层面是写死的;&lt;&#x2F;li&gt;
&lt;li&gt;Alice 选择一个秘密整数 $a$, 并计算 $A = g^a \mod p$, 将 $A$ 发送给 Bob;&lt;&#x2F;li&gt;
&lt;li&gt;Bob 选择一个秘密整数 $b$, 并计算 $B = g^b \mod p$, 将 $B$ 发送给 Alice;&lt;&#x2F;li&gt;
&lt;li&gt;Alice 收到 $B$ 后, 计算共享密钥 $S_1 = B^a \mod p$;&lt;&#x2F;li&gt;
&lt;li&gt;Bob 收到 $A$ 后, 计算共享密钥 $S_2 = A^b \mod p$;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;由模幂的运算律可以找到 $S_1 = S_2$, 即 Alice 和 Bob 都得到了相同的共享密钥 $S$; 而中间人获得 $A$ 和 $B$ 后, 只能通过离散对数求解 $a$ 或 $b$.&lt;&#x2F;p&gt;
&lt;p&gt;在最常见的 DHKE 实现中 (RFC 3526), 基数是 $g = 2$, 模数 $p$ 是一个 1536 到 8192 比特的大质数. 而整数 $A$ $B$ 通常会使用非常大的数字以防范暴力破解. 对于这种离散对数问题 (DLP), 目前还不存在有效的算法.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ecdh&quot;&gt;ECDH&lt;&#x2F;h3&gt;
&lt;p&gt;ECDH 应用椭圆曲线代替了 DH 中的模幂.&lt;&#x2F;p&gt;
&lt;p&gt;我们依然有运算律:&lt;&#x2F;p&gt;
&lt;p&gt;$$(a * G) * b = (b * G) * a$$&lt;&#x2F;p&gt;
&lt;p&gt;其中 $a, b$ 为常数, $G$ 为椭圆曲线上的某一点的坐标 $(x, y)$.&lt;&#x2F;p&gt;
&lt;p&gt;类似地有 ECDH 的过程:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Alice 和 Bob 公开同意使用一个椭圆曲线和基点 $G$;&lt;&#x2F;li&gt;
&lt;li&gt;Alice 生成一个随机的 ECC 密钥对: $A = a * G$, 将公钥 $A$ 发送给 Bob;&lt;&#x2F;li&gt;
&lt;li&gt;Bob 生成一个随机的 ECC 密钥对: $B = b * G$, 将公钥 $B$ 发送给 Alice;&lt;&#x2F;li&gt;
&lt;li&gt;Alice 收到 $B$ 后, 计算共享密钥 $S_1 = a * B$;&lt;&#x2F;li&gt;
&lt;li&gt;Bob 收到 $A$ 后, 计算共享密钥 $S_2 = b * A$&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;显然, $S_1 = S_2$, 即 Alice 和 Bob 都得到了相同的共享密钥 $S$, 而私钥 $a$, $b$ 的安全性, 则类似地由 ECDLP 问题提供保证, 即「通过公开的 $kG$ 以及 $G$ 这两个参数, 目前没有有效的手段能快速求解出 $k$ 的值. 」&lt;&#x2F;p&gt;
&lt;h4 id=&quot;shi-li&quot;&gt;示例&lt;&#x2F;h4&gt;
&lt;blockquote&gt;
&lt;p&gt;如果读者还是对 (EC)DH 感到陌生, 相信 X25519 这个名字会更熟悉一些, 这是 TLS 1.3 中最常用的密钥交换算法.&lt;&#x2F;p&gt;
&lt;p&gt;以下内容参考自 &lt;a href=&quot;https:&#x2F;&#x2F;crypto-in-action.github.io&#x2F;intro-ed25519&#x2F;190902-intro-x25519.pdf&quot;&gt;深入理解 X25519&lt;&#x2F;a&gt;, 在此表示感谢.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Curve25519 是一种椭圆曲线, 由 Daniel J. Bernstein 在 2005 年设计, 其设计目标是提供高安全性和高性能的椭圆曲线密码学 (ECC) 操作. Curve25519 的名称来源于其使用的素数 $2^{255} - 19$, 该素数定义了曲线所在的有限域. 而 X25519 是基于 Curve25519 的密钥交换协议, 具体来说, X25519 是一种椭圆曲线 Diffie-Hellman (ECDH) 密钥交换协议的实现. 关于 ECC 公钥密码学的更详细内容, 我们将在下一章介绍.&lt;&#x2F;p&gt;
&lt;p&gt;值得记忆的常识:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;X25519 协议对应的私钥是 32 字节.&lt;&#x2F;li&gt;
&lt;li&gt;X25519 协议对应的公钥是 &lt;strong&gt;32&lt;&#x2F;strong&gt; 字节.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;dhe-diffie-hellman-ephemeral-lin-shi-dh&quot;&gt;DHE (Diffie-Hellman Ephemeral, 临时 DH)&lt;&#x2F;h3&gt;
&lt;p&gt;前面介绍的经典 DH 与 ECDH 协议流程, 都是在最开始时交换一次密钥, 之后就一直使用该密钥通讯. 因此如果密钥被破解, 整个会话的所有信息对攻击者而言就完全透明了.&lt;&#x2F;p&gt;
&lt;p&gt;为了进一步提高安全性, 密码学家提出了「完全前向保密 (Perfect Forward Secrecy, PFS)」的概念, 并在 DHKE 与 ECDH 的基础上提出了支持 PFS 的 DHE &#x2F; ECDHE 协议.&lt;&#x2F;p&gt;
&lt;p&gt;PFS 是指长期使用的主密钥泄漏不会导致过去的会话密钥泄漏, 从而保护过去进行的通讯不受密码或密钥在未来暴露的威胁.&lt;&#x2F;p&gt;
&lt;p&gt;DHE &#x2F; ECDHE 协议的流程与前面介绍的 DH &#x2F; ECDH 类似, 但每次通讯时都会重新生成一对密钥对, 计算出新的共享密钥随密文发送供下一轮使用. 这样即使某次会话的密钥被破解, 也不会影响到之前或之后的会话.&lt;&#x2F;p&gt;
&lt;p&gt;(&lt;del&gt;一个小问题: 如果能破解一次, 那么破解下一次应该也不难了?&lt;&#x2F;del&gt;)&lt;&#x2F;p&gt;
&lt;h3 id=&quot;liang-zi-ji-suan-ji-de-ying-xiang&quot;&gt;量子计算机的影响&lt;&#x2F;h3&gt;
&lt;p&gt;在量子计算机面前, DLP 可以通过 Shor 算法解决, 因此 DH 和 ECDH 在量子计算机面前不再安全. 值得庆幸的是, 当前量子计算机还远未达到能破解这些加密算法的规模, 但从长远来看, 我们需要考虑量子安全的密钥交换算法.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hou-liang-zi-mi-ma-xue-post-quantum-cryptography-pqc-ying-yong-hun-he-mi-yao-jiao-huan-hybrid-key-exchange&quot;&gt;后量子密码学 (Post-Quantum Cryptography, PQC) 应用: 混合密钥交换 (Hybrid Key Exchange)&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;相信读者一定提到过 X25519MLKEM768, X25519Kyber768Draft00 这样的名字, 这是 TLS 1.3 中的混合密钥交换方案, 本节简要介绍.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;前面提到, 量子计算机的出现对 (EC)DH 的密码学安全保证构成威胁, 因此需要考虑量子安全的密钥交换算法. 目前, NIST 在 &lt;a href=&quot;https:&#x2F;&#x2F;nvlpubs.nist.gov&#x2F;nistpubs&#x2F;FIPS&#x2F;NIST.FIPS.203.pdf&quot;&gt;FIPS. 203&lt;&#x2F;a&gt; 中标准化了 ML-KEM (Module-Lattice-Based Key-Encapsulation Mechanism, 基于模格的密钥封装机制), 各大厂商亦跟进用之替代了先前测试阶段的 Kyber (ML-KEM 的前身).&lt;&#x2F;p&gt;
&lt;p&gt;在介绍混合密钥交换之前, 先简要介绍一下 KEM.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kem-key-encapsulation-mechanism-mi-yao-feng-zhuang-ji-zhi&quot;&gt;KEM (Key Encapsulation Mechanism, 密钥封装机制)&lt;&#x2F;h3&gt;
&lt;p&gt;如其名, 密钥封装机制核心就是对密文的封装 (encapsulate) 与解封装 (decapsulate), 示意图如下:&lt;&#x2F;p&gt;
&lt;div align=&quot;center&quot;&gt;
  &lt;img src=&quot;.&#x2F;FIPS.206-MLKEM-KE.png&quot; alt=&quot;KEM&quot; style=&quot;max-width: 50%;&quot;&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;主要流程为:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Alice 生成一对公私钥 $(pk, sk)$, 并将公钥 $pk$ 发送给 Bob; 公钥也称封装密钥 (encapsulation key), 私钥也称解封装密钥 (decapsulation key);&lt;&#x2F;li&gt;
&lt;li&gt;Bob 使用公钥 $pk$ 执行 Encaps 操作, 获得一个密钥和关联的&lt;strong&gt;封装密文&lt;&#x2F;strong&gt;; Bob 将关联密文发送给 Alice, 密钥则作为共享密钥使用;&lt;&#x2F;li&gt;
&lt;li&gt;Alice 使用私钥 $sk$ 对关联密文执行 Decaps 解封装操作, 获得共享密钥;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;到此, Alice 和 Bob 得到了相同的共享密钥.&lt;&#x2F;p&gt;
&lt;p&gt;而 ML-KEM 是 KEM 中的一种, 其安全性基于模格 (Module-Lattice) 问题, 目前已知的量子计算机无法有效解决.&lt;&#x2F;p&gt;
&lt;p&gt;稍微跑题, 还有 ML-DSA, 作为数字签名算法 (DSA), 应用于 TLS 证书验证模块 (draft-ietf-tls-mldsa).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tls-1-3-zhong-de-hun-he-mi-yao-jiao-huan&quot;&gt;TLS 1.3 中的混合密钥交换&lt;&#x2F;h3&gt;
&lt;p&gt;(也许是)出于兼容性考虑, 目前 TLS 1.3 中的后量子密钥交换方案均以混合密钥交换的形式出现.&lt;&#x2F;p&gt;
&lt;p&gt;感谢 &lt;a href=&quot;https:&#x2F;&#x2F;www.netmeister.org&#x2F;blog&#x2F;tls-hybrid-kex.html&quot;&gt;@jschauma 总结的一图流&lt;&#x2F;a&gt;,  (图示为 X25519Kyber768, 但其他的基于 ML-KEM 的混合密钥交换方案也是类似的流程):&lt;&#x2F;p&gt;
&lt;div align=&quot;center&quot;&gt;
  &lt;img src=&quot;.&#x2F;kyber-kex.png&quot; alt=&quot;TLS 1.3 Hybrid Key Exchange&quot; style=&quot;max-width: 100%;&quot;&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;简单地来说, 就是在原 (EC)DH 的基础上, 额外增加了 KEM 的公钥交换与密文交换过程: 客户端将 PQC 公钥拼接在客户端向服务端共享的 (EC)DH 公钥后, 服务端将封装密文拼接在服务端向客户端共享的 (EC)DH 公钥后, 双方最终将通过 (EC)DH 得到的共享密钥与 KEM 拿到的或解封装出来的共享密钥拼接起来, 就得到了最终的共享密钥, 是不是非常简单粗暴呢.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;碎碎念&lt;&#x2F;p&gt;
&lt;p&gt;后量子算法的引入, 直接导致 ClientHello 消息体积暴增, 如 X25519MLKEM768, 会额外多出 32 字节的用于回落的 X25519 公钥, 以及 1184 字节的 ML-KEM-768 的公钥, 加上原有的 500 字节左右, 大概是 1700 字节左右, 已经超过了 IPv4 TCP 最大 MSS (1500 - 20 - 20 = 1460 Bytes) 导致需要分包, 一旦丢包, 握手延迟蹭蹭涨.&lt;&#x2F;p&gt;
&lt;div align=&quot;center&quot;&gt;
 &lt;img src=&quot;.&#x2F;wireshark-large-client-hello.png&quot; alt=&quot;wireshark-large-client-hello&quot; style=&quot;max-width: 60%;&quot;&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;即便使用纯 PQC, 也只是堪堪减少 32 Bytes, 于事无补.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;xiao-jie&quot;&gt;小结&lt;&#x2F;h2&gt;
&lt;p&gt;读完本文, 我们应该已经熟悉以下术语及相应的流程:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;密钥交换 (Key Exchange, KE)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;密钥协商&lt;&#x2F;strong&gt; (Key Agreement)&lt;&#x2F;li&gt;
&lt;li&gt;密钥传输 (Key Transport)&lt;&#x2F;li&gt;
&lt;li&gt;Diffie-Hellman (&lt;strong&gt;DH&lt;&#x2F;strong&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;椭圆曲线 Diffie-Hellman (&lt;strong&gt;ECDH&lt;&#x2F;strong&gt;)
&lt;ul&gt;
&lt;li&gt;Curve25519, &lt;strong&gt;X25519&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;secp256r1 (NIST &lt;strong&gt;P-256&lt;&#x2F;strong&gt;), etc.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;临时 Diffie-Hellman (&lt;strong&gt;DHE&lt;&#x2F;strong&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;完全前向保密 (Perfect Forward Secrecy, PFS)&lt;&#x2F;li&gt;
&lt;li&gt;后量子安全; 密钥封装机制 (Key Encapsulation Mechanism, KEM)
&lt;ul&gt;
&lt;li&gt;ML-KEM (Module-Lattice-based KEM)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;混合密钥交换 (Hybrid Key Exchange)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        <summary type="html">本文介绍了密钥交换的基本概念, 着重介绍了 TLS 1.3 中使用的 (EC)DH 密钥交换协议, 以及后量子加密参与的混合密钥交换方案.</summary>
        </entry><entry xml:lang="zh">
        <title>从零开始了解 TLS 1.3 系列笔记 (四) —— 实用密码学之「HMAC、HKDF 与安全随机数」</title>
        <published>2025-09-15T00:00:00+00:00</published>
        <updated>2025-09-15T00:00:00+00:00</updated>
        <author>
            <name>Hantong Chen</name>
        </author>
        <link rel="alternate" href="https://i.han.rs/blog/25-09-15-tls-series-cryptography-3/" type="text/html"/>
        <id>https://i.han.rs/blog/25-09-15-tls-series-cryptography-3/</id>
        
            <content type="html">&lt;h2 id=&quot;dao-yu&quot;&gt;导语&lt;&#x2F;h2&gt;
&lt;p&gt;MAC (Message Authentication Code, 消息认证码)、HMAC (Hash-based MAC, 哈希消息认证码)和 KDF (&lt;strong&gt;Key Derivation&lt;&#x2F;strong&gt; Function, &lt;strong&gt;密钥派生&lt;&#x2F;strong&gt;函数) 在密码学中发挥着重要作用. 让我们解释一下何时需要 MAC, 如何计算 HMAC 以及它与 KDF 的关系.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;mac&quot;&gt;MAC&lt;&#x2F;h3&gt;
&lt;p&gt;MAC 由给定密钥和消息计算而来:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;MAC = f(key, message)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;通常, 它的表现类似于加密哈希函数:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;难以分析&lt;&#x2F;strong&gt;: 密钥或消息的微小变化会生成完全不同的 MAC 值.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;不可逆&lt;&#x2F;strong&gt;: 从其哈希值逆向演算出输入值应该是不可行的. 这意味着没有比暴力破解更好的破解方法.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;抗碰撞&lt;&#x2F;strong&gt;: 几乎不可能找到具有相同哈希值的两条不同消息.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;例如, MAC 码可以通过 HMAC-SHA256 算法计算, 如下所示:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;HMAC-SHA256(&amp;#39;key&amp;#39;, &amp;#39;some msg&amp;#39;) = 32885b49c8a1009e6d66662f8462e7dd5df769a7b725d1d546574e6d5d6e76ad
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;MAC 码是&lt;em&gt;数字真实性代码&lt;&#x2F;em&gt; (digital authenticity code), 类似于数字签名 (digital signature), 但具有预共享密钥 (pre-shared key).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;mac-suan-fa&quot;&gt;MAC 算法&lt;&#x2F;h3&gt;
&lt;p&gt;包括但不限于:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;HMAC&quot;&gt;HMAC&lt;&#x2F;a&gt; (Hash-based MAC, 哈希消息认证码), 如 HMAC-SHA256;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.cryptosys.net&#x2F;manapi&#x2F;api_kmac.html&quot;&gt;KMAC&lt;&#x2F;a&gt; (Keccak-based MAC, 基于 Keccak 的消息认证码);&lt;&#x2F;li&gt;
&lt;li&gt;基于对称密码算法的 MAC, 如 &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Poly1305&quot;&gt;&lt;strong&gt;Poly1305&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt; (Bernstein 一次性身份验证) 等等.&lt;&#x2F;li&gt;
&lt;li&gt;其他, 如 &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;SipHash&quot;&gt;SipHash&lt;&#x2F;a&gt; (一种快速的、加密的哈希函数, 适用于哈希表).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;mac-zhu-yao-ying-yong&quot;&gt;MAC 主要应用&lt;&#x2F;h3&gt;
&lt;p&gt;MAC 码主要用于验证消息未被篡改. 如当通信双方持有相同的共享密钥时, 发送方可以计算消息的 MAC 码并将其附加到消息中; 接收方收到消息后, 使用相同的密钥计算消息的 MAC 码, 并将其与附加的 MAC 码进行比较; 如果两个 MAC 码匹配, 则消息被认为是完整且未被篡改的.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ren-zheng-jia-mi-authenticated-encryption-ae&quot;&gt;认证加密 (Authenticated Encryption, AE)&lt;&#x2F;h3&gt;
&lt;p&gt;使用 MAC 码的另一种场景是认证加密.&lt;&#x2F;p&gt;
&lt;p&gt;加密方:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;首先, 我们派生一密钥.&lt;&#x2F;li&gt;
&lt;li&gt;使用该密钥加密消息.&lt;&#x2F;li&gt;
&lt;li&gt;使用该密钥和&lt;strong&gt;原始消息&lt;&#x2F;strong&gt;计算 MAC 码, 并将其附加到第二步的输出中.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;接收方:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;使用一密钥解密密文, 此密钥并不一定是正确的.&lt;&#x2F;li&gt;
&lt;li&gt;使用该密钥和解密结果计算 MAC 码, 并将其与附加的 MAC 码进行比较; 如果两个 MAC 码匹配, 则密钥一致, 解密成功且密文未被篡改; 否则, 密钥不正确或密文被篡改.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;blockquote&gt;
&lt;p&gt;背景知识&lt;&#x2F;p&gt;
&lt;p&gt;可能大家并不熟悉 AE 这个术语, 但 AEAD (Authenticated Encryption with Associated Data, 带关联数据的认证加密) 应该就是熟面孔了. AEAD 是 AE 的一种扩展, 允许在认证加密过程中包含未加密的关联数据 (Associated Data, AD), 如路由信息等需要中间盒处理的信息. 例如, TLS 1.3 中使用的 AES-{128|256}-GCM 和 ChaCha20-Poly1305 都是 AEAD 加密方案, 我们将在介绍对称加密方案时再提到.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;由此, 我们同时验证了通信双方持有相同的共享密钥 (即认证, AE 代表 Authenticated Encryption, 经过认证的加密), 以及消息未被篡改 (完整性).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ji-yu-mac-de-wei-sui-ji-sheng-cheng-han-shu-prf-pseudo-random-function&quot;&gt;基于 MAC 的伪随机生成函数 (PRF, Pseudo-Random Function)&lt;&#x2F;h3&gt;
&lt;p&gt;MAC 码的另一个应用是作 PRF. 我们可以从某个盐和一个随机数(种子)开始.我们可以计算 &lt;code&gt;next_seed&lt;&#x2F;code&gt; 如下:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;next_seed = MAC(salt, seed)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;每次计算上述公式后, 下一个伪随机数都会被 “随机变化”, 我们可以用它来生成一定范围内的下一个随机数.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hmac-he-mi-yao-pai-sheng&quot;&gt;HMAC 和密钥派生&lt;&#x2F;h2&gt;
&lt;p&gt;简单计算 &lt;code&gt;MAC = H(key || msg)&lt;&#x2F;code&gt; 来获取 MAC &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;HMAC#Design_principles&quot;&gt;被认为是不安全的&lt;&#x2F;a&gt;. 建议改用 HMAC 算法, 例如 HMAC-SHA256.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;背景知识&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;大多数哈希函数存在长度拓展攻击, 即在不知道密钥的情况下, 可以通过已知的 &lt;code&gt;H(key || msg)&lt;&#x2F;code&gt; 来计算有效的 &lt;code&gt;H(key || msg || extra)&lt;&#x2F;code&gt;;&lt;&#x2F;li&gt;
&lt;li&gt;计算 &lt;code&gt;MAC = H(msg || key)&lt;&#x2F;code&gt;, 则存在哈希冲突的可能性;&lt;&#x2F;li&gt;
&lt;li&gt;计算 &lt;code&gt;MAC = H(key || msg || key)&lt;&#x2F;code&gt; 仍然被证明是不安全的;&lt;&#x2F;li&gt;
&lt;li&gt;HMAC 计算 &lt;code&gt;HMAC = H(key || H(key || msg))&lt;&#x2F;code&gt;, 采用双重哈希, 消除 msg 长度影响, 目前尚未被证明不安全; 对于 SHA-3 (Keccak) 则不需要双重哈希, 只需 &lt;code&gt;HMAC = H(key || msg)&lt;&#x2F;code&gt;, 因为 SHA-3 不易受长度拓展攻击.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;shen-me-shi-hmac&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;HMAC#Definition&quot;&gt;什么是 HMAC&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;HMAC (Hash-based Message Authentication Code, 哈希消息认证码) 是一种基于哈希函数的 MAC 算法. 它使用一个密钥和一个消息, 通过两次哈希计算得到 MAC 码.&lt;&#x2F;p&gt;
&lt;p&gt;$$\operatorname {HMAC} (K,m)=\operatorname {H} {\Bigl (}{\bigl (}K’\oplus opad{\bigr )}\parallel \operatorname {H} {\bigl (}\left(K’\oplus ipad\right)\parallel m{\bigr )}{\Bigr )}$$&lt;&#x2F;p&gt;
&lt;p&gt;其中:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;$\operatorname {H}$ 是 HMAC 过程所使用的加密哈希函数, 如 SHA-256;&lt;&#x2F;li&gt;
&lt;li&gt;$m$ 是消息;&lt;&#x2F;li&gt;
&lt;li&gt;$K$ 是一个密钥;&lt;&#x2F;li&gt;
&lt;li&gt;$K’$ 是密钥 $K$ 经过右侧补 0 填充或哈希后(必要时右侧补 0)的结果, 以确保其长度等于哈希函数的块大小 (block size);&lt;&#x2F;li&gt;
&lt;li&gt;$ipad$ 和 $opad$ 分别是内填充 (inner padding) 和外填充 (outer padding), 长度与块大小相同, 分别由值为 0x5c, 0x36 的重复字节组成;&lt;&#x2F;li&gt;
&lt;li&gt;$\oplus$ 表示按位异或 (XOR) 操作;&lt;&#x2F;li&gt;
&lt;li&gt;$\parallel$ 表示拼接.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;HMAC 用于验证消息真实性和完整性, 有时还用于密钥派生.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kdf&quot;&gt;KDF&lt;&#x2F;h3&gt;
&lt;p&gt;KDF (Key Derivation Function, 密钥派生函数) 是一种将可变长度密码转换为固定长度密钥的函数:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;key = KDF(password)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;我们可以使用 SHA-256 对密码进行哈希处理, 使用哈希值作密钥, 这就是一个简单的 KDF. 但请不要这样做, 因为它不安全: 简单哈希容易受到字典攻击 (查表法).&lt;&#x2F;p&gt;
&lt;p&gt;为此, 我们可以引入盐 (salt) 执行 HMAC 操作, 此即 &lt;strong&gt;HKDF&lt;&#x2F;strong&gt; (HMAC-based KDF), 具体内容见下文.&lt;&#x2F;p&gt;
&lt;p&gt;使用 HKDF 进行密钥派生不如现代 KDF 安全, 如 PBKDF2, Bcrypt, Scrypt, Argon2 等.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;kdf-cong-mi-ma-huo-mi-yao-pai-sheng-mi-yao&quot;&gt;KDF: 从密码(或密钥)派生密钥&lt;&#x2F;h2&gt;
&lt;p&gt;PBKDF2, Bcrypt, Scrypt, Argon2 等 KDF 函数, 通过引入盐并结合多次迭代来增加密码破解的难度, 迭代过程也称 &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Key_stretching&quot;&gt;key stretching (密钥拉伸)&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;要计算安全的 KDF, 需要一些 CPU 时间来派生密钥 + 一些内存. 因此, 派生密钥是计算成本高昂的, 因此密码破解的尝试也会面临高昂计算成本.&lt;&#x2F;p&gt;
&lt;p&gt;当现代 KDF 与适当的配置参数一起使用时, 破解密码的速度会很慢 (例如, 每秒只能作 5-10 次尝试, 而不是每秒数千或数百万次尝试).&lt;&#x2F;p&gt;
&lt;p&gt;上述现代 KDF 均未申请专利, 可公开使用.&lt;&#x2F;p&gt;
&lt;p&gt;由于本系列主要介绍 TLS 1.3, 因此不再赘述现代 KDF 的细节 (我们只用到了 HKDF), 有兴趣的读者可参考 &lt;a href=&quot;https:&#x2F;&#x2F;practicalcryptography.dev&#x2F;&quot;&gt;Practical Cryptography for Developers Book&lt;&#x2F;a&gt;. 下一节对 HKDF 的介绍, 主要翻译自 &lt;a href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc5869&quot;&gt;RFC 5869&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hkdf-rfc-5869&quot;&gt;HKDF (RFC 5869)&lt;&#x2F;h2&gt;
&lt;p&gt;本文档规定了一个简单的基于 HMAC 的 KDF, 它可以作为各种协议和应用程序中的 (加密) 组件. KDF 旨在支持广泛的应用程序和需求, 并在使用加密哈希函数方面是保守的.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-yin-yan&quot;&gt;1. 引言&lt;&#x2F;h3&gt;
&lt;p&gt;KDF 是加密系统的基本和必要组件. 其目标是获取一些初始密钥材料源, 并从中派生出一个或多个具备强加密强度的密钥.&lt;&#x2F;p&gt;
&lt;p&gt;本文档规定了一个简单的基于 HMAC 的 KDF, 名为 HKDF, 它可以作为各种协议和应用程序中的 (加密) 组件, 并且已经在几个 IETF 协议中使用, 包括 IKEv2、PANA 和 EAP-AKA. 本文档旨在以通用化的方式, 促进其在未来协议和应用中的采纳, 并防止多种 KDF 机制的无序发展. 它不是要求更改现有协议的呼吁, 也不会更改或更新使用此 KDF 的现有规范.&lt;&#x2F;p&gt;
&lt;p&gt;HKDF 遵循 “提取然后扩展” (extract-then-expand) 的范式, 其中 KDF 在逻辑上由两个模块组成. 第一阶段获取输入密钥材料并从中 “提取” 固定长度的伪随机密钥 K. 第二阶段将密钥 K “扩展” 为几个额外的伪随机密钥 (KDF 的输出).&lt;&#x2F;p&gt;
&lt;p&gt;在许多应用程序中, 输入密钥材料不一定均匀分布, 攻击者可能对其有部分了解 (例如, 由密钥交换协议计算的 Diffie-Hellman 值), 甚至对其有部分控制 (如在一些熵收集应用程序中). 因此, “提取” 阶段的目标是将输入密钥材料可能分散的熵 “集中” 到一个短而高强度的&lt;strong&gt;伪随机密钥&lt;&#x2F;strong&gt; (pseudorandom key, &lt;strong&gt;PRK&lt;&#x2F;strong&gt;) 中. 在一些应用程序中, 输入可能已经是一个良好的 PRK; 在这些情况下, “提取” 阶段不是必需的, “扩展” 部分可以单独使用. 第二阶段, 将伪随机密钥 “扩展” 到所需长度; 输出密钥的数量和长度取决于需要密钥的特定加密算法.&lt;&#x2F;p&gt;
&lt;p&gt;请注意, 一些现有的 KDF 规范要么只考虑第二阶段, 要么没有明确区分 “提取” 和 “扩展” 阶段, 经常导致设计缺陷. 本规范的目标是适应广泛的 KDF 需求, 同时最小化对底层哈希函数的假设. 提取然后扩展“ 范式很好地支持了这一目标.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-hkdf&quot;&gt;2. HKDF&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;2-1-fu-hao-xi-tong&quot;&gt;2.1. 符号系统&lt;&#x2F;h4&gt;
&lt;p&gt;HMAC-Hash 表示使用哈希函数 “Hash” 的 HMAC 函数. HMAC 始终有两个参数: 第一个是密钥, 第二个是输入(或消息). (请注意, 在提取步骤中,  IKM 用作 HMAC 输入, 而不是 HMAC 密钥.)&lt;&#x2F;p&gt;
&lt;p&gt;当消息由多个元素组成时, 我们在第二个参数中将其串接 (表示为 |); 例如, HMAC(K, elem1 | elem2 | elem3).&lt;&#x2F;p&gt;
&lt;p&gt;本文档中的关键词 “必须” (“MUST” &#x2F; “SHALL” &#x2F; “REQUIRED”)、“绝不能” (“MUST NOT” &#x2F; “SHALL NOT”), “推荐” (“SHOULD” &#x2F; “RECOMMENDED”)、“不推荐” (“SHOULD NOT” &#x2F; “NOT RECOMMENDED”), “可以&#x2F;可能&#x2F;可选” (“MAY” &#x2F; “OPTIONAL”) 按照 BCP 14, RFC 2119 中的描述进行解释.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;2-2-di-yi-bu-ti-qu-extract&quot;&gt;2.2. 第一步: 提取 (extract)&lt;&#x2F;h4&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;HKDF-Extract(salt, IKM) -&amp;gt; PRK
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;可选:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Hash&lt;&#x2F;code&gt;: 用于 HMAC 的哈希函数, HashLen 是其输出长度 (以字节为单位);&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;入参:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;salt&lt;&#x2F;code&gt;: 可选的随机盐值 (一个非秘密随机值); 如果未提供, 则将其设置为 HashLen 字节的零值;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;IKM&lt;&#x2F;code&gt;: 输入密钥材料 (input key material);&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;输出:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PRK&lt;&#x2F;code&gt;: 输出的长度为 HashLen 字节的伪随机密钥 (pseudorandom key).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;PRK 由以下公式计算:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;PRK = HMAC-Hash(salt, IKM)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;2-3-di-er-bu-kuo-zhan-expand&quot;&gt;2.3. 第二步: 扩展 (expand)&lt;&#x2F;h4&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;HKDF-Expand(PRK, info, L) -&amp;gt; OKM
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;可选:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Hash&lt;&#x2F;code&gt;: 用于 HMAC 的哈希函数, HashLen 是其输出长度 (以字节为单位);&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;入参:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PRK&lt;&#x2F;code&gt;: 伪随机密钥 (pseudorandom key), 长度至少为 HashLen 字节 (通常, 这是由 HKDF-Extract 生成的输出);&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;info&lt;&#x2F;code&gt;: 可选的上下文和应用程序特定信息 (可以是零长度);&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;L&lt;&#x2F;code&gt;: 所需输出密钥材料 (output keying material) 的长度 (以字节为单位); L 必须小于或等于 255 * HashLen;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;输出:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;OKM&lt;&#x2F;code&gt;: 输出的密钥材料 (output keying material), 长度为 L 字节;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;OKM 由以下公式计算:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;N = ceil(L&#x2F;HashLen)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;T = T(1) | T(2) | T(3) | ... | T(N)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;OKM = first L bytes of T
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;其中:&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;T(0) = empty string (zero length)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;T(2) = HMAC-Hash(PRK, T(1) | info | 0x02)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;T(3) = HMAC-Hash(PRK, T(2) | info | 0x03)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;3-hkdf-de-shi-yong-zhu-yi-shi-xiang&quot;&gt;3. HKDF 的使用注意事项&lt;&#x2F;h3&gt;
&lt;p&gt;本节讨论 HKDF 的一些使用注意事项.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;3-1-guan-yu-yan-salt&quot;&gt;3.1. 关于盐 (salt)&lt;&#x2F;h4&gt;
&lt;p&gt;HKDF 被定义为可以在有或没有随机盐值的情况下运行. 这样做是为了适应那些无法获得盐值的应用程序. 然而, 我们强调, 使用盐值可以显著增强 HKDF 的强度, 确保哈希函数不同用途之间的独立性, 支持 “源独立地” 提取, 并强化支持 HKDF 设计的分析结果.&lt;&#x2F;p&gt;
&lt;p&gt;随机盐值与初始密钥材料在两个方面有根本不同: 它不是保密的, 并且可以重复使用. 因此, 许多应用程序都可以应用盐值. 例如, 一个通过将 HKDF 应用于可再生熵池 (例如, 采样的系统事件) 来持续生成输出的伪随机数生成器 (PRNG) 可以固定一个盐值, 并将其用于 HKDF 的多个应用, 而无需保护盐值的秘密性. 在另一个应用领域, 一个从 Diffie-Hellman 交换中导出加密密钥的密钥协商协议可以从通信双方作为密钥协商一部分交换和认证的公开随机数中导出盐值 (这是 IKEv2 中采用的方法).&lt;&#x2F;p&gt;
&lt;p&gt;理想情况下, 盐值是长度为 HashLen 的随机或伪随机字符串. 然而, 即使是质量较低的盐值 (尺寸较短或熵有限) 也可能对输出密钥材料的安全性做出显著贡献; 因此, 鼓励应用程序设计者在应用程序能够获取此类值时, 向 HKDF 提供盐值.&lt;&#x2F;p&gt;
&lt;p&gt;值得注意的是, 虽然不常见, 但某些应用程序甚至可能拥有保密的盐值; 在这种情况下, HKDF 提供了更强的安全保证. 这种应用程序的一个例子是 IKEv1 的 “公钥加密模式”, 其中提取器的 “盐值” 是从秘密随机数计算出来的; 类似地, IKEv1 的预共享模式使用从预共享密钥派生的秘密盐值.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;3-2-guan-yu-info&quot;&gt;3.2. 关于 info&lt;&#x2F;h4&gt;
&lt;p&gt;尽管 “info” 值在 HKDF 的定义中是可选的, 但它在应用程序中通常非常重要. 其主要目标是将派生密钥材料与应用程序和上下文特定的信息绑定. 例如, “info” 可能包含协议号、算法标识符、用户身份等. 特别是, 它可以防止为不同上下文派生相同的密钥材料 (当在这些不同上下文中使用相同的 IKM 时) . 如果需要, 它还可以容纳密钥扩展部分的额外输入 (例如, 应用程序可能希望将密钥材料与其长度 L 绑定, 从而使 L 成为 info 字段的一部分) . “info” 有一个技术要求: 它应该独立于 IKM.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;3-3-tiao-guo-huan-shi-bu-tiao-guo-ti-qu&quot;&gt;3.3. 跳过还是不跳过(提取)&lt;&#x2F;h4&gt;
&lt;p&gt;在某些应用程序中, IKM 可能已经作为密码学强度高的密钥存在 (例如, TLS RSA 密码套件中的预主密钥将是一个伪随机字符串, 除了前两个八位字节) . 在这种情况下, 可以跳过提取部分, 直接使用 IKM 作为扩展步骤中的密钥. 另一方面, 为了与一般情况兼容, 应用程序仍可能使用提取部分. 特别是, 如果 IKM 是随机的 (或伪随机的) , 但比 HMAC 密钥长, 则提取步骤可以用于输出一个合适的 HMAC 密钥 (在 HMAC 的情况下, 通过提取器进行这种缩短并非严格必要, 因为 HMAC 也被定义为可以处理长密钥) . 然而, 请注意, 如果 IKM 是 Diffie-Hellman 值, 如同 TLS 与 Diffie-Hellman 的情况, 则不应跳过提取部分. 这样做将导致使用 Diffie-Hellman 值 g^{xy} 本身 (它不是一个均匀随机或伪随机字符串) 作为 HMAC 的密钥 PRK. 相反, HKDF 应该将提取步骤应用于 g^{xy} (最好带有一个盐值) , 并使用生成的 PRK 作为 HMAC 在扩展部分中的密钥.&lt;&#x2F;p&gt;
&lt;p&gt;在所需的密钥位数 L 不超过 HashLen 的情况下, 可以直接将 PRK 截断获得最终的 OKM. 然而, 不推荐这样做, 特别是因为它会省略在派生过程中使用的 “info” (也不建议将 “info” 作为输入添加到提取步骤中) .&lt;&#x2F;p&gt;
&lt;h4 id=&quot;3-4-du-li-xing-de-zuo-yong&quot;&gt;3.4. 独立性的作用&lt;&#x2F;h4&gt;
&lt;p&gt;KDF 的分析假设 IKM 来自某个源, 该源被建模为特定长度比特流的概率分布 (例如, 由熵池产生的流, 从随机选择的 Diffie-Hellman 指数派生的值等) ; IKM 的每个实例都是该分布中的一个样本. 密钥派生函数的一个主要目标是确保, 当将 KDF 应用于从 (相同) 源分布中抽取的任意两个值 IKM 和 IKM’ 时, 生成的密钥 OKM 和 OKM’ 在本质上是相互独立的 (在统计或计算意义上) . 为了实现这一目标, KDF 的输入必须从适当的输入分布中选择, 并且输入也必须相互独立选择 (从技术上讲, 即使以 KDF 的其他输入为条件, 每个样本也必须具有足够的熵) .&lt;&#x2F;p&gt;
&lt;p&gt;独立性也是提供给 KDF 的盐值的一个重要方面. 虽然没有必要对盐值保密, 并且同一个盐值可以与多个 IKM 值一起使用, 但假定盐值独立于输入密钥材料. 特别是, 应用程序需要确保盐值不是由攻击者选择或操纵的. 例如, 考虑 (如 IKE 中) 盐值是从密钥交换协议中各方提供的随机数派生的情况. 在协议使用此类盐值派生密钥之前, 它需要确保这些随机数被认证为来自合法方, 而不是由攻击者选择的 (在 IKE 中, 例如, 这种认证是经过认证的 Diffie-Hellman 交换的一个组成部分).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4-hkdf-de-ying-yong&quot;&gt;4. HKDF 的应用&lt;&#x2F;h3&gt;
&lt;p&gt;HKDF 旨在用于各种 KDF 应用. 这些应用包括从弱随机性来源获得伪随机性; 在密钥协商协议中从共享的 Diffie-Hellman 值导出加密密钥; 从混合公钥加密方案导出对称密钥; 用于密钥封装机制的密钥导出; 以及更多. 所有这些应用都可以受益于 HKDF 的简洁性和多功能性, 以及其分析基础.&lt;&#x2F;p&gt;
&lt;p&gt;另一方面, 预计某些应用由于特定的操作要求将无法 “按原样” 使用 HKDF, 或者可以使用但无法充分发挥该方案的全部优势. 一个重要的例子是从低熵源 (例如用户密码) 导出加密密钥. HKDF 中的提取步骤可以集中现有熵, 但不能放大熵. 对于基于密码的 KDF, 主要目标是使用两个要素来减缓字典攻击: 一个盐值, 以及有意减慢密钥导出计算. HKDF 自然支持使用盐; 然而, 减速机制并非本规范的一部分. 对基于密码的 KDF 感兴趣的应用应考虑例如 PKCS5 是否比 HKDF 更能满足其需求.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;5-an-quan-zhu-yi-shi-xiang&quot;&gt;5. 安全注意事项&lt;&#x2F;h3&gt;
&lt;p&gt;尽管 HKDF 组成简单, 但在其设计和分析中已考虑了许多安全因素. 对所有这些方面的阐述超出了本文档的范围.&lt;&#x2F;p&gt;
&lt;p&gt;相关论文已投入大量精力, 对 HKDF 作为一种多用途 KDF 进行了密码学分析, 该分析在利用加密哈希函数的方式上非常谨慎. 鉴于我们对当前哈希函数强度的信心有限, 这一点尤为重要. 然而, 这项分析并不意味着任何方案的绝对安全性, 并且它在很大程度上取决于底层哈希函数的强度和建模选择. 尽管如此, 它有力地表明了 HKDF 设计的正确结构及其相对于其他常见 KDF 方案的优势.&lt;&#x2F;p&gt;
&lt;p&gt;(余下内容略去不译)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;an-quan-sui-ji-shu&quot;&gt;安全随机数&lt;&#x2F;h2&gt;
&lt;p&gt;密码学中, 随机性 (熵) 起着非常重要的作用. 在许多算法中, 我们需要随机的 (不可预测的) 数字. 如果这些数字不是不可预测的, 算法就会受到损害.&lt;&#x2F;p&gt;
&lt;p&gt;在计算机科学中, 随机数通常来自伪随机数生成器 (pseudo-random numbers generators, PRNG), 由一些初始随机性初始化, 这些初始随机性一般来自极难预测的用户输入等, 可从操作系统读取, 如 Linux 的 &lt;code&gt;&#x2F;dev&#x2F;random&lt;&#x2F;code&gt;;
在密码学中, 使用安全 PRNG, 称为 CSPRNG, 它通常将熵与 PRNG 和其他技术相结合, 使生成的随机性在密码学意义上不可预测.&lt;&#x2F;p&gt;
&lt;p&gt;应当注意, 获取安全随机数的开销通常是比较大的, 而许多语言提供的随机数生成函数并非 CSPRNG (例如 Python 的 &lt;code&gt;random&lt;&#x2F;code&gt; 库), 而是基于时间戳等可预测的种子获得的伪随机数, 不能用于密码学场景.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;xiao-jie&quot;&gt;小结&lt;&#x2F;h2&gt;
&lt;p&gt;本文介绍了 MAC、HMAC、KDF 和 HKDF 的基本概念及其应用. 除却这四个术语外, 以下再摘抄若干术语、表达式供读者快速回顾:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HMAC = H(key || H(key || msg))&lt;&#x2F;code&gt;;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;AEAD&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;PRK = HKDF-Extract(salt, IKM)&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;OKM = HKDF-Expand(PRK, info, L)&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;在阅读完本文后, 我们应该对上述表达式及相关术语不再陌生.&lt;&#x2F;p&gt;
</content>
        <summary type="html">本文介绍了 MAC (消息认证码)、HMAC (哈希消息认证码) 和 KDF (密钥派生函数), 着重讲解了 HMAC 和 HKDF 的工作原理及其应用场景.</summary>
        </entry><entry xml:lang="zh">
        <title>从零开始了解 TLS 1.3 系列笔记（三）—— 实用密码学之「哈希函数」</title>
        <published>2025-09-14T00:00:00+00:00</published>
        <updated>2026-02-10T00:00:00+00:00</updated>
        <author>
            <name>Hantong Chen</name>
        </author>
        <link rel="alternate" href="https://i.han.rs/blog/25-09-14-tls-series-cryptography-2/" type="text/html"/>
        <id>https://i.han.rs/blog/25-09-14-tls-series-cryptography-2/</id>
        
            <content type="html">&lt;h2 id=&quot;qian-yan&quot;&gt;前言&lt;&#x2F;h2&gt;
&lt;p&gt;在本章中, 我们将介绍哈希函数的基本概念, 以及常见的安全哈希算法. 哈希函数在 TLS 协议中被广泛使用, 例如在数字签名算法、消息认证码 (MAC) 和密钥派生函数 (KDF) 中都有应用.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ha-xi-han-shu-yu-jia-mi-ha-xi-han-shu&quot;&gt;哈希函数与加密哈希函数&lt;&#x2F;h2&gt;
&lt;p&gt;在计算机编程中, 哈希函数将输入不可逆地映射到一个整数. 通常不同的输入映射到不同的输出; 在密码学中, 哈希函数将任意大小的输入数据转换为因算法而异的固定大小的结果, 该结果称为哈希值. 计算机密码学中使用的哈希函数称为 “加密哈希函数”.&lt;&#x2F;p&gt;
&lt;p&gt;对于哈希函数, 我们期待不同输入映射到不同输出, 但由于输入空间无限而输出空间有限, 不可避免地会发生冲突 (也称哈希碰撞); 而对于一个合格的加密哈希函数, 我们要求这个冲突的发生概率非常非常低, 以至于在实际应用中可以忽略不计.&lt;&#x2F;p&gt;
&lt;p&gt;一个理想的加密哈希函数应当具有如下特性:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;确定性&lt;&#x2F;strong&gt;, 即对同样的输入, 应该总是产生同样的输出;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;快速&lt;&#x2F;strong&gt;, 计算速度要足够快;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;难以分析&lt;&#x2F;strong&gt;, 即对输入的任何微小改动, 都应该使输出完全发生变化;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;不可逆&lt;&#x2F;strong&gt;, 即从其哈希值逆向演算出输入值应该是不可行的, 这意味着没有比暴力破解更好的破解方法;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;抗碰撞&lt;&#x2F;strong&gt;, 即几乎不可能找到具有相同哈希值的两条不同消息.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;现代加密哈希函数, 如 SHA-2 和 SHA-3, 都至少在当前已知的攻击方法下满足上述特性.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;jia-mi-ha-xi-han-shu-de-ying-yong&quot;&gt;加密哈希函数的应用&lt;&#x2F;h2&gt;
&lt;p&gt;加密哈希函数有很多应用, 其中最常见的包括:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;数据完整性校验&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;这是加密哈希函数最常见的应用, 此时的哈希值作为 “校验和” (checksum). 例如, 当从互联网下载文件, 下载完毕后计算文件字节流的 SHA256 校验和跟官方公布的一致, 那就说明文件没有损坏.&lt;&#x2F;p&gt;
&lt;p&gt;但需要指出: 哈希函数&lt;strong&gt;自身不能保证文件的真实性&lt;&#x2F;strong&gt;, 目前来讲, 从网上下载的文件的真实性通常是 TLS 协议要保证的, 它确保你看到的网站所公布的「SHA256 校验和」是未被篡改的.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;密码存储&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;加密哈希函数还被用于密码的安全存储, 以避免因直接存储明文密码、而某日数据库泄露导致密码泄露的问题.&lt;&#x2F;p&gt;
&lt;p&gt;应当使用专门设计的安全哈希算法, 如 Scrypt, 计算用户密码的哈希值再持久化保存. 这种算法往往被设计为 CPU 密集和&#x2F;或内存密集的, 以及难以并行化的, 提高单次计算的耗时, 以增加暴力破解的成本.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;唯一 ID&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;将任意长的文件内容哈希化生成一个定长的唯一的 ID, 用以索引等.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;伪随机数生成&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;哈希函数也可以用来生成伪随机数, 例如, 可以将一个随机种子值(从随机事件中收集熵, 如随机的鼠标移动或键盘输入)并附加一个值然后哈希化, 得到一个伪随机数. 可将结果附加一个值再哈希化, 得到另一个伪随机数. Linux 内核的 &lt;code&gt;&#x2F;dev&#x2F;urandom&lt;&#x2F;code&gt; 就是基于此原理实现的.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;工作量证明 (PoW, Proof of Work) 算法&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;略.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;an-quan-ha-xi-suan-fa&quot;&gt;安全哈希算法&lt;&#x2F;h2&gt;
&lt;p&gt;以下简要介绍几种常见的安全哈希算法.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sha-2&quot;&gt;SHA-2&lt;&#x2F;h3&gt;
&lt;p&gt;依据哈希位数, 可分为 SHA-256, SHA-384 和 SHA-512 等若干变体. SHA-2 基于 “Merkle-Damgård 构造” , 目前被认为高度安全.&lt;&#x2F;p&gt;
&lt;p&gt;示例:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;plain&quot; class=&quot;language-plain z-code&quot;&gt;&lt;code class=&quot;language-plain&quot; data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;SHA-256(&amp;#39;hello&amp;#39;) = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;SHA-384(&amp;#39;hello&amp;#39;) = 59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcdb9c666fa90125a3c79f90397bdf5f6a13de828684f
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;SHA-512(&amp;#39;hello&amp;#39;) = 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;sha-3&quot;&gt;SHA-3&lt;&#x2F;h3&gt;
&lt;p&gt;比 SHA-2 更安全, 不容易遭受&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Length_extension_attack&quot;&gt;长度扩展攻击&lt;&#x2F;a&gt;; 在 TLS 1.3 中并未使用.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;blake2-blake3&quot;&gt;BLAKE2 &#x2F; BLAKE3&lt;&#x2F;h3&gt;
&lt;p&gt;BLAKE2 &#x2F; BLAKE3 安全性与 SHA-3 相当, 但针对现代硬件进行高度优化, 哈希速度比 SHA-3 快得多; 在 TLS 1.3 中并未使用.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;qi-ta&quot;&gt;其他&lt;&#x2F;h3&gt;
&lt;p&gt;如中国的商密系列 SM3 &#x2F; SM4 等.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bu-an-quan-de-ha-xi-han-shu&quot;&gt;不安全的哈希函数&lt;&#x2F;h2&gt;
&lt;p&gt;应当避免使用以下被认为不安全或安全性有争议的的哈希算法: MD2、MD4、MD5、SHA-0、SHA-1、Panama、HAVAL (有争议的安全性, HAVAL-128 发现冲突)、Tiger (有争议, 发现弱点)、SipHash (它不是加密哈希函数).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ben-zhang-xiao-jie&quot;&gt;本章小结&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;哈希函数将任意大小的输入数据不可逆地映射为固定大小的结果, 该结果称为哈希值.&lt;&#x2F;li&gt;
&lt;li&gt;加密哈希函数要求映射冲突的发生概率非常低, 以至于在实际应用中可以忽略不计, 保证无法伪造数据和原始数据具备一致的哈希值.&lt;&#x2F;li&gt;
&lt;li&gt;加密哈希函数只能保证数据完整性, 不能保证数据真实性.&lt;&#x2F;li&gt;
&lt;li&gt;现代哈希函数包括 SHA-2, SHA-3, BLAKE2 &#x2F; BLAKE3 等; 应当避免使用 MD5, SHA-1 等被认为不安全的哈希函数.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;bu-fen-can-kao-wen-xian&quot;&gt;部分参考文献&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nakov&#x2F;Practical-Cryptography-for-Developers-Book&quot;&gt;Practical Cryptography for Developers Book&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        <summary type="html">本文介绍了哈希函数的基本概念, 以及常见的安全哈希算法.</summary>
        </entry><entry xml:lang="zh">
        <title>从零开始了解 TLS 1.3 系列笔记（二）—— 实用密码学之「引言」</title>
        <published>2025-09-13T00:00:00+00:00</published>
        <updated>2026-02-10T00:00:00+00:00</updated>
        <author>
            <name>Hantong Chen</name>
        </author>
        <link rel="alternate" href="https://i.han.rs/blog/25-09-13-tls-series-cryptography-1/" type="text/html"/>
        <id>https://i.han.rs/blog/25-09-13-tls-series-cryptography-1/</id>
        
            <content type="html">&lt;h2 id=&quot;qian-yan&quot;&gt;前言&lt;&#x2F;h2&gt;
&lt;p&gt;TLS 协议是一种密码学实践, 其目标如其名曰 “传输层安全”, 在假设完全不可信的信道上提供安全的通信. 这要求 TLS 协议必须满足以下安全目标:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;确保数据不会被中间人获取;&lt;&#x2F;li&gt;
&lt;li&gt;确保数据不被中间人篡改;&lt;&#x2F;li&gt;
&lt;li&gt;确定对端的真实身份, 确保通信双方的身份可信.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;通俗地说, 我们需要维持消息的&lt;strong&gt;机密性&lt;&#x2F;strong&gt; (confidentiality), 以及消息的&lt;strong&gt;真实性&lt;&#x2F;strong&gt; (authenticity)、&lt;strong&gt;完整性&lt;&#x2F;strong&gt; (integrity) 和&lt;strong&gt;不可否认性&lt;&#x2F;strong&gt; (non-repudiation). 为此, TLS 协议使用了大量的密码学算法原语、组件, 如哈希函数, 对称加密算法, 非对称加密算法, 数字签名算法等. 在系统地理解 TLS 协议之前, 我们需要先了解这些密码学基础概念.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;shen-me-shi-mi-ma-xue&quot;&gt;什么是密码学&lt;&#x2F;h2&gt;
&lt;p&gt;密码学 (Cryptography) 是提供&lt;strong&gt;信息安全和保护&lt;&#x2F;strong&gt;的科学. 它在我们的数字世界中无处不在, 当你打开网站时、发送电子邮件时、连接到 WiFi 网络时, 使用账号密码登录 APP 时、使用二步认证验证码认证身份时, 都有涉及到密码学相关技术.
因此, 开发人员应该对密码学有基本的了解, 以避免写出不安全的代码. 至少也得知道如何使用密码算法和密码库, 了解哈希、对称密码算法、非对称密码算法与加密方案这些概念, 知晓数字签名及其背后的密码系统和算法.&lt;&#x2F;p&gt;
&lt;p&gt;以下密码学基础概念(术语)将在本文以及后续文章中频繁出现, 需要熟悉.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;熵 (entropy) 与安全随机数生成器.&lt;&#x2F;li&gt;
&lt;li&gt;哈希函数 (Hash Function, 也称散列函数), 如 MD5, SHA-1, SHA-2 (主要包括 SHA-256, SHA-384, SHA-512 三个变体) 等.&lt;&#x2F;li&gt;
&lt;li&gt;哈希消息认证码 (Hash-based Message Authentication Code, &lt;strong&gt;HMAC&lt;&#x2F;strong&gt;), 如 HMAC-SHA-256.&lt;&#x2F;li&gt;
&lt;li&gt;密钥派生函数 (Key Derivation Function, &lt;strong&gt;KDF&lt;&#x2F;strong&gt;), 如 Scrypt.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;密钥交换&lt;&#x2F;strong&gt;算法 (Key Exchange Algorithm), 如 Diffie-Hellman (DH) 和 ECDH (椭圆曲线 Diffie-Hellman).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;对称密钥加密&lt;&#x2F;strong&gt;方案 (Symmetric key encryption schemes), 如 AES-128-GCM.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;非对称密钥加密&lt;&#x2F;strong&gt;方案 (Asymmetric key encryption schemes), 如 RSA 和 ECC (elliptic curves-based cryptography, 椭圆曲线密码学).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;数字签名算法&lt;&#x2F;strong&gt; (Digital Signature Algorithm, DSA).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;后量子&lt;&#x2F;strong&gt; (Post-Quantum) 安全.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;如果你有过一些开发经验, 可能会很熟悉其中部分名词. 如果不熟也没任何关系, 都会在本系列文章内介绍, 请坐和放宽.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;mi-ma-xue-de-yong-tu&quot;&gt;密码学的用途&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;shang-yu-an-quan-sui-ji-shu&quot;&gt;熵与安全随机数&lt;&#x2F;h3&gt;
&lt;p&gt;熵 (entropy, 指不可预测的随机性) 是密码学的重要部分, 大量算法的安全性都仰赖于具备足够熵的随机数.&lt;&#x2F;p&gt;
&lt;p&gt;计算机无法产生真正的随机数, 只能从外部获得 “真” 随机性:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Linux 系统下的 &lt;code&gt;&#x2F;dev&#x2F;urandom&lt;&#x2F;code&gt; 的随机性来源于硬件中断、按键输入、鼠标移动、磁盘 IO 等不可预测的系统事件;&lt;&#x2F;li&gt;
&lt;li&gt;Cloudflare 使用&lt;a href=&quot;https:&#x2F;&#x2F;www.cloudflare.com&#x2F;zh-cn&#x2F;learning&#x2F;ssl&#x2F;lava-lamp-encryption&#x2F;&quot;&gt;一面熔岩墙&lt;&#x2F;a&gt; 获得真随机性…&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;区别于真随机性, 通过特定算法从一定的随机性种子 (seed) 生成的随机性我们称之为伪随机性, 伪随机性显然由于随机性种子的来源有高低优劣之分. 密码学操作在需求随机性时, 往往要求使用安全伪随机数生成器 (Cryptographically secure pseudo-random number generator, CSPRNG), 基于具备足够熵的随机性种子生成高质量的伪随机数: 通过 CSPRNG 生成的随机数即便攻击者在统计学意义上能收集大量过往产生的随机数进行分析, 或者计算上通过特定手段探知得 CSPRNG 内部状态, 均无法推测出未来的随机数. 而大部分编程语言内置的伪随机数生成器出于性能因素, 在设计上是基于时间戳等可预测性强的随机数种子的, 不具备密码学安全性.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ha-xi-han-shu-yu-hmac&quot;&gt;哈希函数与 HMAC&lt;&#x2F;h3&gt;
&lt;p&gt;哈希函数, 如 MD5、SHA-1、SHA-2, SHA-3 和 BLAKE2 等, 将任意长消息&lt;strong&gt;不可逆地&lt;&#x2F;strong&gt;转换固定长度的哈希值, 称消息摘要 (digest). 哈希函数被设计为几乎不可能找到具有相同哈希值的两条不同消息, 违背这一点的哈希函数被认为是不安全的, 如 MD5 和 SHA-1.&lt;&#x2F;p&gt;
&lt;p&gt;基于哈希函数的特性, 可以将特定哈希函数用于验证消息完整性, 称 HMAC.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kdf&quot;&gt;KDF&lt;&#x2F;h3&gt;
&lt;p&gt;文本密码绝大部分情况下不具备足够的熵, 不能直接作加密密钥. &lt;strong&gt;KDF&lt;&#x2F;strong&gt; (Key Derivation Function, 密钥派生函数) 负责从文本密码安全地派生出具备足够熵的密钥, 且往往还通过注入随机参数 (盐, salt) 和使用大量迭代和计算资源使暴力计算所有可能的密钥变得不可行. 常用的 KDF 包括 PBKDF2、Scrypt 和 Argon2 等.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;mi-yao-jiao-huan&quot;&gt;密钥交换&lt;&#x2F;h3&gt;
&lt;p&gt;密钥交换算法、方案允许通信双方经由完全不可信的信道安全地协商共享密钥. TLS 中使用到的密钥交换算法包括传统 Diffie-Hellman (&lt;strong&gt;DH&lt;&#x2F;strong&gt;) 和基于椭圆曲线的 &lt;strong&gt;ECDH&lt;&#x2F;strong&gt; (Elliptic Curve DH), 以及后量子安全的密钥交换算法 (如 &lt;strong&gt;ML-KEM&lt;&#x2F;strong&gt;).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;jia-jie-mi&quot;&gt;加解密&lt;&#x2F;h3&gt;
&lt;p&gt;密码学自诞生之日起最大用途, 就是进行数据的安全存储和安全传输. 按密钥数量, 可将加密算法分为两类:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;对称 (Symmetric) 加密: 加密和解密&lt;strong&gt;使用相同的密钥&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;如 AES 和 ChaCha20.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;非对称 (Asymmetric) 加密: 加密和解密&lt;strong&gt;使用成对的不同的密钥&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;非对称加密用到的两个密钥在数学上是关联的, 我们称其为 “&lt;strong&gt;密钥对&lt;&#x2F;strong&gt;”; 其中一把密钥公开, 另一把密钥保密, 我们分别称其为 “&lt;strong&gt;公钥&lt;&#x2F;strong&gt;” 和 “&lt;strong&gt;私钥&lt;&#x2F;strong&gt;”; 公钥可以由私钥计算得到, 但反过来则几乎不可能实现.&lt;&#x2F;p&gt;
&lt;p&gt;非对称加密体系也称公钥密码学体系.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;一般而言, &lt;strong&gt;对称加密比非对称加密更快, 但非对称加密更安全&lt;&#x2F;strong&gt;. TLS 等现代加密协议通常会结合使用对称和非对称加密, 以平衡最佳的安全性和性能.&lt;&#x2F;p&gt;
&lt;p&gt;单纯使用加密算法是不够的, 这是因为有的加密算法只能按块进行加密, 而且很多加密算法并不能保证密文的真实性、完整性. 因此, 现实中我们通常会使用一套&lt;strong&gt;加密方案&lt;&#x2F;strong&gt;进行数据的加解密. 加密方案由一系列加密算法、消息认证算法或数字签名算法、块密码模式等多种密码学原语组合得到, 以同时保证数据的安全性、真实性、完整性;加密方案的名称就是使用到的各种密码算法名称的组合, 如 AES-128-GCM、ChaCha20-Poly1305 等. 后面我们再详细了解.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;shu-zi-qian-ming-he-xiao-xi-ren-zheng&quot;&gt;数字签名和消息认证&lt;&#x2F;h3&gt;
&lt;p&gt;密码学当中, 数字签名算法 (Digital Signature Algorithm, DSA) 算法和消息认证 (Message Authentication) 算法提供了对消息真实性、完整性和不可否认性的保证.&lt;&#x2F;p&gt;
&lt;p&gt;DSA 首先是个公钥密码学体系, 大多数数字签名算法使用非对称加密原语: 使用私钥加密特定信息, 此即&lt;strong&gt;签名&lt;&#x2F;strong&gt;; 由相应的公钥解密, 此即&lt;strong&gt;验签&lt;&#x2F;strong&gt; (保证双方持有合法的密钥对).&lt;&#x2F;p&gt;
&lt;p&gt;MAC 跟数字签名的功能实际上是一致的, 区别在于其使用哈希算法 (HMAC), 或者对称加密原语.&lt;&#x2F;p&gt;
&lt;p&gt;现代加密协议通常会结合使用数字签名和消息认证.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hun-yao-yu-kuo-san&quot;&gt;混淆与扩散&lt;&#x2F;h2&gt;
&lt;p&gt;在密码学当中, 香农提出的「混淆」 (confusion) 与「扩散」 (diffusion) 是设计安全密码学算法的两个原则.&lt;&#x2F;p&gt;
&lt;p&gt;「混淆」使密文和对称加密中密钥的映射关系变得尽可能的复杂, 使之难以分析. 如果使用了混淆, 那么输出密文中的每个比特位都应该依赖于密钥和输入数据的多个部分, 确保两者无法建立直接映射.  混淆常用的方法是「替换」与「排列」.&lt;&#x2F;p&gt;
&lt;p&gt;「扩散」将明文的统计结构扩散到大量密文中, 隐藏明文与密文之间的统计学关系. 使单个明文或密钥位的影响尽可能扩大到更多的密文中去, 确保改变输入中的任意一位都应该导致输出中大约一半的位发生变化, 反过来改变输出密文的任一位, 明文中大约一半的位也必须发生变化. 扩散常用的方法是「置换」.&lt;&#x2F;p&gt;
&lt;p&gt;这两个原则被包含在大多数哈希函数、MAC 算法、随机数生成器、对称和非对称密码算法中.&lt;&#x2F;p&gt;
&lt;p&gt;值得指出, “XOR 加密” 的说法本质上是错误的. XOR 操作本身并不提供混淆或扩散.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;guan-yu-ku-de-shi-yong&quot;&gt;关于库的使用&lt;&#x2F;h2&gt;
&lt;p&gt;程序员常自嘲为 Ctrl-C &#x2F; Ctrl-V 工程师, 但在密码学领域反而推荐那么干, 以获得经大量实践验证的当下最优的安全性. 当然, 盲目地从互联网复制粘贴代码也可能会导致安全问题; 曾经安全的代码、算法或者最佳实践, 随着时间的推移也可能变得不再安全.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ben-zhang-xiao-jie&quot;&gt;本章小结&lt;&#x2F;h2&gt;
&lt;p&gt;密码学是一个庞大而复杂的领域, 在后续的文章中, 我们将继续深入探讨 TLS 1.3 协议这一密码学最佳实践. 虽然本章很短, 但不管怎么样, 通过本章内容先建立一个全局观念是极好的.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bu-fen-can-kao-wen-xian&quot;&gt;部分参考文献&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nakov&#x2F;Practical-Cryptography-for-Developers-Book&quot;&gt;Practical Cryptography for Developers Book&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.cloudflare.com&#x2F;zh-cn&#x2F;learning&#x2F;ssl&#x2F;lava-lamp-encryption&#x2F;&quot;&gt;Cloudflare: 熔岩灯如何为 Internet 加密助力？&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        </entry>
</feed>
