☰
libimobiledevice 内部 SRP6a-sha512 客户端认证库剖析:从斯坦福 SRP 裁剪到 iOS 配对实战
2026/9/26 7:48:40 网站建设 项目流程
  • 移动开发

【免费下载链接】libimobiledevice

A cross-platform protocol library to communicate with iOS devices

项目地址:https://gitcode.com/gh_mirrors/li/libimobiledevice
点击查看免费下载

libimobiledevice 是跨平台的 iOS 设备通信协议库,在与设备完成配对(Pairing)的过程中,需要一套零知识密码学证明来验证 PIN、协商会话密钥。本文聚焦仓库内 3rd_party/libsrp6a-sha512 这个裁剪版 SRP 库:它源自斯坦福大学的 Secure Remote Password(SRP)实现,仅保留 SRP6a 客户端方法并改用 SHA-512 摘要,读者将掌握其 API 全貌、底层调用链,以及它如何支撑 lockdown-cu.c 中的 CU 配对流程。

背景:为什么 libimobiledevice 需要一棵裁剪过的 SRP

SRP(Secure Remote Password)是一种零知识密码证明协议,客户端无需把明文密码发送到网络上,即可向服务端证明自己知道某个密码,并在此基础上协商出共享会话密钥。斯坦福大学发布的原始 SRP 项目(libsrp)同时包含客户端与服务端实现,并支持多种摘要算法与方法族(RFC2945、SRP-6、SRP-6a)。

libimobiledevice 只需要在配对流程中扮演客户端,因此该项目对原始代码做了三件事的适配(见 3rd_party/libsrp6a-sha512/README.md):

  1. 只保留客户端半边:所有 server-side 代码被移除;
  2. 仅支持一种方法:SRP6a_sha512_client_method(),将斯坦福原始实现中的 SHA-1 摘要替换为 SHA-512(关于方法选择与 SHA-512 定义,可参考 srp6a_sha512_client.c 与 t_sha.h);
  3. 新增 MbedTLS 后端:除 OpenSSL、libgcrypt 外,补上了 MbedTLS 支持,便于在无 OpenSSL 的嵌入式/移动平台上编译。

该库被构建为内部静态库libsrp6a-sha512.la(见 3rd_party/libsrp6a-sha512/Makefile.am),通过 Automake 条件编译在OPENSSL/GCRYPT/MBEDTLS三种密码后端间切换。

支持面与限制:只有这些函数被保证可用

原 README 明确指出,经过裁剪后只有以下 9 个函数保持可用,其余原始 API“未经测试、应视为不可用”:

  • SRP_initialize_library:全局初始化(大整数运算与强随机源);
  • SRP_new:按方法创建 SRP 上下文;
  • SRP_free:释放上下文;
  • SRP_set_user_raw:设置用户名(长度受限的原始字节串);
  • SRP_set_params:设置模数、生成元与盐;
  • SRP_set_auth_password:由明文密码派生认证器;
  • SRP_gen_pub:生成己方公钥 A;
  • SRP_compute_key:计算共享会话密钥;
  • SRP_respond:生成发送给对端的证明;
  • SRP_verify:校验对端发来的证明。

其余如服务端查找 API、SRP_set_authenticator、SRP_add_ex_data等尽管在头文件中仍有声明,但项目只验证了上述列表。使用前提:这段声明同样意味着调用方应只依赖这 9 个函数。

核心 API 解析与调用次序

SRP 上下文SRP是一个混合结构体,通过magic字段区分客户端/服务端状态(SRP_MAGIC_CLIENT 12、SRP_MAGIC_SERVER 28),内部保存 username、modulus、generator、salt、verifier、password、pubkey、secret、u、key 以及方法指针meth与方法私有数据meth_data(见 srp.h)。

客户端调用方必须先调用SRP_initialize_library(),之后依次执行:

  1. SRP_new(SRP6a_sha512_client_method())创建上下文;
  2. SRP_set_user_raw(srp, user, userlen)设置用户名(SRP_set_username是接受 C 字符串的等价形式,二者必须二选一);
  3. SRP_set_params(srp, modulus, modlen, generator, genlen, salt, saltlen)装载域参数与盐;
  4. SRP_set_auth_password(srp, password)(或其 raw 变体)由密码派生认证器;
  5. SRP_gen_pub(srp, &result)生成公钥;
  6. SRP_compute_key(srp, &key, remote_pubkey, remote_pubkeylen)计算会话密钥;
  7. SRP_respond(srp, &proof)产出证明;
  8. SRP_verify(srp, remote_proof, prooflen)校验对端;
  9. SRP_free(srp)释放并清零敏感中间量(如 password、verifier、key)。

其中SRP_set_user_raw与SRP_set_params必须按顺序、先于其他一切调用(见 srp.h 中对SRP_set_username/SRP_set_params的注释)。

参数校验细节

在 srp.c 中,SRP_set_params会先做三项检查:

  • modulus、generator、salt任一为 NULL 直接返回SRP_ERROR;
  • 模数位长小于全局最小位数(默认SRP_DEFAULT_MIN_BITS 512,可通过SRP_set_modulus_min_bits调整)则拒绝;
  • 若设置了客户端参数校验回调SRP_CLIENT_PARAM_VERIFY_CB,则调用回调确认 N、g 可接受(SRP_set_client_param_verify_cb注入)。

之后才把参数转发给方法实现srp->meth->params。

SHA-512 方法实现细节:基于源码的密码学流程

SRP6a_sha512_client_method()返回一个静态的SRP_METHOD结构(见 srp6a_sha512_client.c),其名字串为"SRP-6a sha512 client (tjw)",方法回调依次为 init/finish/params/auth/passwd/genpub/key/verify/respond。客户端私有状态是一个sha512_client_meth_st,内含两个 SHA-512 上下文(hash与ckhash)以及 64 字节的会话密钥缓冲区k(SRP6_SHA512_KEY_LEN 64)。

对照源码,各阶段实现的密码学要点如下:

  • init:设置 magic 为SRP_MAGIC_CLIENT,标志位SRP_FLAG_MOD_ACCEL | SRP_FLAG_LEFT_PAD(分别表示启用模幂加速、哈希内大整数左填充到模数长度),并初始化两个 SHA-512 上下文。
  • params:计算H(N) xor H(g)(两个 64 字节 SHA-512 摘要逐字节异或),依次把H(N) xor H(g)、H(user)、salt喂入hash上下文——这是客户端证明 M 的输入前缀。
  • passwd:先计算dig = H(U | ":" | P),再计算H(salt | dig),结果作为“认证器”(raw secret 的大端字节串),由内部SRP_set_authenticator落盘,随后清零临时摘要。SRP_set_auth_password的默认长度取strlen(password)(srp.c)。
  • auth:客户端侧认证器即“密码派生哈希”,随后verifier = g^x mod N也被本地计算出来,供会话密钥公式使用。
  • genpub:用强随机源t_random生成与模数等长的临时串,取其前SRP_get_secret_bits(...)字节为秘密指数a,再叠加BigIntegerBitLen(modulus)以强制g^a mod n发生“回绕”,最终A = g^a mod N;同时把 A 追加进hash,并把 A 置为ckhash的起点。
  • key:先计算k = H(N || g)(SRP-6a 相对 SRP-6 的改进:将 g^x 乘以 N、g 的哈希而非固定系数 3);随后校验对端公钥 B:长度不得超过模数字节长、B >= modulus或B == 0一律拒绝,再以(B - k*v) mod N对 B 去盲、计算u = H(A_pad || B_pad),最终K = (B - k*v)^(a + u*x) mod N,把 K 的 SHA-512 摘要作为 64 字节会话密钥,并依次追加 B、K、ex_data 进hash。
  • respond:产出hash上下文的最终 64 字节摘要作为客户端证明 M,并把 M 与 K 追加进ckhash。
  • verify:计算ckhash的最终摘要,与对端证明做常量时间memcmp(长度须为 64),一致返回SRP_SUCCESS,否则SRP_ERROR。

哈希后端抽象:OpenSSL / GCRYPT / MBEDTLS

t_sha.h 通过编译期宏把SHA512Init/Update/Final映射到不同后端:

  • OPENSSL:OpenSSL ≥ 3.0 走 EVP 封装(EVP_MD_CTX),旧版直接映射SHA512_Init/Update/Final;
  • GCRYPT:映射到 libgcrypt 的gcry_md_*接口(见 t_sha.c 中的SHA512Init_gcry等包装);
  • MBEDTLS:映射到mbedtls_md_*(mbedtls_md_context_t),这是本项目新增的支持。

大整数抽象则集中在 srp_aux.h:BigInteger一族(FromBytes/FromInt、ModExp、ModMul、Ctx/ModAccel、ClearFree 等)隐藏了底层大数实现,BigIntegerInitialize/Finalize在SRP_initialize_library/finalize_library中成对调用。t_random是一个用单向哈希反馈配置的密码学随机源,t_stronginitrand从多个高熵源播种。

在 libimobiledevice 中的真实用法:CU 配对流程

该库最直接的消费者是 src/lockdown-cu.c 中与 iOS 设备进行“CU Pairing”(CUPairingCreate)的代码。其调用序列与上文 API 次序完全对应:

SRP_initialize_library(); SRP* srp = SRP_new(SRP6a_sha512_client_method()); if (!srp) { /* 处理失败 */ } ... /* state 2:收到设备下发的 salt 与 pubkey 后 */ const char PAIR_SETUP[] = "Pair-Setup"; if (SRP_set_user_raw(srp, (const unsigned char*)PAIR_SETUP, sizeof(PAIR_SETUP)-1) != 0) { ... } /* kSRPParameters_3072_SHA512 */ if (SRP_set_params(srp, kSRPModulus3072, sizeof(kSRPModulus3072), &kSRPGenerator5, 1, salt, salt_size) != 0) { ... } if (pairing_callback) { char pin[64]; unsigned int pin_len = sizeof(pin); pairing_callback(LOCKDOWN_CU_PAIRING_PIN_REQUESTED, cb_user_data, pin, &pin_len); SRP_set_auth_password_raw(srp, (const unsigned char*)pin, pin_len); } ... /* state 3:生成公钥、计算会话密钥、产出证明并随 TLV 发送 */ SRP_gen_pub(srp, &own_pub); SRP_compute_key(srp, &thekey, pubkey, pubkey_size); SRP_respond(srp, &response); /* state 4:收到对端证明并校验 PIN */ int vrfy_result = SRP_verify(srp, proof, proof_len);

配对使用的域参数正是 3072 位模数kSRPModulus3072(384 字节,RFC 3526 风格的安全素数)与生成元g = 5(见 src/lockdown-cu.c 中的kSRPGenerator5),与注释/* kSRPParameters_3072_SHA512 */一致。

配对成功后,thekey(SRP_compute_key产出的 64 字节会话密钥)并不会直接使用:lockdown-cu.c 后续通过 HKDF(SHA-512,hkdf_md(MD_ALGO_SHA512, ...))分别派生出:

  • Pair-Setup-Encrypt-Salt/Pair-Setup-Encrypt-Info:用作 chacha20-poly1305 的加解密密钥(setup_encryption_key,32 字节),保护消息 PS-Msg05/PS-Msg06;
  • Pair-Setup-Controller-Sign-Salt/Pair-Setup-Controller-Sign-Info:结合 ed25519 密钥对(3rd_party/ed25519)签署主机信息。

而SRP_verify返回 0 即打印"[SRP] PIN verified successfully",失败则进入LOCKDOWN_E_PAIRING_FAILED分支。整个流程结束后调用SRP_free(srp)清理上下文(其中敏感大整数被BigIntegerClearFree清零后再释放)。

构建与集成方式

作为第三方内部库,libsrp6a-sha512 由 3rd_party/Makefile.am 纳入整个项目的 Autotools 构建,configure.ac 会探测 OpenSSL / libgcrypt / MbedTLS 并定义对应宏;3rd_party/libsrp6a-sha512/Makefile.am 编译t_conv.c t_math.c t_misc.c t_truerand.c cstr.c srp.c srp6a_sha512_client.c t_sha.c等源文件为libsrp6a-sha512.la。编译时需保证与顶层-I路径及-DHAVE_CONFIG_H一致,并按后端链接对应密码库。

许可说明

该库保留了斯坦福 SRP 原始项目的 BSD 风格许可(见 3rd_party/libsrp6a-sha512/LICENSE),全部源文件头部亦标注 Stanford SRP Authentication Project 的版权声明,衍生使用时需遵守相应条款。

小结

概括而言,libsrp6a-sha512 是一棵“最小可用”的 SRP6a 客户端实现:移除服务端、固定 SHA-512、增加 MbedTLS 后端,并把可用 API 收敛到 9 个函数。它在 libimobiledevice 中支撑起 CU 配对这一关键安全步骤,配合 HKDF-SHA512、chacha20-poly1305 与 ed25519 完成 iOS 设备的配对与密钥协商。阅读 srp.c 与 srp6a_sha512_client.c 可完整还原其密码学细节,而 src/lockdown-cu.c 提供了真实可追踪的集成范例。

  • 移动开发

【免费下载链接】libimobiledevice

A cross-platform protocol library to communicate with iOS devices

项目地址:https://gitcode.com/gh_mirrors/li/libimobiledevice
点击查看免费下载

相关推荐

上一篇:Yaagl:macOS游戏启动器的终极解决方案
下一篇:FunClip:基于 FunASR 的本地视频智能剪辑,一键拿到 SRT 字幕与说话人切片

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询