这一篇在干嘛?
论文出处:N. Aaraj, A. Raghunathan, N. K. Jha,ACM Transactions on Embedded Computing Systems (TECS) 8(1), Article 8, 2008,共 31 页。 要解决的核心问题:标准的可信计算要求在主板上一颗独立的 Trusted Platform Module(TPM,可信平台模块)芯片,但嵌入式设备既塞不下这颗芯片、也掏不起这颗芯片的钱,于是只能把 TPM 用软件实现(SW-TPM);问题是——电池供电的嵌入式处理器跑得动吗? 作者的软硬件协同划分思路分三层:先把密码算法从 RSA 换成同等安全强度但密钥短得多的 Elliptic Curve Cryptography(ECC,椭圆曲线密码);再剖析 ECC 的计算热点(99.5% 时间花在标量点乘上),用自定义指令把最底层的二元域乘法搬进流水线;最后把点乘按标量位拆分到多核上并行。 主要结论:换成 ECC 后,单条 TPM 命令平均执行时间降 6.51 倍、能耗降 6.75 倍;放到真实应用里(可信启动、VoIP、SSL)平均能耗降 10.75 倍;再加上自定义指令与多核并行,单条命令最高再加速 5.71 倍,而硬件代价只有 30,137 个 NAND 门(约 0.24 mm²,相当于基准处理器面积的 31.72%)。
一、背景:嵌入式设备为什么需要”可信”
先从一个你可能没意识到的变化说起。
二十年前,嵌入式系统大多是”封闭的铁盒子”:跑一段写死在 ROM 里的固件,没有网络,没有第三方应用,能出什么安全问题?但今天,你的智能门锁、车载 T-Box、工业网关、POS 机、智能摄像头,跑的都是完整的 Linux,能通过 Wi-Fi / 4G 联网,还能被远程 OTA 升级。它们同时具备了两件危险的事:
- 软件复杂度暴涨——几百万行代码意味着几千个潜在漏洞;
- 物理上暴露——设备放在楼道里、电线杆上、车底,攻击者可以拆壳、接 JTAG、换 Flash。
Desktop 世界用”杀毒软件 + 打补丁”这套被动防御已经证明是失败的(CERT 的漏洞数量年年增长)。嵌入式设备更惨:它没有算力跑杀软,也没有人记得给它打补丁。
于是产业界提出了另一条路——Trusted Computing(可信计算):不去试图”检测所有坏软件”,而是反过来,先证明这台机器的软件状态是我期望的那个状态,再决定要不要相信它。
一句话区分
传统安全回答”你是谁”(身份认证);可信计算回答”你现在是什么状态”(平台完整性证明)。后者需要硬件配合,因为如果证明者自己就是被攻破的操作系统,它说的任何话都不可信。
可信计算的标准化工作由 Trusted Computing Group(TCG,可信计算组织)推动,落地形态就是主板上一颗单独的 TPM 芯片。它已经被大量笔记本和服务器采用。问题来了:
嵌入式设备加不起这颗芯片。
- 成本:独立的 TPM 芯片、配套的 PCB 面积、BOM 成本、额外的功耗——对一颗售价几美元的 MCU 应用来说不可接受;
- 尺寸:可穿戴设备里每一平方毫米都在打架;
- 功耗:多一颗常电芯片,待机电流就上去了。
TCG 自己也意识到了这个问题,成立了 Mobile Phone Working Group;业界也有 Trusted Mobile Platform 联盟。但方向的共识不等于方案的落地。这篇论文问的就是那个最实际的问题:
把 TPM 的功能搬进嵌入式处理器上运行的软件里(称为 Software TPM,SW-TPM),在执行时间和能耗上到底能不能接受?
注意这个提问方式。作者并没有宣称 SW-TPM 和硬件 TPM 一样安全——它当然不一样,软件实现挡不住探针攻击。作者关心的是一个工程可行性问题:如果代价可以接受,那 SW-TPM 跑在 ARM TrustZone 这类隔离执行域里、用片上内存存密钥,就能在”抗软件攻击 + 有限抗物理攻击”这个档次上,给嵌入式设备带来 80% 的可信计算收益,而成本接近于零。
这就是本文的出发点和全部张力所在:安全想要硬件,成本和面积想要软件,本文用软硬件协同设计把两者捏在一起。
二、TPM 到底是什么:三个信任根与一堆奇怪的缩写
在讨论”软件实现”之前,必须先把 TPM 这个黑盒子拆开。这一节是全篇的地基,初学者的第一个门槛就是 TPM 那一堆缩写。
2.1 三个信任根(Roots of Trust)
TPM 的全部功能都建立在三个”信任根”之上。所谓信任根,就是系统里那一小撮你必须无条件相信、且无法被软件篡改的东西。
| 缩写 | 英文 | 中文 | 干什么 |
|---|---|---|---|
| RTM | Root of Trust for Measurement | 度量信任根 | 负责”测量”平台状态(就是算哈希) |
| RTS | Root of Trust for Storage | 存储信任根 | 安全地存下这些测量结果 |
| RTR | Root of Trust for Reporting | 报告信任根 | 可靠地把测量结果报给外部挑战者 |
加粗理解:RTM 负责”量”,RTS 负责”记”,RTR 负责”说”。完整性证明的完整链条就是:量出来 → 记下来 → 签名报出去。
其中 RTM 里最核心的一小段代码叫 CRTM(Core RTM,核心度量信任根),通常是 bootloader 的第一阶段,上电reset后最先执行、不可被跳过。
2.2 PCR:那个只能”往后卷”的寄存器
RTS 的硬件载体主要是 Platform Configuration Register(PCR,平台配置寄存器)。TPM 里的每个 PCR 只有 20 字节,刚好放一个 SHA-1 摘要。
PCR 有一个非常反直觉但极其关键的性质:你不能直接写它,只能”扩展”(Extend)它。
其中 表示拼接。这个设计的妙处在于:
- PCR 的值成为了一串测量历史的压缩表示,而不仅仅是最后一次测量的结果;
- 由于 SHA-1 不可逆,攻击者即使控制了 PCR 的输入,也无法让 PCR 回到某个特定的历史值;
- 只要有一次测量的顺序或内容不同,最终 PCR 就完全不同。
所以启动时依次”扩展”:bootloader stage2 → 内核镜像 → 内核模块与配置文件 → 应用,最后 PCR 里就凝结了整条启动链的指纹。
2.3 密钥家族:EK / SRK / AIK
TPM 的密钥体系是第二个门槛。三类最重要的非对称密钥:
- EK(Endorsement Key,背书密钥):出厂时由厂商烧进 TPM 的 2048 位 RSA 密钥,是这台设备的”身份证”。私钥永不出 TPM,只用来做两件事:建立所有权、签发 AIK 证书。
- SRK(Storage Root Key,存储根密钥):建立所有权时生成,是一整棵密钥树的根,用来加密那些存在 TPM 外面的可迁移密钥。
- AIK(Attestation Identity Key,身份证明密钥):专门为远程证明而生的 2048 位 RSA 密钥。它的私钥由 TPM 保管,公钥连同证书用来对外做签名和认证。
为什么要绕这么一大圈,不直接用 EK 签名?因为隐私。EK 是设备的唯一身份证,如果每次通信都拿 EK 签名,那所有人都能把你的每一次行为关联到同一台设备——等于终身可追踪。AIK 的作用是:TPM 可以生成任意多个 AIK,每次用不同的假名对外证明”我是一台真 TPM 上的合法平台”,但不暴露是哪一台。
2.4 密封(Seal)与绑定(Bind)
这是 TPM 两个最有用、也最容易被忽略的功能:
- Bind(绑定):用 TPM 的公钥加密数据。解密必须用 TPM 内的私钥 → 数据和这台设备绑定。
- Seal(密封):加密数据的同时,把一组特定的 PCR 值也绑进去。解密时 TPM 会检查当前 PCR 是否和密封时一致,不一致就拒绝解密。
Seal 的威力在于:你可以把磁盘密钥密封在”PCR = 干净启动状态”这个条件上。一旦系统被植入 rootkit,启动链变了,PCR 变了,密钥就永远解不开——数据自己会锁死。
2.5 命令集与 TSS
TPM 对外提供几十条命令,论文按功能分成八类:
| 类别 | 代表命令 | 作用 |
|---|---|---|
| 认证 | TPM_OIAP / TPM_OSAP | 建立会话授权 |
| 能力查询 | TPM_GetCapability | 读取 TPM 自身信息 |
| 密码学 | TPM_Sign、TPM_GetRandom | 签名、取随机数 |
| 身份 | TPM_MakeIdentity、TPM_ActivateIdentity | 生成 AIK、解密 AIK 凭证 |
| 度量 | TPM_PcrRead、TPM_PcrExtend、TPM_Quote | 读/扩展/引用 PCR |
| 所有权 | TPM_TakeOwnership | 建立所有权、生成 SRK |
| 启动 | tpm_init_data、TPM_Startup | 初始化状态 |
| 存储与密钥管理 | TPM_CreateWrapKey、TPM_LoadKey、TPM_EvictKey、TPM_UnBind、TPM_Seal、TPM_Unseal | 密钥生成/加载/驱逐、数据绑定/密封 |
应用程序不直接和 TPM 打交道,中间隔了一层 TCG Software Stack(TSS,TCG 软件栈),负责管理 TPM 资源、给上层提供统一 API。论文用的是开源实现 TrouSerS。
图 1 是整篇论文的总架构图,把上面这些东西的层次关系画清楚了:最上面是应用程序,中间是 TSS 软件栈,下面是 TPM 芯片(或本文的 SW-TPM),内部包含 PCR、RNG、密钥生成器、RSA 引擎、非易失存储等模块。

图 1:可信平台的模块与接口——应用 / TSS 软件栈 / TPM 三层结构,以及 TPM 内部的 PCR、RNG、密钥生成与 RSA 引擎
常见坑:把"可信"当成"安全"
TPM 不保证你的代码没有 bug,也不阻止攻击发生。它只做一件事:诚实地记录和报告平台状态。判断”这个状态是否可接受”是挑战者(远端服务器)的事。很多人第一次接触 TPM 时以为”有了 TPM 就不会被黑”,这是彻底的理解错位。
三、SW-TPM:把 TPM 塞进软件,然后拿电表去量
3.1 软件实现能安全吗?
坦白讲:不能完全等价。软件实现最大的软肋是物理攻击——攻击者读出内存就能拿到私钥,硬件 TPM 的防拆解、防探针、防侧信道设计全都没有了。
但作者给出的答案是分层降级:
- SW-TPM 跑在 CPU 的隔离执行域里(如 ARM TrustZone 的安全世界),普通操作系统被攻破也进不去;
- 密钥放在片上内存(on-chip memory),掉电即失,且不在外部总线上暴露;
- 因此它能挡住软件攻击,以及一部分物理攻击。
代价清楚了,收益也清楚了。接下来唯一的问题就是:它跑得动吗?
3.2 实现细节
作者的 SW-TPM 改编自开源的 TPM Emulator(瑞士 ETH Zurich 的 M. Strasser 项目),作为一个 Linux 内核模块运行。三处关键改动:
- RNG(Random Number Generator,随机数发生器):用 Mersenne Twister(梅森旋转算法)产生输出后再过一遍 SHA-1(称为 hash-complemented),弥补 MT 本身不是密码学安全随机数的缺陷;
- ECC 引擎:在二元域 上实现椭圆曲线,支持 160 / 192 / 224 位密钥;
- AES-CBC 引擎:用于 ECC 加解密,以及解密 AIK 凭证。
关于 ECC 的密钥长度,这里有个初学者必须记住的对照表。ECC 的最大卖点就是同等安全强度下密钥短得多:
| ECC 密钥长度 | 等效 RSA 密钥长度 | 说明 |
|---|---|---|
| 160 位 | 1024 位 | 论文支持 |
| 192 位 | (无直接对应) | 论文支持,因广泛使用而纳入 |
| 224 位 | 2048 位 | 论文支持,TCG 标准要求的安全等级 |
为什么密钥短就快?因为 RSA 的核心运算是模幂,复杂度随密钥位数呈超线性增长;而 ECC 的核心运算是标量点乘,虽然单次运算更复杂,但操作数是 224 位而不是 2048 位,少了近一个数量级。这就是后面所有加速的物理根源。
3.3 实验平台:怎么量一块电池供电的 PDA 的能耗
这是论文里非常值得嵌入式工程师学习的部分——能耗是怎么测出来的。

图 2:硬件与软件实验搭建——Sharp Zaurus PDA 通过 0.1Ω 采样电阻接 5V 直流电源,Agilent 34401A 数字万用表以 25 Hz 采样电压降,PC 端用 MATLAB 梯形积分算能耗
硬件侧:
- 目标机:Sharp Zaurus SL-5600 PDA,400 MHz Intel XScale(PXA-250)处理器,32 MB SDRAM + 64 MB Flash ROM,运行 Embedix + Qtopia;
- 测量链路:在 5V 直流供电线上串联一个 0.1Ω 的采样电阻,用 Agilent 34401A 数字万用表以 25 Hz 的频率采样电阻两端电压降;
- 数据处理:PC 上用 Visual C++ 控制万用表采集,MATLAB 脚本用梯形法则对功率时间序列积分得到能耗。
写成公式就是:
其中 。离散化后:
为什么用串联采样电阻而不是读电池电量计?
电池电量计的分辨率太低、响应太慢,测不出单条命令几十毫秒、几十毫焦的差异。串联小阻值采样电阻 + 高精度万用表是嵌入式能耗测量的经典做法。注意电阻要足够小(不影响供电电压),又要足够大(让电压降落在万用表的有效量程内)。
软件侧:
- SW-TPM 命令取自开源 TPM emulator,从 x86 + Redhat Linux 移植到 PXA-250 + Embedix;
- 移植了 GNU MP 库提供 RSA / HMAC / SHA-1;
- ECC 引擎使用 OpenSSL 的 Big Number(BN)库 + Sun 贡献的 Montgomery 点乘模块;
- 用 TrouSerS(TSS 实现)+ Testsuite(测试用例集)在 x86 Linux PC 上跑通测试,抓取每条命令的输入/输出参数,再把这些参数喂给 PDA 上的 SW-TPM 做测量;
- 为了消除密钥随机性带来的抖动,每条命令重复执行 16 次取平均。
四、第一组实测:RSA 到底有多贵
现在来看硬数据。下表是论文表 I 的整理版,单位:能耗 mJ(毫焦),时间 ms(毫秒)。注意”ECC/RSA”列的形式是 ECC值/RSA值,例如 450/2210 表示 ECC 用 450 mJ、RSA 用 2210 mJ。
4.1 密码学命令与身份命令
| 命令 | 密钥 K (bit) ECC/RSA | 数据 D (B) | 能耗 (mJ) ECC/RSA | 时间 (ms) ECC/RSA |
|---|---|---|---|---|
| TPM_GetRandom | n/a | 20 | 0.55 | 0.19 |
| TPM_Sign | 224/2048 | 20 | 450 / 2210 | 191 / 902 |
| TPM_Sign | 160/1024 | 20 | 210 / 806 | 90 / 343 |
| TPM_Sign | 192/512 | 20 | 321 / 626 | 136 / 265 |
| TPM_ActivateIdentity | 224/2048 | n/a | 598 / 12824 | 348 / 5239 |
| TPM_MakeIdentity | 224/2048 | n/a | 5859 / 70943 | 2425 / 29634 |
4.2 度量、所有权与启动命令
| 命令 | 密钥 K (bit) | 能耗 (mJ) ECC/RSA | 时间 (ms) ECC/RSA |
|---|---|---|---|
| TPM_PcrRead | n/a | 17.32 | 6.69 |
| TPM_PcrExtend | n/a | 32.28 | 12.46 |
| TPM_Quote | 224/2048 | 762 / 2475 | 381 / 1239 |
| TPM_ReadPubek | 224/2048 | 0.31 / 3.10 | 0.12 / 1.22 |
| TPM_TakeOwnership | 224/2048 | 5619 / 66777 | 2391 / 28619 |
| tpm_init_data | 224/2048 | 1.71 / 25.39 | 0.69 / 10.52 |
| TPM_Startup | 224/2048 | 0.48 / 1.46 | 0.19 / 0.58 |
4.3 存储与密钥管理命令
| 命令 | 密钥 K (bit) | 数据 D (B) | 能耗 (mJ) ECC/RSA | 时间 (ms) ECC/RSA |
|---|---|---|---|---|
| TPM_CreateWrapKey | 224/2048 | n/a | 5558 / 42582 | 2322 / 16938 |
| TPM_CreateWrapKey | 160/1024 | n/a | 4128 / 12133 | 1813 / 4594 |
| TPM_EvictKey | 224/2048 | n/a | 8.36 / 37.08 | 3.31 / 14.78 |
| TPM_GetPubKey | 224/2048 | n/a | 640 / 10592 | 229 / 4388 |
| TPM_LoadKey | 224/2048 | n/a | 810 / 14547 | 336 / 5367 |
| TPM_Seal | 224/2048 | 20 | 1103 / 3751 | 463 / 1476 |
| TPM_Unseal | 224/2048 | 256 | 1444 / 14056 | 585 / 5520 |
| TPM_UnBind | 224/2048 | 256 | 1459 / 10480 | 576 / 4103 |
4.4 怎么读这张表
第一个震撼:TPM_MakeIdentity 在 PDA 上要跑 29.6 秒、吃掉 70.9 焦耳的能量。
这是什么概念?一块典型的 PDA 电池大约 15~20 kJ 可用能量。也就是说,生成一次 AIK 就烧掉了电池总量的 0.4%——而这还只是一条命令。TPM_TakeOwnership(建立所有权)是 28.6 秒 / 66.8 J,同一量级。
第二个发现:贵的都是”私钥”操作。 TPM_ReadPubek 只要 1.22 ms(RSA)而 TPM_Sign 要 902 ms。原因很清楚——公钥操作的指数很小(通常是 65537),而私钥操作要对 2048 位的数做模幂,是大数运算的地狱。
第三个发现:开销和 RSA 密钥长度强相关。 看 TPM_CreateWrapKey:RSA-512 是 3025 ms,RSA-1024 是 4594 ms,RSA-2048 直接飙到 16938 ms。基本符合模幂运算 到 的增长规律。
第四个发现:换成 ECC 之后,全都降下来了。 论文给出的平均值是:
- 执行时间平均降低 6.51 倍(摘要中另一处表述为 6.15 倍,取数范围不同)
- 能耗平均降低 6.75 倍
最夸张的是 TPM_CreateWrapKey(2048 位档):从 42582 mJ / 16938 ms 降到 5558 mJ / 2322 ms,能耗降 7.66 倍,时间降 7.29 倍。TPM_MakeIdentity 更是从 70.9 J 降到 5.86 J,降了 12.1 倍。
常见坑:不要把"平均降低 6.75 倍"套用到所有命令上
看 TPM_GetPubKey:640 → 10592 mJ,降了 16.6 倍;而 TPM_Seal 在 192/512 档只从 1019 → 1001 mJ,几乎没降甚至略升。因为 ECC 的绝对开销本就小,当命令里混杂了大量哈希、内存拷贝、AES 操作时,密码算法换代的收益就被摊薄了。优化之前先 profile,这话永远成立。
五、放到真实应用里看:三个场景的代价
单看命令不够,还得看它在完整应用里占多大比例。论文做了三个场景,结果汇总如下表(论文表 II)。注意列的含义是 “非可信应用本身的消耗 / 可信化带来的总开销”。
| 场景 | 算法 | 应用本身 能耗(J) / 时间(s) | 可信化总开销 能耗(J) / 时间(s) | 其中 SW-TPM 命令 能耗(J) / 时间(s) |
|---|---|---|---|---|
| 可信启动 | RSA | 95.542 / 48.281 | 198.759 / 89.495 | 66.806 / 28.657 |
| 可信启动 | ECC | 95.542 / 48.281 | 137.699 / 63.280 | 5.746 / 2.442 |
| VoIP(仅加密) | RSA | 804.246 / 300 | 100.867 / 42.356 | 88.778 / 37.376 |
| VoIP(仅加密) | ECC | 804.246 / 300 | 12.961 / 6.524 | 8.034 / 3.579 |
| VoIP(加密+哈希) | RSA | 804.246 / 300 | 103.612 / 43.121 | 88.778 / 37.376 |
| VoIP(加密+哈希) | ECC | 804.246 / 300 | 14.708 / 7.237 | 8.034 / 3.579 |
| SSL(PDA 做服务端) | RSA | 0.530 / 0.213 | 92.455 / 38.707 | 86.271 / 36.124 |
| SSL(PDA 做服务端) | ECC | 0.530 / 0.213 | 7.652 / 3.387 | 7.250 / 3.186 |
| SSL(PDA 做客户端) | RSA | 0.707 / 0.284 | 2.449 / 1.175 | n/a |
| SSL(PDA 做客户端) | ECC | 0.707 / 0.284 | 0.259 / 0.124 | n/a |
综合起来,在这些真实应用中使用 ECC 替代 RSA,SW-TPM 相关部分平均节能 10.75 倍、平均省时间 10.25 倍。
5.1 可信启动
标准 Linux 启动链被改造成可信版本,每一步都先算哈希再扩展 PCR:
- 上电执行 bootloader stage 1(这一段就是 CRTM,假定可信),激活 SW-TPM 并执行 TPM_Startup,然后哈希 stage 2 并扩展 PCR 4;
- stage 2 加载内核镜像,哈希后扩展 PCR 5;
- 内核哈希预装的内核模块、配置文件、预装应用,扩展 PCR 8。
最后把 PCR 值和”干净启动”时的基准值比对即可判断完整性。
读数据:非可信启动本身是 95.542 J / 48.281 s;用 RSA 的可信启动要额外付 198.759 J / 89.495 s,开销是启动本身的 2.08 倍——相当于开机时间从 48 秒变成 138 秒,用户绝对骂人。换成 ECC 后开销降到 137.699 J / 63.280 s,其中 SW-TPM 命令只占 5.746 J / 2.442 s。
剩下的 132 J 是什么?
是完整性度量本身——也就是对内核镜像、模块、应用做 SHA-1 的能耗。这说明:当密码算法优化完之后,瓶颈从”密码运算”转移到了”哈希大量数据”。这是优化工作里最经典的剧情:解决一个瓶颈,下一个瓶颈就浮出水面。
5.2 安全 VoIP
VoIP(Voice over Internet Protocol,网络电话)面临的威胁包括垃圾呼叫、呼叫劫持、DoS 等。论文的方案是:用 SW-TPM 向服务器证明客户端应用的二进制没被篡改,并安全地交换会话密钥。

图 3:VoIP 通信安全方案——客户端向 PBX 服务器注册并进行平台证明,服务器验证通过后分发用双方 AIK 公钥加密的 AES 会话密钥
完整流程拆成两段:
注册阶段:
- 客户端平台先生成 AIK,并向可信第三方(TTP)申请 AIK 证书。TTP 用背书凭证验证 EK 公钥,再用 EK 验证 AIK,然后签发证书;证书用对称密钥 加密,而 又用 EK 公钥加密。SW-TPM 解密出 ,激活并解密 AIK 凭证。
- 注册时客户端操作系统哈希 VoIP 客户端的二进制,用摘要扩展 PCR 11,并用生成的 AIK 对其签名。把 PCR 11 内容、签名、AIK 证书、平台凭证一起发给服务器。
- 服务器校验证书和签名,把 PCR 11 与已知合法的 VoIP 客户端配置比对,决定注册或拒绝。
通信阶段:
- 客户端 Z 发起呼叫请求;Z 启动时 PCR 11 被重置并重新哈希客户端二进制(这一步很关键——可以检测注册之后到通话之前发生的篡改);
- 服务器向 Z 和 C 双方发送挑战,包含一个 **freshness nonce(新鲜性随机数)**以防御重放攻击;
- 双方 SW-TPM 用注册时的 AIK 对「PCR 11 内容 ‖ nonce」签名,连同凭证回传;
- 服务器验证平台真实性、签名、新鲜性和 PCR 值;通过后建立连接,生成 128 位 AES-CBC 会话密钥,用双方 AIK 公钥分别加密后下发;
- 双方用各自 AIK 私钥解密会话密钥,之后业务流量用 AES-CBC 加密。
读数据:5 分钟的 VoIP 通话,应用本身耗 804.246 J / 300 s。用 RSA 时可信化开销 100.867 J / 42.356 s;换成 ECC 后只有 12.961 J / 6.524 s,降了 7.78 倍。如果还要防篡改(数据加密后再哈希),ECC 方案也只多花 1.7 J 左右。

图 4:VoIP 会话能耗拆分——随通话时长(1/2/5/10 分钟)变化,可信化开销中 SW-TPM 命令、完整性度量、对称加解密三部分的占比
图 4 揭示了一个重要规律:随着通话时间变长,可信化的固定开销被摊薄。因为注册和证明是一次性的,而语音数据的对称加密是持续的。这正是作者在结论里说的——对”TPM 只在建立阶段使用、之后是长时间数据传输”的应用,SW-TPM 的开销是可以接受的。
5.3 安全 Web 浏览
SSL(Secure Sockets Layer,安全套接层)协议有个著名的缺陷:客户端靠证书能确认服务器身份,但无法确认这台服务器上跑的是不是它声称的那个应用。论文的方案是:除了服务器证书,服务端的 SW-TPM 还要生成 AIK、取得 AIK 证书,并用 AIK 私钥签名应用代码的完整性度量值,客户端一并验证。

图 5:可信 Web 浏览方案——在传统 SSL 握手流程中插入 AIK 证书交换与应用完整性证明,只有验证通过后才进入 SSL Record 协议传输数据
读数据:这个场景的对比最刺眼。PDA 当服务端时,RSA 需要 38.707 s 完成握手(用户早跑了),ECC 只要 3.387 s,快了 11.4 倍。PDA 当客户端时,RSA 1.175 s vs ECC 0.124 s,快了 9.5 倍。
六、热点剖析:99.5% 的时间花在一个函数上
到这里,ECC 已经比 RSA 快了 6 倍多。但作者没有停——他们问:ECC-SW-TPM 的时间又花在哪了?
6.1 调用图给出的答案
在 Xtensa 嵌入式处理器上跑 profile,TPM_CreateWrapKey 命令的调用图给出了一个近乎荒谬的结论:

图 6:TPM_CreateWrapKey 命令的调用图——EC_Point_mul 独占 99.54% 的执行时间,其下层是 Montgomery 点乘、GF2m_Madd、GF2m_Mdouble、二元域乘法 BN_GF2m_mul_2x2(占 48.64%)与取模 BN_GF2m_mod_arr
99.54% 的时间在函数 EC_Point_mul 里。 其他 TPM 命令的 profile 结果类似。
这意味着一个极其明确的优化目标:只要把点乘加速 N 倍,整条命令就几乎加速 N 倍。这就是所谓的 Amdahl 定律在实践中的最好情况——热点占比高到几乎不需要考虑串行部分的限制。
6.2 点乘是什么
ECC 里最核心、也最耗时的运算就是 Point Multiplication(点乘,也叫标量乘):
其中 是椭圆曲线 上的一个随机点, 是 中的一个 位标量()。
点乘建立在两个基本操作之上:
- Point Adding(点加):求 ;
- Point Doubling(点倍):求 。
一个直觉类比
如果椭圆曲线上的”点加”相当于普通算术里的”加法”,那”点乘”就相当于”乘法”——即用重复的加法实现。RSA 的模幂 也是同样的思想(重复平方+乘)。非对称密码的性能瓶颈永远是这个”重复的标量运算”,区别只在于底层的”加法”有多贵。
6.3 Montgomery 点乘算法
论文用的是 López-Dahab 优化的 Montgomery 点乘(对应图中的 ec_GF2m_montgomery_point_multiply)。算法 1 给出伪代码:
算法 1:优化的 Montgomery 点乘
输入:椭圆曲线 E(GF(2^m)),参数 a, b ∈ GF(2^m),K ≥ 0,点 P(x, y)
输出:Q(x, y) = K × P(x, y)
if K = 0 或 x = 0 then return Q(0, 0)
K = (k_{n-1} k_{n-2} ... k_{0})_2
X_1 = x, Z_1 = 1, X_2 = x^4 + b, Z_2 = x^2
Loop: for i from n-2 downto 0
if k_i = 1 then
P_1(X_1, Z_1) = GF2m_Madd(P_1(X_1, Z_1), P_2(X_2, Z_2))
P_2(X_2, Z_2) = GF2m_Mdouble(P_2(X_2, Z_2))
else
P_2(X_2, Z_2) = GF2m_Madd(P_2(X_2, Z_2), P_1(X_1, Z_1))
P_1(X_1, Z_1) = GF2m_Mdouble(P_1(X_1, Z_1))
return Q(x, y) = gf2m_Mxy(X_1, Z_1, X_2, Z_2)
这里有两个精妙的设计值得初学者细品:
第一,投影坐标(Projective Coordinates)避免求逆。 输入输出的点坐标用仿射坐标系(affine),但中间步骤全部在投影坐标系里做。为什么?因为在有限域里,求逆(inversion)比乘法贵几十倍。投影坐标把点表示成 对(对应仿射坐标的 ),把整个计算过程中需要的除法全部推迟、最后只做一次。
第二,Montgomery 的”差为常数”技巧。 在算法 1 的第 次迭代结束时,同时有 和 ,也就是说两者的差恒为常数点 。这个恒定差值让点加(算法 2)和点倍(算法 3)可以用只用 坐标对(仿射系下只用 坐标)的高效实现—— 坐标干脆不算了,最后在 次迭代后才用 gf2m_Mxy 恢复出来。
算法 2:GF(2^m) 上的点加
输入:曲线参数 a, b ∈ GF(2^m),P_2(X_2, Z_2) - P_1(X_1, Z_1) = P(x, 1)
输出:Q(X, Z) = P_1(X_1, Z_1) + P_2(X_2, Z_2)
T_1 = x, X_1 = X_1 × Z_2
Z_1 = Z_1 × X_2, T_2 = X_1 × Z_1
Z_1 = Z_1 + X_1, Z_1 = (Z_1)^2
X_1 = Z_1 × T_1, X_1 = X_1 + T_2
X = X_1, Z = Z_1
return Q(X, Z)
算法 3:GF(2^m) 上的点倍
输入:曲线参数 a, b ∈ GF(2^m),P_1(X_1, Z_1),c = b^2
输出:Q(X, Z) = 2 × P_1(X_1, Z_1)
T_1 = c, X_1 = (X_1)^2
Z_1 = (Z_1)^2, T_1 = Z_1 × T_1
Z_1 = Z_1 × X_1, T_1 = (T_1)^2
X_1 = (X_1)^2, X_1 = X_1 + T_1
X = X_1, Z = Z_1
return Q(X, Z)
注意算法 2 和算法 3 里的运算:在 上,“加法”就是按位 XOR(没有进位!),乘法则是二元多项式乘法后再模上本原多项式 。这就是二元域 ECC 相对于素数域 ECC 的一大优势——没有进位传播,硬件实现极其简洁。
6.4 再往下一层:Karatsuba 乘法
算法 2、3 里的每一次”乘法”,落到软件里是 ec_GF2m_simple_field_mul,它调用 BN_GF2m_mul_2x2(64 位 × 64 位乘法)和 BN_GF2m_mod_arr(取模)。而 BN_GF2m_mul_2x2 用的是 Karatsuba 算法:
把两个次数为 (本文 )的二元多项式分别写成 和 ,则: