ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

KLJN协议安全密钥交换中随机数生成器统计攻击仿真

KLJN协议安全密钥交换中随机数生成器统计攻击仿真 做物理层信息安全的人肯定绕不开基尔霍夫-洛-约翰逊噪声KLJN安全密钥交换协议。这个名字念出来像一串咒语但它解决的问题非常朴素两个节点在一条被偷听的信道上能不能只靠电阻的热噪声交换一串安全密钥有意思的是理论上可以。但最近我复现了一类很刁钻的攻击——统计随机数生成器攻击攻击对象不是物理层而是协议实现里最容易被忽略的随机源。这篇文章我会把KLJN协议的底子讲透再给出一个完整的Matlab仿真脚本演示攻击者如何利用随机数生成器的统计偏差从公共信道上“猜”出大部分密钥比特。看完你不仅知道协议为什么安全更知道实现中的随机源一旦不干净安全边界会垮得有多快。1. 项目概述KLJN协议与攻击场景1.1 KLJN协议如何工作热噪声与电阻匹配KLJN协议的全称是Kirchhoff-Law-Johnson-Noise核心就是两个物理定律基尔霍夫电路定律以及约翰逊噪声公式。约翰逊噪声就是电阻内部自由电子的热运动产生的随机电压它的功率谱密度只和电阻值R、温度T有关公式是[ S_V(f) 4k_B T R ]其中 (k_B) 是玻尔兹曼常数。这个公式的妙处在于给定温度和电阻噪声功率是确定的但瞬时波形完全随机。KLJN协议的交换过程大致是这样的Alice和Bob之间连接一条公共信道两端各接一个电阻并且各自并联一个噪声源表示热噪声。每个时隙里Alice随机选择一个电阻值低阻 (R_L) 或高阻 (R_H)这个选择对应一个随机比特。Bob也独立做同样的选择。如果两人选择了相同的电阻则两端等效电阻匹配信道上的总噪声功率落在某个确定区间如果选择了不同的电阻等效电阻不匹配总噪声功率落在另一个区间。窃听者Eve虽然能测量信道上的电压或电流但她只能判断“这两个人的电阻是否匹配”却无法判断匹配时具体是“低阻配低阻”还是“高阻配高阻”因为这两种情况在信道上看热噪声统计特性完全一致。于是匹配的时隙就产生一个有效密钥比特不匹配的时隙直接丢弃。这就是KLJN协议的基本逻辑不靠数学困难问题靠物理热噪声和电路的宏观可观测特征来隐藏比特。1.2 随机数生成器攻击的动机与威胁模型KLJN协议在理想条件下是安全的但理想条件包含一条容易被忽略的假设Alice和Bob用来选择电阻的随机源必须产生独立、均匀、不可预测的比特。现实世界没有那么多“理想”。很多原型机用的是伪随机数生成器或者硬件随机源受温度、电压、老化影响输出比特会有统计偏差。这里的威胁模型很有意思。Eve不需要注入任何信号也不需要破解热噪声的物理细节她只需要被动监听信道得到每个时隙“匹配/不匹配”的信息知道或者能够估计Alice和Bob所用随机源的统计偏置利用贝叶斯推断把匹配信息结合随机源偏置还原出密钥比特的概率分布。我用一个生活类比来说明假设Alice和Bob各拿一枚都偏向正面的硬币两人同时掷硬币只告诉旁观者“结果一样”还是“结果不一样”。旁观者听到“结果一样”时他会猜到大概率是“正正”而不是“反反”。如果他听到很多次“结果一样”就能以高于50%的正确率猜出正面正面的次数。KLJN攻击也是同一个套路匹配状态是公开的随机源偏置是可测的匹配时密钥比特的条件分布就不再是均匀的了。2. 统计随机数生成器攻击的原理解读2.1 从匹配率到密钥偏置后验概率推导设Alice选择高阻对应比特1的概率为 (p_A)Bob选择高阻概率为 (p_B)。为简化先讨论最常用的场景Alice和Bob使用同一个型号、同一批次、工作条件相同的随机源所以 (p_A p_B p)。每个时隙的匹配概率为[ P(M1) p^2 (1-p)^2 ]这个概率最小时是 (p0.5)对应0.5当 (p) 偏离0.5时匹配概率会上升。Eve可以统计大量时隙的匹配频率反解出 (p) 的估计值具体公式后面代码里会有。现在关键问题是Eve观测到一个匹配时隙密钥比特到底是1还是0贝叶斯公式直接给出[ P(a1 | M1) \frac{P(a1)P(b1)}{P(M1)} \frac{p^2}{p^2 (1-p)^2} ]如果 (p0.5)这个后验概率正好是0.5Eve没有任何优势。但只要 (p0.5)后验概率就大于0.5。我把几个典型值列出来你感受一下偏差的危害真实偏置 p匹配概率 (p^2(1-p)^2)匹配时猜测密钥位为1的后验概率0.500.5000.5000.550.5050.5990.600.5200.6920.700.5800.8450.800.6800.9410.900.8200.988看到没有哪怕随机源只有5%的偏置攻击者猜中密钥位的概率已经接近60%。如果偏置达到20%正确率超过90%。这在密码学上是非常严重的可区分性密钥的随机性已经名存实亡。2.2 未知偏置的估计策略实际攻击中Eve通常不会预先知道 (p) 的精确值但她不缺样本。每个时隙的匹配/不匹配结果都是公开可观测的假设观察了 (N) 个时隙匹配数为 (N_m)那么匹配频率 (\hat{p}_M N_m / N) 是 (P(M1)) 的极大似然估计。在 (p_Ap_Bp) 的假设下解方程[ 2p^2 - 2p 1 - \hat{p}_M 0 ]得到两个根[ p_{est} \frac{1 \pm \sqrt{2\hat{p}_M - 1}}{2} ]其中大于0.5的根对应偏置偏向1小于0.5的根对应偏置偏向0。Eve如果没有额外信息会面临“左右互搏”的歧义她不知道密钥位更可能是1还是更可能是0。但在工程实现中偏置方向往往是确定的比如某个随机源因为电路设计原因倾向于输出高电平这个信息通过设备型号或芯片手册就能知道。所以我后面的Matlab代码假设攻击者已知偏置方向使用大于0.5的根。如果Alice和Bob的随机源偏置不相同匹配概率公式变成[ P(M1) p_A p_B (1-p_A)(1-p_B) ]单独一个匹配频率输不出 (p_A) 和 (p_B)攻击会更复杂。实际中同一批设备的RNG偏置方向通常一致所以同偏置模型仍然有很强的代表性。3. Matlab仿真实现从协议到攻击的完整代码3.1 仿真架构与变量设计我写这个仿真时有几个设计目标不依赖任何Matlab工具箱、代码可复现、结果直观。整体流程分五步设定物理层参数包括低阻、高阻、温度这些参数会在注释里说明但仿真主体不展开噪声波形的生成。生成Alice和Bob的带偏置随机比特模拟双方RNG统计缺陷。计算每个时隙的匹配状态提取匹配时的密钥比特这一步对应Eve能观察到的公开信息。Eve根据匹配频率估计 (p)然后计算后验概率做出最大后验猜测。扫描不同 (p) 值画出攻击正确率和后验概率曲线。我用的随机比特生成逻辑是rand(1, nSlots) p这样会以概率 (p) 生成逻辑值1以 (1-p) 生成逻辑值0。用固定种子rng(2025)保证任何人在任何机器上跑出来的结果一致。3.2 核心代码与逐段说明下面是完整的Matlab脚本直接保存成KLJN_statistical_RNG_attack_demo.m就能跑。%% KLJN_statistical_RNG_attack_demo.m % 对KLJN安全密钥交换协议的统计随机数生成器攻击仿真 % 场景Alice/Bob的随机源有相同偏置Eve只观测匹配/不匹配状态 % 平台Matlab R2020b 及以上版本 clc; clear; close all; %% 1. 物理层参数用于描述KLJN信道背景 RL 1e3; % 低阻值单位欧姆 RH 10e3; % 高阻值单位欧姆 T 300; % 温度单位开尔文 kB 1.380649e-23; % 玻尔兹曼常数 % 这些参数在完整物理仿真中决定噪声功率差 % S_VL 4*kB*T*RLS_VH 4*kB*T*RH % 这里我们直接使用理想匹配观测即Eve总能正确判断match。 %% 2. 随机源参数 nSlots 20000; % 总时隙数 p 0.60; % 真实偏置P(bit1)pAlice和Bob相同 rng(2025); % 固定随机种子保证可复现 %% 3. 生成Alice/Bob的电阻选择比特 a rand(1, nSlots) p; % 1表示选高阻0表示选低阻 b rand(1, nSlots) p; %% 4. 理想信道观测匹配时隙的密钥比特 match (a b); % 逻辑数组1表示匹配0表示不匹配 keyIdx find(match); % 匹配时隙的索引 keyBits a(keyIdx); % 匹配时的密钥比特与b相同 fprintf(匹配时隙数%d有效密钥比特数%d\n, ... sum(match), length(keyBits)); %% 5. 攻击者估计偏置 % 观测匹配频率 pMatchObs mean(match); % 根据 p^2 (1-p)^2 pMatchObs 反解 p if pMatchObs 0.5 delta sqrt(max(2*pMatchObs - 1, 0)); % 防止浮点误差导致负数 p_est_hi (1 delta) / 2; % 大于0.5的根 p_est_lo (1 - delta) / 2; % 小于0.5的根 else error(观测匹配率低于0.5当前模型假设相同偏置请检查数据); end % 攻击者已知该随机源偏置偏向1因此取较大根 p_est p_est_hi; %% 6. 贝叶斯后验与最大后验猜测 post1 p_est^2 / (p_est^2 (1 - p_est)^2); if post1 0.5 guess ones(1, length(keyBits)); % 每个匹配位都猜1 else guess zeros(1, length(keyBits)); % 每个匹配位都猜0 end % 计算猜测正确率 acc mean(guess keyBits); fprintf(估计偏置 p_est %.4f\n, p_est); fprintf(匹配时后验 P(a1|match) %.4f\n, post1); fprintf(密钥猜测正确率 %.4f\n, acc); %% 7. 扫描不同偏置水平观察攻击效果 pList 0.5:0.02:0.9; accList zeros(size(pList)); postList zeros(size(pList)); for k 1:length(pList) pCur pList(k); aCur rand(1, nSlots) pCur; bCur rand(1, nSlots) pCur; mCur (aCur bCur); keyCur aCur(mCur); pMatchCur mean(mCur); deltaCur sqrt(max(2*pMatchCur - 1, 0)); pEstCur (1 deltaCur) / 2; % 假定偏置偏向1 postCur pEstCur^2 / (pEstCur^2 (1 - pEstCur)^2); if postCur 0.5 guessCur ones(1, length(keyCur)); else guessCur zeros(1, length(keyCur)); end accList(k) mean(guessCur keyCur); postList(k) postCur; end %% 8. 可视化 figure(Color, w, Position, [100 100 900 380]); subplot(1, 2, 1); plot(pList, accList, bo-, LineWidth, 1.5); xlabel(真实偏置 p); ylabel(密钥猜测正确率); ylim([0.4 1]); grid on; title(统计攻击正确率随偏置变化); subplot(1, 2, 2); plot(pList, postList, r^-, LineWidth, 1.5); xlabel(估计偏置 p_{est}); ylabel(后验概率 P(a1|match)); ylim([0.4 1]); grid on; title(贝叶斯后验随偏置变化);运行这段代码你会看到类似这样的输出匹配时隙数10403有效密钥比特数10403 估计偏置 p_est 0.6007 匹配时后验 P(a1|match) 0.6931 密钥猜测正确率 0.6931当真实偏置 (p0.6) 时攻击者能猜中约69.3%的密钥位。这个结果比随机猜的50%高出一大截而且在密码协议里哪怕只有1%的优势都算是泄漏。下图里的右半部分曲线也验证了理论推导随着偏置增大后验概率单调逼近1。3.3 为什么固定猜1是最优策略有读者会问既然后验概率是0.69为什么不以0.69的概率随机猜1、以0.31的概率随机猜0而是全部猜1原因是最大后验准则。当 (post1 0.5) 时猜测“1”的期望正确率就是 (post1)猜测“0”的期望正确率是 (1-post1)。逐位比较固定猜1是最优的。所以正确率恰好等于后验概率这不是巧合而是贝叶斯决策的必然结果。如果偏置方向弄反了取成了 (p_est_lo)后验概率会小于0.5最优决策就变成全部猜0正确率反而接近 (1-post1)。实际攻击里方向信息一般来自硬件设计、芯片手册或对手中随机数生成器的黑盒测试不是没法拿到。4. 仿真结果与安全性评估4.1 不同时隙数对攻击到底有什么影响我在初学这个攻击时有一个误解以为把仿真时隙数调大攻击正确率会不断提高。实际跑下来才发现逐位猜测的正确率由真实偏置 (p) 决定增加时隙数并不会改变这个值。那增加样本有什么好处它只提升了对 (p) 的估计精度。也就是说时隙数越多Eve越能确信自己估计的偏置接近真实值但她对每个密钥位的“猜测优势”不会因此变大。举个例子真实偏置 (p0.55)理论上最优正确率约为0.599。哪怕你把时隙数从2万增加到200万正确率还是会在0.599附近震荡不会变成0.8。这一点对理解攻击性质很重要统计随机数生成器攻击不是通过大量样本“硬磨”出完整密钥而是在单个密钥位上获得了稳定的概率优势这种优势直接来自随机源的信息熵亏损。那为什么密码协议仍然害怕这种攻击因为实际密钥不会只有几十位往往是128位、256位。如果每个比特都有0.6的正确率整个密钥空间的有效大小就大幅度缩水。比如一个128位密钥按位独立计算攻击者逐位猜测全部正确的概率虽然还是极低但他可以结合完整性校验、消息认证码或后续协议交互用排序和筛选的方式逼近真实密钥。安全性不是“0和1”的绝对崩溃而是信息论意义上的逐步瓦解。4.2 对抗措施与实现底线从这次仿真可以反推出几条非常实用的防御基线。第一随机源必须经过质量把关。不能只看RNG能不能跑出随机数要看它是否均匀、独立、通过统计检验。协议实现里至少要跑一下卡方检验、游程检验有条件就上NIST STS测试套件。硬件随机源如果存在温漂或电压敏感必须在固件里加入在线自检。第二对RNG输出做“去偏”处理。最简单的办法是用哈希函数对随机比特做压缩提取比如SHA-256或更轻量的Toeplitz哈希把偏置比特流映射成近似均匀的比特流。这一步可以把统计攻击的优势压回噪声级别。第三协议后级必须加隐私放大。KLJN交换的是物理层原始密钥哪怕只有微小的偏置残留也要通过双方共同计算的提取器去掉信息泄漏。隐私放大不是可选项而是安全协议的标准配置。第四监控匹配率。如果协议运行环境允许Alice和Bob可以定期统计匹配事件的比例。在理想均匀随机源下匹配率应该在0.5附近波动如果持续显著偏离0.5说明双方至少有一方的随机源出了问题。这个监控指标简单、零额外通信成本特别适合工程部署。5. 常见问题与Matlab实现排查5.1 运行脚本时的典型报错与修复我在不同版本的Matlab上跑过这段代码遇到过几个小问题这里一并列出来。现象可能原因解决办法报错error(观测匹配率低于0.5...)随机种子改变后匹配频率因有限样本低于0.5或者 (p_A \neq p_B)模型不适用检查是否用了固定种子确认仿真场景确实是相同偏置增加时隙数降低波动正确率明显低于理论后验概率偏置方向取反用了p_est_lo而不是p_est_hi检查估计 p 的根选择如果随机源实际偏向0应该取小根不同机器运行结果不一致没有固定rng种子或者Matlab版本差异导致生成器算法不同脚本开头加上rng(2025)如需跨版本一致改用rng(2025,twister)显式指定生成器扫描曲线抖动很大nSlots太小匹配频率估计方差大调大nSlots到至少20000曲线会明显平滑sqrt里出现负数浮点误差导致2*pMatchObs - 1略小于0使用max(..., 0)保护脚本中已经处理5.2 理论后验和仿真正确率对不上怎么办确认代码逻辑后最常见的原因是估计出来的p_est和真实p有偏差。比如固定nSlots2000时匹配频率的波动可能让 (p_{est}) 偏离真实值0.02以上这时理论后验和仿真正确率就会有肉眼可见的差距。解决思路不是调代码而是调样本量。另一个容易踩的坑是后验概率公式用的是真实 (p)而仿真中的acc是有限样本下的平均正确率。当keyBits数量够多时两者会收敛。如果差很多大概率是猜测策略选错了比如在post1 0.5时仍然猜1或者没有等号判定的情况。密码学仿真不要嫌琐碎把每一处决策都打印出来一眼就能找到问题。5.3 扩展方向把物理层误判也加进来我给的代码假设Eve对匹配状态判断零误差。实际KLJN信道存在噪声积分时间、采样带宽、环境干扰等限制匹配/不匹配可能误判。想模拟更真实的场景可以在生成match后增加一个误码通道以一定概率翻转match。结果会让估计出的匹配率向0.5收缩攻击优势被削弱但不会完全消失。这个扩展留给感兴趣的读者自己改改动量不大但能加深对物理层和统计层交互的理解。6. 从这次实验想到的几点安全实践我在复现这类攻击时最大的体会是协议的安全证明和实现的安全工程之间隔着一道看不见的“实现鸿沟”。KLJN的物理层安全性设计得再漂亮随机数生成器一颗老鼠屎就能坏掉一锅粥。统计随机数生成器攻击的最大价值不是让你学会一个Matlab脚本而是提醒所有做安全协议的人不要默认随机源是理想的不要把“概率上均匀”当成“实际均匀”更不要在高安全场景里省略随机源质量检测和隐私放大。最后再分享一个小技巧。做这类仿真时把随机种子固定下来同时把p、nSlots、acc打印到日志里你会发现排查问题会快很多。我过去因为没固定种子浪费了好几个小时去对比一组不可能复现的结果。别小看这个习惯它几乎是所有可复现安全实验的起点。
返回列表