ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

可信计算知识地图:从密码学底座到TPM、PCR与远程证明

可信计算知识地图:从密码学底座到TPM、PCR与远程证明

简介:这份文档汇总华中科技大学可信计算线上测试的题目与参考答案,面向网络安全、信息安全课程学习者及备考可信计算相关测验的学生,可用于梳理考点、核对答题思路与查漏补缺。内容围绕可信计算的理论短板、TPM与TSS软件栈、Hash算法、对称与非对称加密、PKI与证书、PCR及平台状态报告等主题展开,既列出MD4、MD5、SHA-1的性质,也对比DES、AES、RC5、Blowfish与RSA、ElGamal、ECC的特点和应用场景。压缩包内为1个docx文件,大小约558KB,便于直接检索和标注复习。当前已有333人学习,适合在课程复习或考前自测时对照题目快速定位知识盲区,也可作为整理可信计算知识框架的参考材料。

1. 从一道反直觉的判断题切入:可信计算的四层知识地图

一份可信计算的卷子里,最容易让人愣住的不是 PCR 扩展公式,而是那种看着像常识的判断题:TPM 能不能挡住系统里的漏洞?答案是不能。这一下就把整门课的边界划出来了——它管的不是「代码有没有漏洞」,而是「这段代码是不是来自可信的一方、平台状态有没有被人动过」。整张地图大致分四层:最底下是 hash、对称与非对称、PKI 这套密码学底座;往上是 TPM 芯片内部的 PCR 与七类密钥;再往上是信任链,从 CRTM 一路量到动态可信度量根;最上面落到证明与应用,本地报告、远程证明,以及虚拟化之后的 vTPM 与回滚。系统学网安方向、正在备考的人,把这四层串成一条线,比零散背四十道题有效得多,因为这套题里几乎每一问,都是这条线上的某个节点被单独拎出来问了一次。

2. 密码学底座:hash、对称非对称与 PKI 的分工表

可信计算整条链子都建在密码学上:PCR 里存的是摘要,AIK 签的是摘要,密封密钥绑定的还是摘要。所以这部分不是背景知识,而是后面所有机制的地基。卷子上这块出得最「平」,几乎全是名词和参数,但恰恰最容易掉以轻心——因为它看起来像背表格,实际上每一条后面都挂着一个「为什么不能用另一个」。

2.1 三代 hash 的取舍:MD4、MD5 与 SHA-1

MD4 是为 32 位字长的处理器设计的,走的是基于 32 位操作数的位操作路线,追求的是在当时的机器上用软件跑得快;MD5 是后来对 MD4 的改进版,输入仍按 512 位分组,输出仍是 4 个 32 位字的级联,结构上和 MD4 一脉相承,代价是复杂度上去了、速度慢了一点,换回来的是抗分析和抗差分能力的提升;SHA-1 的设计原理同样基于 MD4 并大量模仿了它,但输出拉长到 160 bit,因此抗穷举(brute-force)的能力更好。

把这三者放在一张表里看,差别其实只有两个维度:输出长度和设计取向。

算法输入分组输出长度设计取向主要短板
MD4512 位128 位32 位机器上软件实现快抗差分能力弱
MD5512 位128 位比 MD4 复杂,抗分析更好输出偏短,安全边际小
SHA-1512 位160 位抗穷举更强相对更慢

今天这三个算法都已经不再作为安全散列出厂使用,但在 TPM 1.2 的 PCR 里,SHA-1 仍然是标准配置——这正是考点所在。考试问「常见 hash 算法有哪些」,要的不是「哪个还能用」,而是「各自为什么被设计成那样」。答题时把「分组长度、输出长度、改进关系、适用处理器」四个点写全,基本就不会丢分。

提示:MD5 和 SHA-1 的输出长度要用比特写,不要写「32 位」「40 位」——那是十六进制字符数。这个单位错误在填空题里非常常见。

2.2 三条性质:输入敏感、不可逆、抗冲突

hash 算法的性质被归纳成三条,每一条在可信计算里都有明确的落点。

输入敏感,指原始输入发生任何变化,新的 hash 值都应该出现很大变化。这一条是 PCR 扩展能工作的前提:只要被测代码改了哪怕一个字节,扩展进 PCR 的结果就完全不同,攻击者没法「微调」出一个看起来一样的度量值。

不可逆性,指给定明文和算法,在有限时间和有限资源内能算出 hash 值;但给定 hash 值,在有限时间内很难逆推出明文。注意这句话是有方向性的——正向容易、反向困难,缺一半都不算完整表述。这条性质直接支撑了「攻击者无法从当前 PCR 值反推最初状态」的论证。

冲突避免,指很难找到两段内容不同的明文,使它们的 hash 值一致。这里有个容易被忽略的层次:抗冲突其实分弱抗冲突和强抗冲突。弱抗冲突是给定一个 x,找不到另一个 x' 让两者 hash 相同;强抗冲突是任意两段不同明文都撞不上。而按照生日悖论,n 位摘要的实际碰撞强度只有大约 n/2 位,所以 128 位的输出在碰撞意义上只相当于 64 位——这是选择题里最爱设的陷阱。

import hashlib # 1) 输出长度:hexdigest() 返回十六进制字符串,字符数 × 4 = 比特数 print(len(hashlib.md5(b"state-v1").hexdigest())) # 32 个字符 → 128 bit print(len(hashlib.sha1(b"state-v1").hexdigest())) # 40 个字符 → 160 bit # 2) 输入敏感:只把结尾的 1 改成 2,摘要立刻面目全非 a = hashlib.sha1(b"state-v1").hexdigest() b = hashlib.sha1(b"state-v2").hexdigest() print(a[:16]) print(b[:16]) # 3) 不可逆:这里只有正向计算路径,反推没有可行入口

这段代码只做三件事:量输出长度、看雪崩效应、确认单向性。hexdigest()返回的是十六进制字符串而不是字节串,所以要判断比特数得先乘 4;输入用b"..."转成字节,是因为 hash 函数吃的是字节序列而不是字符串。跑一遍再回头看那三条性质,比背定义扎实得多。

2.3 对称与非对称的分水岭:速度、密钥分发与签名场景

对称加密与非对称加密的分界,说到底是「快」和「密钥怎么安全送到对方手里」这两件事没法同时满足。对称算法快,但密钥得先共享;非对称解决了密钥分发和不可否认,但慢。

类型算法关键参数特点典型场景
对称DES56 位密钥速度较快加密大量数据
对称AES(Rijndael)分组密码,替代 DES速度快、安全级别高加密大量数据
对称RC5分组、密钥、轮数均可变以简洁著称参数可变的分组密码场合
对称Blowfish64 位分组、密钥长度可变加密快、紧凑、可变长加密 64 比特长度的字符串
非对称RSA密钥长度足够长安全性基于大整数因数分解数字签名
非对称基于有限域离散对数的算法依赖离散对数难题与密钥交换思路同源公钥加密、电子商业
非对称ECC160 位 ECC ≈ 1024 位 RSA安全强度高、计算量小、密钥与参数小、带宽要求低公钥加密、电子商业

ECC 那一行值得单独记:安全性能更高(160 位 ECC 与 1024 位 RSA、DSA 同级),计算量小、处理速度快(私钥处理速度比 RSA 快得多),存储空间占用小,带宽要求低。这四条不是并列的形容词,而是一条因果链——密钥和系统参数小,所以存储省;参数小所以计算快;计算快所以在受限设备上更合适。

注意:RSA 的表述是「钥匙长度足够长时,加密的信息实际上不能被解破」,不是「数学上已证明安全」。定语写不全,这类题会被判半对。

2.4 PKI 只做一件事:把公钥和身份绑在一起

为什么需要 PKI?因为公钥本身不带身份。你手上有一把公钥,但你不知道它属于谁,就没法判断用它验出来的签名到底是谁签的。PKI 解决的正是这个:证明公钥和身份的对应关系。在这个机制保障的前提下,才谈得上可信赖的网络通信。

证书和公私密钥对的关系可以一句话说清:证书里包含公钥信息,因此可以用来验证私钥产生的签名。私钥签名、公钥验证,这是密钥对能做的事;而「这把公钥属于谁」,是证书额外签上去的一层。两条链路别混:签名验证的是数据完整性加持有人身份,证书验证的是公钥归属。

3. TPM 这颗芯片:总线连接、PCR 扩展与七类密钥

TPM 是这套题里出场频率最高的角色,但它本身其实很朴素——一颗挂在主板上、只会做几件固定事情的芯片。把「接口怎么连」「寄存器怎么变」「密钥谁能保护谁」这三件事分清楚,后面的信任链、证明、回滚才有落脚点。很多人复习到后面越看越乱,根子就在这三件事没拆开。

3.1 芯片形态与 TSS 软件栈

在 CPU 这一侧,TPM 通常的形态是一颗封装为 TSSOP28 的 IC。它既可以是一颗独立的芯片,也可以嵌入到主板上的其他芯片里——比如某些安全芯片方案中,TPM 只是这颗安全芯片的一部分,同一颗芯片还包含指纹扫描和智能读卡器功能。

软件怎么和它说话?固件和操作系统通过访问内存映射寄存器进行交互,CPU 芯片组把这些交互转换成总线命令。也就是说,上层看到的是一段内存地址,底层走的是总线事务,中间由芯片组翻译。

因为 TPM 命令本身比较复杂,规范组织定义了 TSS 软件栈,目的是让程序员更容易使用接口。整条调用链是:需要 TSS 服务的应用链接到提供简化编程接口的库,TSS 把这些高级应用编程接口调用翻译成等价的 TPM 命令并发给设备驱动,设备驱动再把命令送到芯片上。

这条链要能默画出来:应用 → 简化接口库 → TSS → 设备驱动 → TPM 芯片。每一层的职责就一句话,考试问「TSS 的作用」,答「把高级 API 调用转换为等价 TPM 命令」即可。

提示:问到「TPM 与 CPU 的连接方式」,落点是「主板上的芯片,与 CPU 一起集成到 PC 硬件中」。不要展开成总线协议细节,多写不加分。

3.2 PCR 的数量、扩展公式与抗攻击原理

PCR 里存的是平台状态信息的 SHA-1 散列值,所以 PCR 的值能够代表机器的运行状态。数量上,1.1 规范要求至少有 16 个,1.2 规范又额外引进了 8 个用于实现动态可信度量,一共 24 个。这 8 个新增的 PCR 后面会反复出现,先记住它们是「动态」那一半的地盘。

两个操作的权限和时机完全不同,这是最容易被合并成一句话答错的地方:PCR-Reset 只有在机器重新启动或断电时才会执行;PCR-Extend 则是任何具有管理员权限的人在系统运行过程中都能执行。

扩展操作的公式必须会写:

PCR[i] = SHA-1(PCR[i] || newMeasurement)
import hashlib def extend(pcr: bytes, measurement: bytes) -> bytes: """PCR 扩展:旧值与新度量值拼接后再取 SHA-1,输出恒为 20 字节""" return hashlib.sha1(pcr + measurement).digest() pcr17 = b"\xff" * 20 # 动态 PCR 初值:全 1,不是全 0 pcr17 = extend(pcr17, b"secure-loader") # 第一次扩展 pcr17 = extend(pcr17, b"os-kernel") # 第二次扩展,历史被卷进当前值 print(pcr17.hex()) # 40 个十六进制字符

两个参数值得说明:pcr是当前寄存器值,长度固定 20 字节;measurement是本次被测对象的摘要。因为每次扩展都重新做一次 SHA-1,输出长度恒定,TPM 的存储开销就不会随度量次数增长——这是「为什么 TPM 只存摘要」的物理原因。同时,历史状态被不可逆地卷进当前值,任何一次异常都会永久留在后续序列里。

为什么扩展能抵御攻击?三层理由。第一,扩展让每一次系统状态的异常或改变都体现在其后的度量序列里,攻击痕迹难以消除,攻击失去隐匿性。第二,hash 具有单向性,攻击者无法从当前值推断最初状态,也就没法通过「知道初值再往后推」的方式伪造出一致的状态。第三,正因为没法伪造,攻击者想掩盖入侵就只能重置 PCR,而重置只在重启或断电时才发生,动作太大、太显眼。

3.3 密钥家族全景:EK、AIK、SRK 与绑定/密封/迁移

TPM 的密钥有三类参数:通用信息(密钥类型、密钥算法、授权秘密)、特殊信息(密钥长度、密钥数据)、密钥属性(可迁移属性、PCR 值)。密钥类型一共有 7 种。真正要记牢的是下面这几把的定位。

密钥可迁移性关键约束主要用途
EK 签署(背书)密钥不可迁移2048 位 RSA;生产过程中生成;每平台唯一;从不用作数据加密和签名解密所有者授权数据、解密生成 AIK 相关数据、确立平台所有者
SRK 存储根密钥不可迁移每个用户创建时生成;一个 TPM 仅一个;不以明文或密文形式离开 TPM保护所有其他密钥
AIK 身份认证密钥不可迁移每个用户可拥有多个;生成需可信第三方支持对 TPM 产生的数据(功能、PCR 值)签名,证明平台身份与环境配置
Sealing Key 密封密钥不可迁移创建时记录配置值与文件哈希快照;当前值匹配才能解封保护秘密信息
Binding Key 绑定密钥绑定于平台用平台特有密钥加密跨平台加密小规模数据或对称密钥,方便密钥迁移
可迁移密钥可迁移不局限特定平台,由用户控制在平台之间迁移

这张表里有几处因果必须串起来看,否则单个背下来也答不对综合题。

EK 只签名不加密,所以没有任何密钥能用于加密 SRK;而 SRK 又必须被保护,结论只能是 SRK 必须存在 TPM 内部、绝不离开。这一串推理是「为什么 SRK 不可迁移」的标准答法,比直接说「规定如此」有说服力得多。

不可迁移密钥比可迁移密钥更安全,理由有两条:全部由 TPM 内部产生,从产生到销毁的整个周期里私钥部分都不离开 TPM;并且可以被 TPM 签名,从而向用户证明它的不可迁移属性。第二条常被漏掉,但它其实是「安全性如何被外部感知」的关键。

两者不能相互转换,只能由不可迁移密钥单向转化为可迁移密钥——因为安全等级不可迁移密钥更高,反向转化等于降级后再也回不去。方向上记成单向阀就不会错。

自密钥的使用过程是从顶端密钥(通常是 SRK)开始,依次加载各层密钥,包括迁移和不可迁移密钥、签名和绑定密钥,直到所有密钥加载完成。以「把签名密钥加载进 TPM 用于签名」为例,三步是:用私有的 SRK 解密存储密钥 #1 的私钥,用存储密钥 #1 解密存储密钥 #2 的私钥,用存储密钥 #2 解密签名密钥的私钥。子密钥的使用要先获得父密钥的授权,使用前必须先加载,加载方式有绑定 PCR 加载和口令加载两种。

3.4 报告平台状态:本地报告与远程证明的分工

TPM 报告平台状态分两种方式,前提条件完全不同,这是设计上的关键区别。

本地报告的前提是:本地机器可能已经不可信。正因为不能信任本地软件,才要借助 TPM 本身的机制来完成安全报告。具体做法是 Seal 与 Unseal——Seal 把数据或密钥与一个或一组指定的 PCR 值绑定,只有当这些 PCR 的值符合指定值时,数据和密钥才能被释放。也就是说,Seal 把数据的可访问性和机器状态绑在了一起。要判断机器启动是否可信,用户要求 TPM 对这条机密信息执行 Unseal,如果能被释放,说明相应 PCR 值符合期望,进而说明启动过程安全。正常启动之后要销毁这条秘密信息,并扩展 PCR 改变机器状态,确保后来者无法再 unseal——这一步是防重放的后悔药。

远程报告的前提是:验证方在远端,不掌握平台。流程可以拆成六步。

  1. 挑战者向配备 TPM 的客户端请求一次摘要。
  2. 客户端用自身 AIK 对要求的 PCR 值和 nonce 做数字签名。
  3. 客户端把已签名的摘要、AIK 证书以及度量日志一并回传。
  4. 挑战者验证摘要数据块的签名和 nonce,并与第三方 CA 交流验证 AIK 证书的合法性。
  5. 挑战者读取度量日志 SML,其中包含每次度量得到的度量值,模仿 PCR 扩展操作,按扩展的顺序对度量值依次执行扩展,重算出期望的 PCR 值。
  6. 把期望值与客户端返回的值比对,相等则证实客户端环境配置值得信任,据此决定下一步动作。

第 5 步是整条流程的核心,也是最容易被一句话带过的地方:验证方不是「相信」客户端给的 PCR 值,而是拿日志自己重算一遍。nonce 的作用则是保证这次挑战是新鲜的,防止攻击者拿旧的签名摘要来应付。

4. 信任链与度量根:静态根的四个难题、三个缺陷与动态修补

这一章是整门课的重心,也是最容易背串的地方。静态根、动态根、三个缺陷、五个 Locality,四组东西经常被混着考,原因不是记不住,而是没有按「静态根有什么问题 → 哪些缺陷源于此 → 动态根怎么改」这条因果线去组织。

4.1 信任链怎么长出来,日志为什么可以不防篡改

信任传递机制是这样的:在信任当前某一环节的前提下,由该环节去评估下一个环节的安全性,确定下一环节可信之后,再把控制权转交给它,然后依次向后推进。整个启动序列遵循「先度量,再执行」的原则——当前阶段的代码负责度量下一阶段即将执行的代码,把度量值扩展到 PCR 寄存器中,循环往复就构成了信任链。以 TPM 为例,从 CRTM 开始,每一级度量下一级的 hash 值,扩展进 PCR 后再移交控制权,中间还会产生日志。

CRTM 是核心可信度量根,是引导时在平台上执行的第一部分代码,比如现有平台的 BIOS 或 BIOS 引导块,或者下一代平台上的 CPU 程序。它为什么必须不可修改?因为源头在启动过程中没有被度量——这里存在一个假设:这个源头本身是安全可信的。而大多数 PC 系统使用的是可刷写的 BIOS 固件,攻击者有可能通过修改 BIOS 摧毁信任根,所以符合规范的系统必须拥有一段不可更改的 BIOS 代码:它可以是短小的固化 BIOS 代码,由它去度量其余大块的 BIOS,但最初执行的这段必须是固化不可修改的,这就是 CRTM。

如果 CRTM 真的被篡改,后果不是「少了一次度量」,而是整条链失去意义:攻击者可以构造自己的信任链,可以往 PCR 中写入任意值,可以轻易完成远程证明。这句话最好背下来,它是「为什么信任根必须固化」最有分量的答法。

日志的作用和它为什么不用防篡改,是同一个因果的两头。TPM 存储空间有限,不可能存放与运行状态相关的完整信息,只能存其摘要;所以平台状态信息以日志的形式放在 TPM 外部的度量日志文件中,PCR 通过扩展记录这些日志信息的摘要,供以后对日志进行验证。那日志被改了怎么办?即使攻击者篡改了度量日志,由于 PCR 中记录的度量值不可伪造,用户对日志重新求摘要就会发现与度量值不匹配。

注意:这套关系反过来写就全错了。「PCR 存日志、日志要防篡改」是把两个东西对调,是这类题最高频的错

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进