<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>密码学系列 - category - 沐木</title><link>https://oldletter.cn/categories/%E5%AF%86%E7%A0%81%E5%AD%A6%E7%B3%BB%E5%88%97/</link><description>密码学系列 - category - 沐木</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Mon, 20 Nov 2023 00:00:00 +0000</lastBuildDate><atom:link href="https://oldletter.cn/categories/%E5%AF%86%E7%A0%81%E5%AD%A6%E7%B3%BB%E5%88%97/" rel="self" type="application/rss+xml"/><item><title>密码学基础：Hash、对称加密、非对称加密</title><link>https://oldletter.cn/posts/crypto-01-fundamentals/</link><pubDate>Thu, 05 Jan 2023 00:00:00 +0000</pubDate><author>mumu</author><guid>https://oldletter.cn/posts/crypto-01-fundamentals/</guid><description><![CDATA[<blockquote>
<p>作者：林 | 系列：密码学 | 适合读者：后端开发 / 对密码学感兴趣的工程师</p></blockquote>
<hr>
<h2 id="一为什么要懂密码学">一、为什么要懂密码学</h2>
<p>作为开发者，你可能每天都在用密码学而不自知：</p>
<ul>
<li>HTTPS 连接 → TLS 握手（非对称 + 对称加密）</li>
<li>用户密码存储 → BCrypt/Argon2（散列函数）</li>
<li>JWT Token → HMAC-SHA256（消息认证码）</li>
<li>支付接口签名 → RSA/SM2（数字签名）</li>
<li>数据库敏感字段 → AES/SM4（对称加密）</li>
</ul>
<p>密码学并非安全团队的专属，重点是每个后端工程师的基本功。本文用下限的篇幅把三大支柱讲清楚，后续每篇深入一个方向。</p>
<hr>
<h2 id="二三大分类总览">二、三大分类总览</h2>
<table>
  <thead>
      <tr>
          <th>能力</th>
          <th>散列函数</th>
          <th>对称密码</th>
          <th>公钥密码</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>主要用途</td>
          <td>完整性、派生、消息认证的组成部分</td>
          <td>数据机密性与认证加密</td>
          <td>密钥协商、签名，部分算法支持加密</td>
      </tr>
      <tr>
          <td>是否可逆</td>
          <td>不可逆</td>
          <td>持有密钥可解密</td>
          <td>取决于具体算法与用途</td>
      </tr>
      <tr>
          <td>密钥</td>
          <td>普通散列无密钥，HMAC 有密钥</td>
          <td>双方共享密钥</td>
          <td>公钥与私钥成对</td>
      </tr>
      <tr>
          <td>常见算法</td>
          <td>SHA-2、SHA-3、SM3</td>
          <td>AES、SM4、ChaCha20</td>
          <td>RSA、ECC、SM2</td>
      </tr>
  </tbody>
</table>
<p>核心区别一句话：</p>
<ul>
<li><strong>Hash</strong>：单向压缩，不能解密，用于验证完整性</li>
<li><strong>对称加密</strong>：一把钥匙，能加能解，用于加密数据</li>
<li><strong>非对称加密</strong>：两把钥匙，公私配对，用于密钥交换和签名</li>
</ul>
<hr>
<h2 id="三散列函数hash">三、散列函数（Hash）</h2>
<h3 id="31-特征">3.1 特征</h3>
<table>
  <thead>
      <tr>
          <th>特征</th>
          <th>说明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>单向性</td>
          <td>从哈希值无法反推出原文</td>
      </tr>
      <tr>
          <td>固定长度</td>
          <td>无论输入多长，输出长度固定</td>
      </tr>
      <tr>
          <td>雪崩效应</td>
          <td>输入改一个 bit，输出变化超过 50%</td>
      </tr>
      <tr>
          <td>抗碰撞</td>
          <td>找到两个不同输入产生相同输出，计算上不可行</td>
      </tr>
  </tbody>
</table>
<h3 id="32-常见算法">3.2 常见算法</h3>
<table>
  <thead>
      <tr>
          <th>算法</th>
          <th>输出长度</th>
          <th>状态</th>
          <th>用途</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>MD5</td>
          <td>128 bit</td>
          <td>❌ 已破解</td>
          <td>仅用于文件校验（非安全场景）</td>
      </tr>
      <tr>
          <td>SHA-1</td>
          <td>160 bit</td>
          <td>❌ 已破解</td>
          <td>不应再使用</td>
      </tr>
      <tr>
          <td>SHA-256</td>
          <td>256 bit</td>
          <td>✅ 安全</td>
          <td>数字签名、证书、区块链</td>
      </tr>
      <tr>
          <td>SHA-3</td>
          <td>可变</td>
          <td>✅ 安全</td>
          <td>SHA-2 的备选方案</td>
      </tr>
      <tr>
          <td>SM3</td>
          <td>256 bit</td>
          <td>✅ 安全</td>
          <td>国密体系，对标 SHA-256</td>
      </tr>
  </tbody>
</table>
<h3 id="33-代码示例">3.3 代码示例</h3>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-java">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title=""><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">java.security.MessageDigest</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// SHA-256</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kt">byte</span><span class="o">[]</span><span class="w"> </span><span class="n">hash</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MessageDigest</span><span class="p">.</span><span class="na">getInstance</span><span class="p">(</span><span class="s">&#34;SHA-256&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">.</span><span class="na">digest</span><span class="p">(</span><span class="s">&#34;hello&#34;</span><span class="p">.</span><span class="na">getBytes</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// SM3（需要 BouncyCastle）</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kt">byte</span><span class="o">[]</span><span class="w"> </span><span class="n">sm3Hash</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MessageDigest</span><span class="p">.</span><span class="na">getInstance</span><span class="p">(</span><span class="s">&#34;SM3&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">.</span><span class="na">digest</span><span class="p">(</span><span class="s">&#34;hello&#34;</span><span class="p">.</span><span class="na">getBytes</span><span class="p">());</span></span></span></code></pre></div></div>
<h3 id="34-典型应用">3.4 典型应用</h3>
<table>
  <thead>
      <tr>
          <th>场景</th>
          <th>做法</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>密码存储</td>
          <td>BCrypt/Argon2（带盐的慢哈希）</td>
      </tr>
      <tr>
          <td>文件完整性校验</td>
          <td>SHA-256 摘要比对</td>
      </tr>
      <tr>
          <td>消息认证（HMAC）</td>
          <td>HMAC-SHA256(key, message)</td>
      </tr>
      <tr>
          <td>数字签名</td>
          <td>先 Hash 再用私钥签 Hash 值</td>
      </tr>
      <tr>
          <td>区块链</td>
          <td>SHA-256 链式哈希</td>
      </tr>
  </tbody>
</table>
<div class="details admonition warning open">
    <div class="details-summary admonition-title">
        <i class="icon fas fa-exclamation" aria-hidden="true"></i>别用 MD5/SHA-1 做安全用途<i class="details-icon fas fa-angle-right" aria-hidden="true"></i>
    </div>
    <div class="details-content">
        <div class="admonition-content">MD5 碰撞攻击成本已低至几秒，SHA-1 也在 2017 年被 Google 实际碰撞。密码存储、签名验证等安全场景，必须用 SHA-256+ 或 SM3。</div>
    </div>
</div>
<hr>
<h2 id="四对称加密symmetric-encryption">四、对称加密（Symmetric Encryption）</h2>
<h3 id="41-原理">4.1 原理</h3>
<p>加密和解密使用<strong>同一把密钥</strong>：</p>]]></description></item><item><title>散列函数：MD5、SHA、SM3 与 HMAC</title><link>https://oldletter.cn/posts/crypto-02-hash/</link><pubDate>Fri, 10 Feb 2023 00:00:00 +0000</pubDate><author>mumu</author><guid>https://oldletter.cn/posts/crypto-02-hash/</guid><description><![CDATA[<blockquote>
<p>作者：林 | 系列：密码学 | 适合读者：后端开发 / 安全工程师</p></blockquote>
<hr>
<h2 id="一什么是散列函数">一、什么是散列函数</h2>
<p>散列函数（Hash Function）将任意长度的输入映射为固定长度的输出，且这个过程<strong>不可逆</strong>。</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-text">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title=""><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">输入（任意长度）       →  散列函数  →  输出（固定长度）
</span></span><span class="line"><span class="cl">&#34;hello&#34;              →  SHA-256  →  2cf24dba5fb0a30e...（64 hex = 256 bit）
</span></span><span class="line"><span class="cl">&#34;hello world&#34;        →  SHA-256  →  b94d27b9934d3e08...（64 hex = 256 bit）
</span></span><span class="line"><span class="cl">整本《红楼梦》(2MB)   →  SHA-256  →  固定 64 hex 字符</span></span></code></pre></div></div>
<h3 id="11-密码学安全散列的四个性质">1.1 密码学安全散列的四个性质</h3>
<table>
  <thead>
      <tr>
          <th>性质</th>
          <th>含义</th>
          <th>被破坏的后果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>单向性</strong>（Preimage Resistance）</td>
          <td>给定 h，找不到 m 使得 H(m)=h</td>
          <td>能从哈希值反推出原文</td>
      </tr>
      <tr>
          <td><strong>第二原像抗性</strong>（Second Preimage）</td>
          <td>给定 m1，找不到 m2≠m1 使得 H(m1)=H(m2)</td>
          <td>能伪造替换文件</td>
      </tr>
      <tr>
          <td><strong>抗碰撞性</strong>（Collision Resistance）</td>
          <td>找不到任意 m1≠m2 使得 H(m1)=H(m2)</td>
          <td>能伪造证书/签名</td>
      </tr>
      <tr>
          <td><strong>雪崩效应</strong>（Avalanche Effect）</td>
          <td>输入改 1 bit，输出至少变化 50%</td>
          <td>能通过输出推测输入特征</td>
      </tr>
  </tbody>
</table>
<hr>
<h2 id="二主流算法对比">二、主流算法对比</h2>
<h3 id="21-算法一览">2.1 算法一览</h3>
<table>
  <thead>
      <tr>
          <th>算法</th>
          <th>输出长度</th>
          <th>分组长度</th>
          <th>结构</th>
          <th>安全状态</th>
          <th>性能（相对）</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>MD5</td>
          <td>128 bit</td>
          <td>512 bit</td>
          <td>Merkle-Damgård</td>
          <td>❌ 碰撞已破解</td>
          <td>速度高</td>
      </tr>
      <tr>
          <td>SHA-1</td>
          <td>160 bit</td>
          <td>512 bit</td>
          <td>Merkle-Damgård</td>
          <td>❌ 碰撞已破解</td>
          <td>快</td>
      </tr>
      <tr>
          <td>SHA-256</td>
          <td>256 bit</td>
          <td>512 bit</td>
          <td>Merkle-Damgård</td>
          <td>✅ 安全</td>
          <td>中</td>
      </tr>
      <tr>
          <td>SHA-512</td>
          <td>512 bit</td>
          <td>1024 bit</td>
          <td>Merkle-Damgård</td>
          <td>✅ 安全</td>
          <td>64位机更快</td>
      </tr>
      <tr>
          <td>SHA-3(256)</td>
          <td>256 bit</td>
          <td>1088 bit</td>
          <td>Sponge（海绵结构）</td>
          <td>✅ 安全</td>
          <td>略慢</td>
      </tr>
      <tr>
          <td>SM3</td>
          <td>256 bit</td>
          <td>512 bit</td>
          <td>Merkle-Damgård</td>
          <td>✅ 安全</td>
          <td>与 SHA-256 相当</td>
      </tr>
      <tr>
          <td>BLAKE3</td>
          <td>256 bit</td>
          <td>64 byte</td>
          <td>Merkle Tree</td>
          <td>✅ 安全</td>
          <td>极快（可并行）</td>
      </tr>
  </tbody>
</table>
<h3 id="22-md5为什么不能再用">2.2 MD5：为什么不能再用</h3>
<p>MD5 的碰撞攻击已经非常成熟：</p>]]></description></item><item><title>对称加密：AES 与 SM4 模式选择指南</title><link>https://oldletter.cn/posts/crypto-03-symmetric/</link><pubDate>Wed, 15 Mar 2023 00:00:00 +0000</pubDate><author>mumu</author><guid>https://oldletter.cn/posts/crypto-03-symmetric/</guid><description><![CDATA[<blockquote>
<p>作者：林 | 系列：密码学 | 适合读者：后端开发 / 安全工程师</p></blockquote>
<hr>
<h2 id="一对称加密基础">一、对称加密基础</h2>
<p>对称加密使用同一把密钥进行加密和解密。当前主流的两个分组密码算法：</p>
<table>
  <thead>
      <tr>
          <th>属性</th>
          <th>AES</th>
          <th>SM4</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>全称</td>
          <td>Advanced Encryption Standard</td>
          <td>国密分组密码算法</td>
      </tr>
      <tr>
          <td>标准</td>
          <td>NIST FIPS 197 (2001)</td>
          <td>GM/T 0002 (2012)</td>
      </tr>
      <tr>
          <td>分组长度</td>
          <td>128 bit</td>
          <td>128 bit</td>
      </tr>
      <tr>
          <td>密钥长度</td>
          <td>128 / 192 / 256 bit</td>
          <td>128 bit</td>
      </tr>
      <tr>
          <td>轮数</td>
          <td>10 / 12 / 14</td>
          <td>32</td>
      </tr>
      <tr>
          <td>结构</td>
          <td>SPN (代换-置换网络)</td>
          <td>非平衡 Feistel</td>
      </tr>
      <tr>
          <td>安全性</td>
          <td>无已知实际攻击</td>
          <td>无已知实际攻击</td>
      </tr>
  </tbody>
</table>
<p>两者安全性等价（AES-128 ≈ SM4），区别在于合规要求：信创项目用 SM4，其他场景用 AES。</p>
<hr>
<h2 id="二加密模式比算法本身更重要">二、加密模式：比算法本身更重要</h2>
<p>分组密码一次只能处理一个固定长度的数据块（16 字节）。当明文超过 16 字节时，<strong>加密模式</strong>决定了如何处理多个分组。</p>
<p>模式选错，算法再强也白搭。</p>
<h3 id="21-ecb千万别用">2.1 ECB：千万别用</h3>
<p>ECB（Electronic Codebook）每个分组独立加密：</p>]]></description></item><item><title>非对称加密与签名：RSA、ECC、SM2</title><link>https://oldletter.cn/posts/crypto-04-asymmetric/</link><pubDate>Thu, 20 Apr 2023 00:00:00 +0000</pubDate><author>mumu</author><guid>https://oldletter.cn/posts/crypto-04-asymmetric/</guid><description><![CDATA[<blockquote>
<p>作者：林 | 系列：密码学 | 适合读者：后端开发 / 安全工程师</p></blockquote>
<hr>
<h2 id="一非对称加密原理">一、非对称加密原理</h2>
<p>对称加密用一把钥匙，非对称加密用一对钥匙：</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-text">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title=""><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">公钥（Public Key）：可以公开，任何人都能拿到
</span></span><span class="line"><span class="cl">私钥（Private Key）：必须保密，只有自己持有
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">加密：用对方的公钥加密 → 只有对方的私钥能解
</span></span><span class="line"><span class="cl">签名：用自己的私钥签名 → 任何人用公钥都能验证</span></span></code></pre></div></div>
<p>非对称加密的数学基础是&quot;单向陷门函数&quot;，正向计算容易，反向计算极难，但持有特定信息（私钥）可以轻松反向。</p>
<hr>
<h2 id="二三大主流算法">二、三大主流算法</h2>
<h3 id="21-rsa">2.1 RSA</h3>
<p>基于<strong>大整数分解难题</strong>：给定两个大素数 p、q，计算 n = p × q 容易；但给定 n，分解出 p 和 q 极难。</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-text">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title=""><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">密钥生成：
</span></span><span class="line"><span class="cl">  1. 选两个大素数 p, q（各 1024 bit）
</span></span><span class="line"><span class="cl">  2. 计算 n = p × q（2048 bit）
</span></span><span class="line"><span class="cl">  3. 计算 φ(n) = (p-1)(q-1)
</span></span><span class="line"><span class="cl">  4. 选择 e（通常 65537），满足 gcd(e, φ(n)) = 1
</span></span><span class="line"><span class="cl">  5. 计算 d = e⁻¹ mod φ(n)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  公钥 = (n, e)
</span></span><span class="line"><span class="cl">  私钥 = (n, d)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">加密：C = M^e mod n
</span></span><span class="line"><span class="cl">解密：M = C^d mod n</span></span></code></pre></div></div>
<p>RSA 的问题：密钥太长。2048 bit 才提供 112 bit 安全强度，4096 bit 才提供 128 bit。</p>]]></description></item><item><title>数字信封与密钥协商：SM2+SM4、ECDH、TLS</title><link>https://oldletter.cn/posts/crypto-05-key-exchange/</link><pubDate>Thu, 25 May 2023 00:00:00 +0000</pubDate><author>mumu</author><guid>https://oldletter.cn/posts/crypto-05-key-exchange/</guid><description><![CDATA[<blockquote>
<p>作者：林 | 系列：密码学 | 适合读者：后端开发 / 安全工程师</p></blockquote>
<hr>
<h2 id="一问题对称密钥怎么安全传递">一、问题：对称密钥怎么安全传递</h2>
<p>对称加密速度快，但面临一个核心问题：通信双方怎么共享同一把密钥？</p>
<table>
  <thead>
      <tr>
          <th>方案</th>
          <th>问题</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>线下交换</td>
          <td>不可能每次通信都见面</td>
      </tr>
      <tr>
          <td>明文传输密钥</td>
          <td>等于没加密</td>
      </tr>
      <tr>
          <td>预共享密钥</td>
          <td>不灵活，N 方通信需要 N×(N-1)/2 个密钥</td>
      </tr>
  </tbody>
</table>
<p>解决方案有两种：</p>
<ul>
<li><strong>数字信封</strong>：用非对称加密传递对称密钥</li>
<li><strong>密钥协商</strong>：双方各出一部分，协商出共享密钥（不传输密钥本身）</li>
</ul>
<hr>
<h2 id="二数字信封">二、数字信封</h2>
<h3 id="21-原理">2.1 原理</h3>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-text">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title=""><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">发送方                                   接收方
</span></span><span class="line"><span class="cl">  │                                       │
</span></span><span class="line"><span class="cl">  │ 1. 随机生成对称密钥 K                   │
</span></span><span class="line"><span class="cl">  │ 2. 用 K 加密业务数据：C = Enc(K, Data) │
</span></span><span class="line"><span class="cl">  │ 3. 用接收方公钥加密 K：EK = Enc(PubB, K)│
</span></span><span class="line"><span class="cl">  │ 4. 发送 (EK, C) ─────────────────────→│
</span></span><span class="line"><span class="cl">  │                                       │
</span></span><span class="line"><span class="cl">  │                 5. 用私钥解密：K = Dec(PriB, EK)
</span></span><span class="line"><span class="cl">  │                 6. 用 K 解密数据：Data = Dec(K, C)
</span></span><span class="line"><span class="cl">  │                                       │</span></span></code></pre></div></div>
<p>好处：</p>]]></description></item><item><title>可搜索加密：加密数据的模糊检索方案</title><link>https://oldletter.cn/posts/crypto-06-searchable-encryption/</link><pubDate>Sun, 10 Sep 2023 00:00:00 +0000</pubDate><author>mumu</author><guid>https://oldletter.cn/posts/crypto-06-searchable-encryption/</guid><description><![CDATA[<blockquote>
<p>作者:lin | 系列:密码学实战</p></blockquote>
<h2 id="一问题背景加密与检索的两难">一、问题背景:加密与检索的两难</h2>
<p>数据库安全的成熟实践是:敏感字段落盘前加密。比如用户的手机号、身份证号、姓名,写入数据库时用 AES 加密成一串乱码。</p>
<p>但业务马上就会遇到一个问题:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-sql">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title=""><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- 加密前,模糊查询很自然
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">users</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="k">LIKE</span><span class="w"> </span><span class="s1">&#39;%张%&#39;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- 加密后,name 字段变成了 &#39;a3f8b2c1d4e5...&#39;,LIKE 完全失效
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">users</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="k">LIKE</span><span class="w"> </span><span class="s1">&#39;%a3f8%&#39;</span><span class="p">;</span><span class="w">  </span><span class="c1">-- 这搜的是密文,不是张三</span></span></span></code></pre></div></div>
<p><strong>直接解密再搜索?</strong> 如果表有 1000 万行,每次查询都要全部解密再逐一比对,响应时间从毫秒级变成分钟级,完全不可接受。</p>
<p><strong>保留明文索引?</strong> 那加密等于白做&ndash;索引泄露的信息量和明文几乎一样。</p>
<p>这就是**可搜索加密(Searchable Encryption, SE)**要解决的核心矛盾:<strong>如何在不暴露明文的前提下,高效地对加密数据做检索?</strong></p>
<div class="details admonition info open">
    <div class="details-summary admonition-title">
        <i class="icon fas fa-info" aria-hidden="true"></i>适用场景<i class="details-icon fas fa-angle-right" aria-hidden="true"></i>
    </div>
    <div class="details-content">
        <div class="admonition-content">可搜索加密不是银弹。它更适合的场景是:数据必须落盘加密(合规要求),同时业务需要检索能力,且可以接受一定程度的信息泄露(比如搜索模式泄露)。如果你的数据完全不需要检索,直接加密存储就好,不需要这些技术。</div>
    </div>
</div>
<h2 id="二四种主流方案对比">二、四种主流方案对比</h2>
<h3 id="方案一桶索引bucket-index">方案一:桶索引(Bucket Index)</h3>
<p><strong>原理:</strong> 直接的思路&ndash;为每个关键词建立一个&quot;桶&quot;,查询时直接定位到桶。</p>]]></description></item><item><title>格式保留加密、同态加密与零知识证明</title><link>https://oldletter.cn/posts/crypto-07-advanced/</link><pubDate>Mon, 20 Nov 2023 00:00:00 +0000</pubDate><author>mumu</author><guid>https://oldletter.cn/posts/crypto-07-advanced/</guid><description><![CDATA[<blockquote>
<p>作者：林 | 系列：密码学 | 适合读者：后端开发 / 对前沿密码学感兴趣的工程师</p></blockquote>
<hr>
<h2 id="一前言">一、前言</h2>
<p>前六篇覆盖了工程中更常用的密码学技术。这篇聊几个&quot;高级货&quot;，它们目前在特定场景已有落地，未来几年会越来越重要：</p>
<table>
  <thead>
      <tr>
          <th>技术</th>
          <th>一句话</th>
          <th>典型场景</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>格式保留加密（FPE）</td>
          <td>加密后格式不变</td>
          <td>数据脱敏、存量系统改造</td>
      </tr>
      <tr>
          <td>同态加密（HE/FHE）</td>
          <td>密文上直接计算</td>
          <td>隐私计算、联邦学习</td>
      </tr>
      <tr>
          <td>零知识证明（ZKP）</td>
          <td>证明我知道但不告诉你</td>
          <td>区块链隐私、身份认证</td>
      </tr>
      <tr>
          <td>后量子密码（PQC）</td>
          <td>抗量子计算机攻击</td>
          <td>未来标准迁移</td>
      </tr>
  </tbody>
</table>
<hr>
<h2 id="二格式保留加密fpe">二、格式保留加密（FPE）</h2>
<h3 id="21-什么是-fpe">2.1 什么是 FPE</h3>
<p>FPE（Format-Preserving Encryption）：加密后的密文与明文<strong>格式完全相同</strong>。</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-text">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title=""><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">普通 AES 加密：
</span></span><span class="line"><span class="cl">  &#34;13800001111&#34; → &#34;a3Kf8bQ2xR7m9p...&#34; （Base64 乱码，长度也变了）
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">FPE 加密：
</span></span><span class="line"><span class="cl">  &#34;13800001111&#34; → &#34;15927463850&#34;       （还是 11 位数字）
</span></span><span class="line"><span class="cl">  &#34;张三&#34;        → &#34;李七&#34;              （还是 2 个汉字）
</span></span><span class="line"><span class="cl">  &#34;320106199001011234&#34; → &#34;410523198712255678&#34; （还是 18 位身份证号格式）</span></span></code></pre></div></div>
<h3 id="22-为什么需要-fpe">2.2 为什么需要 FPE</h3>
<p>存量系统改造时，数据库字段类型、长度、校验规则都不能改。用 AES 加密后字段变成了长 Base64 字符串，需要改表结构、改校验逻辑、改前端展示，改动太大。</p>]]></description></item><item><title>国密实战（一）：SM2 密钥格式与 PFX 证书解析全指南</title><link>https://oldletter.cn/posts/guomi-01-sm2-key-cert/</link><pubDate>Thu, 10 Mar 2022 00:00:00 +0000</pubDate><author>mumu</author><guid>https://oldletter.cn/posts/guomi-01-sm2-key-cert/</guid><description><![CDATA[<blockquote>
<p>作者：林 | 系列：国密实战 | 适合读者：Java 后端/架构师</p></blockquote>
<hr>
<h2 id="一背景与问题">一、背景与问题</h2>
<p>随着《密码法》的实施和信创（信息技术应用创新）要求的推进，越来越多的政府、央企、金融项目要求使用<strong>国密算法</strong>替代 RSA/ECDSA。SM2 作为国密体系中的非对称加密算法，对标 RSA-2048 和 ECDSA P-256，已广泛应用于数字证书、签名验签、密钥交换等场景。</p>
<p>然而，在实际项目中接入 SM2 时，第一个拦路虎往往并非算法本身，重点是，<strong>密钥格式和证书解析</strong>。不同厂商输出的密钥格式不一致（hex、DER、PEM），PFX 证书里封装的 SM2 密钥对解析方式与 RSA 也有差异，稍不注意就会踩坑。</p>
<p>本文将系统梳理 SM2 密钥格式，并给出从 PFX 证书中提取 SM2 公私钥的完整 Java 实现。</p>
<hr>
<h2 id="二sm2-算法简介">二、SM2 算法简介</h2>
<p>SM2 是国家密码管理局发布的椭圆曲线公钥密码算法，标准编号 <strong>GM/T 0003</strong>，包含：</p>
<table>
  <thead>
      <tr>
          <th>部分</th>
          <th>内容</th>
          <th>对标国际标准</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GM/T 0003.1</td>
          <td>总则</td>
          <td>—</td>
      </tr>
      <tr>
          <td>GM/T 0003.2</td>
          <td>数字签名算法</td>
          <td>ECDSA</td>
      </tr>
      <tr>
          <td>GM/T 0003.3</td>
          <td>密钥交换协议</td>
          <td>ECDH</td>
      </tr>
      <tr>
          <td>GM/T 0003.4</td>
          <td>公钥加密算法</td>
          <td>ECIES</td>
      </tr>
      <tr>
          <td>GM/T 0003.5</td>
          <td>参数定义</td>
          <td>—</td>
      </tr>
  </tbody>
</table>
<p>SM2 使用的椭圆曲线参数为 <code>sm2p256v1</code>，其曲线方程为标准 Weierstrass 形式：y² = x³ + ax + b (mod p)。</p>]]></description></item><item><title>国密实战（二）：SM2 签名验签前后端对接全指南</title><link>https://oldletter.cn/posts/guomi-02-sm2-sign-verify/</link><pubDate>Wed, 15 Jun 2022 00:00:00 +0000</pubDate><author>mumu</author><guid>https://oldletter.cn/posts/guomi-02-sm2-sign-verify/</guid><description><![CDATA[<blockquote>
<p>作者：林 | 系列：国密实战 | 适合读者：Java 后端/架构师 + 前端开发者</p></blockquote>
<hr>
<h2 id="一背景与问题">一、背景与问题</h2>
<p>在很多业务场景中，前端需要对请求参数进行签名，后端进行验签，以确保数据完整性和防篡改。传统方案多使用 RSA 签名，但在信创项目中，SM2 签名验签成为必选项。</p>
<p><strong>典型场景</strong>：</p>
<ul>
<li>前端提交表单数据，附带 SM2 签名</li>
<li>后端验签通过后才处理业务逻辑</li>
<li>API 网关层面的请求签名校验</li>
<li>合同/文档电子签章</li>
</ul>
<p>前后端对接 SM2 签名验签的核心挑战：</p>
<ol>
<li><strong>库的选择</strong>：Java 端用什么库？前端用什么库？</li>
<li><strong>密钥格式约定</strong>：私钥和公钥的格式必须统一</li>
<li><strong>userId 的一致性</strong>：SM2 签名有一个独特的 <code>userId</code> 参数，两端必须一致</li>
<li><strong>hash 参数的一致性</strong>：是否对消息做预哈希，两端必须统一</li>
<li><strong>签名格式</strong>：<code>r || s</code> 拼接 vs DER 编码，两端必须约定</li>
</ol>
<p>本文将给出 Java（Hutool）+ TypeScript（sm-crypto）的完整对接方案。</p>
<hr>
<h2 id="二sm2-签名验签原理">二、SM2 签名验签原理</h2>
<h3 id="21-签名过程">2.1 签名过程</h3>
<p>SM2 签名过程比 ECDSA 多了一个 <strong>Z 值</strong>（用户标识哈希）的计算。完整流程如下：</p>
<p><strong>输入参数</strong>：</p>
<ul>
<li>待签名消息 M</li>
<li>用户标识 ID（默认 <code>&quot;1234567812345678&quot;</code>）</li>
<li>私钥 d（256 位整数）</li>
<li>公钥 P = d × G = (xA, yA）</li>
</ul>
<p><strong>步骤</strong>：</p>]]></description></item><item><title>国密实战（三）：SM2+SM4 数字信封完整实现（对接国企实战）</title><link>https://oldletter.cn/posts/guomi-03-sm2-sm4-envelope/</link><pubDate>Thu, 15 Dec 2022 00:00:00 +0000</pubDate><author>mumu</author><guid>https://oldletter.cn/posts/guomi-03-sm2-sm4-envelope/</guid><description><![CDATA[<blockquote>
<p>作者：林 | 系列：国密实战 | 适合读者：Java 后端/架构师</p></blockquote>
<hr>
<h2 id="一背景与问题">一、背景与问题</h2>
<p>在国企、央企、政府项目的接口对接中，数据传输的安全性要求通常采用<strong>数字信封</strong>（Digital Envelope）机制：使用非对称算法加密对称密钥，再用对称密钥加密业务数据。这既保证了密钥传输的安全性，又兼顾了大数据量加密的性能。</p>
<p>在国密体系中，这个组合就是 <strong>SM2 + SM4</strong>：</p>
<ul>
<li><strong>SM4</strong>：对称加密算法，负责加密业务数据（高效）</li>
<li><strong>SM2</strong>：非对称加密算法，负责加密 SM4 密钥（安全）</li>
</ul>
<h3 id="11-为什么需要数字信封">1.1 为什么需要数字信封？</h3>
<table>
  <thead>
      <tr>
          <th>方案</th>
          <th style="text-align: center">安全性</th>
          <th style="text-align: center">性能</th>
          <th>适用场景</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>直接 SM2 加密数据</td>
          <td style="text-align: center">✅ 高</td>
          <td style="text-align: center">❌ 差（数据量受限）</td>
          <td>小数据（如密钥）</td>
      </tr>
      <tr>
          <td>直接 SM4 加密数据</td>
          <td style="text-align: center">❌ 密钥如何安全传输？</td>
          <td style="text-align: center">✅ 好</td>
          <td>需要解决密钥分发问题</td>
      </tr>
      <tr>
          <td><strong>SM2+SM4 数字信封</strong></td>
          <td style="text-align: center">✅ 高</td>
          <td style="text-align: center">✅ 好</td>
          <td><strong>大数据量 + 高安全性</strong></td>
      </tr>
  </tbody>
</table>
<p>SM2 加密的数据长度受限，上限明文长度约为 <strong>256 字节</strong>（受椭圆曲线参数限制）。不适合直接加密业务数据。而 SM4 虽然性能好，但密钥需要安全传输。数字信封完美结合了两者的优势。</p>
<p>SM2 加密数据长度计算：密文长度 = 65（C1，临时公钥点）+ 32（C3，SM3 哈希）+ n = 97 + n bytes。其中 n 为明文长度。加密 16 字节 SM4 密钥时，密文为 97 + 16 = 113 字节。</p>]]></description></item></channel></rss>