OP-TEE Secure Storage 与 Sign/Verify 实战总结

2025博客之星年度评选已开启 10w+人浏览 2.2k人参与


📺 B站视频讲解(Bilibili)https://www.bilibili.com/video/BV1k1C9BYEAB/

📘 《Yocto项目实战教程》京东购买链接Yocto项目实战教程


OP-TEE Secure Storage 与 Sign/Verify 实战总结

定位说明
本文并不试图“直接解决模型加密或 IP 保护问题”,而是从工程基础角度,系统梳理 OP-TEE 中 Secure StorageSign / Verify 两个核心能力。

它们的价值在于:

  • 帮助你真正理解 CA / TA 架构
  • 熟悉 TEE Core API 的使用方式与设计哲学
  • 为后续「密钥保护 / 模型加密 / License / DRM」打下可复用的安全基础

一、整体视角:CA / TA / TEE 在干什么?

在进入 API 之前,必须先建立正确的心智模型

1.1 CA / TA 的职责划分

REE (Normal World)
└── CA (Client Application)
    - 文件系统
    - 网络
    - UI
    - 不可信

TEE (Secure World)
└── TA (Trusted Application)
    - 密钥
    - 安全运算
    - 安全存储
    - 可信

核心原则只有一句话

👉 REE 负责“搬数据”,TEE 负责“做决定 + 管密钥”


二、Secure Storage:不是“加密文件”,而是“可信状态”

2.1 Secure Storage 的真实定位

很多初学者会误解:

❌ Secure Storage = 安全 U 盘 / 加密磁盘

实际上:

✅ Secure Storage = TEE 内部的可信持久状态

它最适合存的是:

  • 私钥
  • 对称密钥
  • Counter / Version
  • Hash / 校验值
  • License 状态

不适合

  • 大文件
  • 模型本体

在这里插入图片描述

2.2 Persistent Object 的文件模型

OP-TEE 把 Secure Storage 设计成了一个极简文件系统抽象

概念类比说明
Object ID文件名你自己定义
Object Data文件内容原始 bytes
Object Handlefd打开后的句柄

没有字段、没有成员、没有 schema ——

👉 一切结构,都由你自己定义。


2.3 创建对象(实战代码)

TEE_Result res;
TEE_ObjectHandle object;

res = TEE_CreatePersistentObject(
        TEE_STORAGE_PRIVATE,
        obj_id, obj_id_sz,
        TEE_DATA_FLAG_ACCESS_READ |
        TEE_DATA_FLAG_ACCESS_WRITE,
        TEE_HANDLE_NULL,
        NULL, 0,
        &object);

这一步只做一件事

👉 创建一个“空对象容器”

此时:

  • 没有数据
  • 没有结构

2.4 写入与读取(关键理解)

写入
TEE_WriteObjectData(object, &secure_data, sizeof(secure_data));
读取
TEE_ReadObjectData(object, &secure_data, sizeof(secure_data), &read_bytes);

⚠️ 关键认知点

Secure Storage 只是一个 byte stream,
你必须自己保证:

  • 结构一致
  • 版本兼容
  • 长度正确

2.5 一个“推荐结构模式”

struct secure_blob {
    uint32_t version;
    uint8_t key[32];
    uint32_t counter;
};

实践经验:

  • 永远带 version
  • 永远整体读写
  • 不要拆成很多零散字段

三、Sign / Verify:理解“密钥不出 TEE”

如果说 Secure Storage 是 状态
那么 Sign / Verify 是 能力


3.1 为什么要做 Sign / Verify?

现实问题:

  • REE 不可信
  • 文件可能被替换
  • 参数可能被篡改

TEE 能提供的保证:

👉 只要签名通过,数据一定来自“拥有私钥的一方”


3.2 密钥生成(TA 内部)

TEE_ObjectHandle key;

TEE_AllocateTransientObject(
    TEE_TYPE_RSA_KEYPAIR,
    2048,
    &key);

TEE_GenerateKey(key, 2048, NULL, 0);

✔ 私钥永远不出 TEE
✔ CA 永远拿不到


3.3 签名流程(TA)

TEE_OperationHandle op;

TEE_AllocateOperation(
    &op,
    TEE_ALG_RSASSA_PKCS1_V1_5_SHA256,
    TEE_MODE_SIGN,
    2048);

TEE_SetOperationKey(op, key);
TEE_DigestDoFinal(op, data, data_len, hash, &hash_len);
TEE_AsymmetricSignDigest(op, NULL, 0, hash, hash_len, sig, &sig_len);

关键理解

TA 并不是在“加密数据”,
而是在对“数据摘要”负责。


3.4 验证流程(TA)

TEE_AsymmetricVerifyDigest(
    op,
    NULL, 0,
    hash, hash_len,
    sig, sig_len);

✔ 成功:数据可信
✔ 失败:数据被篡改 / 来源不可信


四、把两者结合:一个完整实战场景

场景:可信配置加载

config.json  (REE)
   |
   |  hash + signature
   v
CA  ------------------>  TA
                         - verify signature
                         - check version
                         - store hash in secure storage

Secure Storage 的作用

  • 保存:

    • 公钥
    • 上一次 hash
    • 版本号

Sign / Verify 的作用

  • 保证:

    • 配置未被篡改
    • 来源可信

五、它们与“模型保护”的真实关系

你之前的判断是对的:

❌ 它们本身 不是模型加密方案

但它们是:

一切模型保护方案的“基础积木”

现实中的模型保护,几乎一定会用到:

  • Secure Storage:存 key / hash / license
  • Sign / Verify:校验模型合法性

六、总结:你真正锻炼了什么?

通过 Secure Storage + Sign / Verify,你已经实打实掌握了:

  • ✔ CA / TA 的调用边界
  • ✔ 数据如何在 REE / TEE 间流动
  • ✔ 密钥如何“生成、使用、但不泄露”
  • ✔ 为什么 TEE 是 Root of Trust

这些能力,直接可迁移到

  • 模型解密
  • License 系统
  • Anti-rollback
  • Secure Update


📺 B站视频讲解(Bilibili)https://www.bilibili.com/video/BV1k1C9BYEAB/

📘 《Yocto项目实战教程》京东购买链接Yocto项目实战教程


ea_key/verify_key.o -o app -lpthread -lrt -lm -lcrypto -ljansson -L/home/thn/at606_v1r3_server/verify_area_key/lib -Wl,--whole-archive -Wl,--no-whole-archive -lpthread -lm /opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/../lib/gcc/aarch64-none-linux-gnu/10.3.1/../../../../aarch64-none-linux-gnu/bin/ld: verify_area_key/verify_key.o: in function `verify_signature': /home/thn/at606_v1r3_server/verify_area_key/verify_key.c:101: undefined reference to `EVP_PKEY_get_id' /opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/../lib/gcc/aarch64-none-linux-gnu/10.3.1/../../../../aarch64-none-linux-gnu/bin/ld: /home/thn/at606_v1r3_server/verify_area_key/verify_key.c:136: undefined reference to `EVP_DigestVerifyUpdate' /opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/../lib/gcc/aarch64-none-linux-gnu/10.3.1/../../../../aarch64-none-linux-gnu/bin/ld: /home/thn/at606_v1r3_server/verify_area_key/lib/libcrypto.a(dso_dlfcn.o): in function `dlfcn_globallookup': dso_dlfcn.c:(.text+0x1c): undefined reference to `dlopen' /opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/../lib/gcc/aarch64-none-linux-gnu/10.3.1/../../../../aarch64-none-linux-gnu/bin/ld: dso_dlfcn.c:(.text+0x2c): undefined reference to `dlsym' /opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/../lib/gcc/aarch64-none-linux-gnu/10.3.1/../../../../aarch64-none-linux-gnu/bin/ld: dso_dlfcn.c:(.text+0x3c): undefined reference to `dlclose' /opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/../lib/gcc/aarch64-none-linux-gnu/10.3.1/../../../../aarch64-none-linux-gnu/bin/ld: /home/thn/at606_v1r3_server/verify_area_key/lib/libcrypto.a(dso_dlfcn.o): in function `dlfcn_bind_func': dso_dlfcn.c:(.text+0x1d4): undefined reference to `dlsym' /opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/../lib/gcc/aarch64-none-linux-gnu/10.3.1/../../../../aarch64-none-linux-gnu/bin/ld: dso_dlfcn.c:(.text+0x290): undefined reference to `dlerror' /opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/../lib/gcc/aarch64-none-linux-gnu/10.3.1/../../../../aarch64-none-linux-gnu/bin/ld: /home/thn/at606_v1r3_server/verify_area_key/lib/libcrypto.a(dso_dlfcn.o): in function `dlfcn_load': dso_dlfcn.c:(.text+0x30c): undefined reference to `dlopen' /opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/../lib/gcc/aarch64-none-linux-gnu/10.3.1/../../../../aarch64-none-linux-gnu/bin/ld: dso_dlfcn.c:(.text+0x384): undefined reference to `dlclose' /opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/../lib/gcc/aarch64-none-linux-gnu/10.3.1/../../../../aarch64-none-linux-gnu/bin/ld: dso_dlfcn.c:(.text+0x3c4): undefined reference to `dlerror' /opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/../lib/gcc/aarch64-none-linux-gnu/10.3.1/../../../../aarch64-none-linux-gnu/bin/ld: /home/thn/at606_v1r3_server/verify_area_key/lib/libcrypto.a(dso_dlfcn.o): in function `dlfcn_pathbyaddr': dso_dlfcn.c:(.text+0x478): undefined reference to `dladdr' /opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/../lib/gcc/aarch64-none-linux-gnu/10.3.1/../../../../aarch64-none-linux-gnu/bin/ld: dso_dlfcn.c:(.text+0x4f0): undefined reference to `dlerror' /opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/../lib/gcc/aarch64-none-linux-gnu/10.3.1/../../../../aarch64-none-linux-gnu/bin/ld: /home/thn/at606_v1r3_server/verify_area_key/lib/libcrypto.a(dso_dlfcn.o): in function `dlfcn_unload': dso_dlfcn.c:(.text+0x6d8): undefined reference to `dlclose' collect2: error: ld returned 1 exit status make: *** [Makefile:35: app] Error 1
11-06
你遇到的链接错误如下: ```bash undefined reference to `EVP_PKEY_get_id` undefined reference to `EVP_DigestVerifyUpdate` undefined reference to `dlopen`, `dlsym`, `dlclose`, `dladdr`, `dlerror` ``` --- ## 🔴 问题分类根本原因 你的链接失败是由 **两类问题** 导致的: --- ### ❌ 错误 1:`EVP_PKEY_get_id`, `EVP_DigestVerifyUpdate` 找不到 👉 这些是 OpenSSL 1.1.0+ 的 API,说明你使用的 `libcrypto.a` **版本太旧或不完整** ### ❌ 错误 2:`dlopen`, `dlsym`, `dlclose` 等找不到 👉 这些是动态加载库函数(POSIX dlfcn),属于系统库 `libdl`,但你在 **静态链接时没有包含 `-ldl`** 更严重的是:**你的 `libcrypto.a` 是在启用了 `DSO`(Dynamic Shared Object)支持的情况下编译的**,它依赖 `dlopen` 等符号。 而你现在是在做 **静态交叉编译嵌入式程序**,目标平台可能根本没有动态加载能力! --- ## ✅ 正确解决方案(两步走) --- ### ✅ 第一步:使用正确版本的 aarch64 兼容 `libcrypto.a` 你当前用的: > `/home/thn/at606_v1r3_server/verify_area_key/lib/libcrypto.a` 这个库要么是: - x86_64 编译的(PC 版) - ARM32 编译的(armhf) - 或者是旧版 OpenSSL 编译的 - 并且启用了 DSO 动态模块加载 → 引入了对 `libdl` 的依赖 --- #### ✅ 解决方法:自己从源码交叉编译一个 **无 DSO、aarch64 架构兼容** 的 `libcrypto.a` ```bash # 清理旧配置 cd /home/thn/openssl-1.1.1w make distclean # 使用正确的前缀重新配置 ./Configure linux-aarch64 \ --prefix=/home/thn/openssl-aarch64 \ --cross-compile-prefix=aarch64-none-linux-gnu- \ no-shared \ no-async \ no-dso \ # 👈 关键!禁用 DSO,避免依赖 dlopen/dlsym no-engine \ # 👈 可选:禁用引擎(进一步减少依赖) -fPIC # 编译并安装 make -j$(nproc) make install ``` 📌 核心参数解释: | 参数 | 含义 | |------|------| | `no-dso` | 禁用动态共享对象支持 → 不再需要 `dlopen` 等 | | `no-engine` | 禁用硬件加速引擎(如 PKCS#11),进一步减小体积和依赖 | | `no-shared` | 只生成 `.a` 静态库 | | `--cross-compile-prefix=...` | 指定交叉工具链 | --- ### ✅ 第二步:修改 Makefile,确保链接顺序正确 你现在链接命令写成了: ```makefile -lpthread -lrt -lm -lcrypto -ljansson -L... -Wl,--whole-archive -Wl,--no-whole-archive ``` ⚠️ 问题: - `-lcrypto` 放得太早 - 没有 `-ldl` - `-L` 放在后面也无效 ✅ 正确写法: ```makefile # 工具链 CC = aarch64-none-linux-gnu-gcc CFLAGS += -I/home/thn/openssl-aarch64/include CFLAGS += -I/opt/include # 对象文件 OBJECTS = cJSON_Parse.o cJSON.o link.o main.o mongoose.o ... verify_key.o # 目标 app: $(OBJECTS) $(CC) $(OBJECTS) \ -o app \ -L/home/thn/openssl-aarch64/lib \ -Wl,--start-group \ -lssl -lcrypto -ljansson \ -lpthread -lrt -lm \ -Wl,--end-group clean: rm -f *.o */*.o app ``` 📌 关键点说明: | 技巧 | 原因 | |------|------| | `-L/path/to/lib` 必须在 `-lxxx` 之前 | 否则链接器找不到路径 | | 使用 `--start-group ... --end-group` | 解决库之间循环依赖问题 | | 不需要 `-ldl` | 因为我们用了 `no-dso`,彻底去除了对 `libdl` 的依赖 | | 头文件路径正确 | 防止编译时报 `EVP_PKEY_get_id` 找不到声明 | --- ### ✅ 第三步:验证新生成的 `libcrypto.a` 是否干净 运行命令检查是否还引用 `dlopen` 等符号: ```bash aarch64-none-linux-gnu-nm /home/thn/openssl-aarch64/lib/libcrypto.a | grep dlopen ``` ✅ 正常情况应 **没有任何输出**。 如果有输出,说明你没成功关闭 `DSO`,必须重新编译。 --- ### ✅ 第四步:确认架构正确 ```bash aarch64-none-linux-gnu-readelf -h /home/thn/openssl-aarch64/lib/libcrypto.a | grep Machine ``` ✅ 输出应为: ``` Machine: AArch64 ``` 并且 Class 是 ELF64。 --- ## 🧠 为什么 `EVP_PKEY_get_id` 和 `EVP_DigestVerifyUpdate` 会报错? 这些函数是在 **OpenSSL 1.1.0** 中引入的。如果你使用的是非常老的 OpenSSL 版本(比如 1.0.2),它们不存在。 ✅ 请确保你下载的是 **OpenSSL 1.1.1 或更高版本**(如 `openssl-1.1.1w.tar.gz`) 验证方式: ```bash cat /home/thn/openssl-1.1.1w/VERSION # 应该输出:1.1.1w ``` --- ## ✅ 总结:你现在要做的事 | 步骤 | 命令 | |------|------| | 1. 清理旧 OpenSSL 构建 | `make distclean` | | 2. 正确配置(关键!) | `./Configure linux-aarch64 --cross-compile-prefix=aarch64-none-linux-gnu- no-dso no-shared ...` | | 3. 编译安装 | `make && make install` | | 4. 修改 Makefile 使用新路径 | `-L/home/thn/openssl-aarch64/lib` | | 5. 移除 `-ldl`,改用 `--start-group` 分组链接 | 更安全 | | 6. 重新编译主工程 | `make clean && make` | --- ## ✅ 最终验证 成功后运行: ```bash file app ``` 应该显示: ``` app: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, ... ``` 表示这是一个合法的 aarch64 可执行文件。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值