- 移动开发
【免费下载链接】libimobiledevice
A cross-platform protocol library to communicate with iOS devices
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):
- 只保留客户端半边:所有 server-side 代码被移除;
- 仅支持一种方法:
SRP6a_sha512_client_method(),将斯坦福原始实现中的 SHA-1 摘要替换为 SHA-512(关于方法选择与 SHA-512 定义,可参考 srp6a_sha512_client.c 与 t_sha.h); - 新增 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(),之后依次执行:
SRP_new(SRP6a_sha512_client_method())创建上下文;SRP_set_user_raw(srp, user, userlen)设置用户名(SRP_set_username是接受 C 字符串的等价形式,二者必须二选一);SRP_set_params(srp, modulus, modlen, generator, genlen, salt, saltlen)装载域参数与盐;SRP_set_auth_password(srp, password)(或其 raw 变体)由密码派生认证器;SRP_gen_pub(srp, &result)生成公钥;SRP_compute_key(srp, &key, remote_pubkey, remote_pubkeylen)计算会话密钥;SRP_respond(srp, &proof)产出证明;SRP_verify(srp, remote_proof, prooflen)校验对端;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
相关推荐
HMAC-SHA256终极指南:斯坦福加密库中的消息认证最佳实践
HMAC SHA256终极指南:斯坦福加密库中的消息认证最佳实践 在当今数据传输日益频繁的数字时代,确保信息的完整性和真实性至关重要。斯坦福JavaScript
密码学Apache Pulsar TLS 客户端认证实战指南:从证书签发到 Broker/Proxy/多语言客户端配置
Apache Pulsar TLS 客户端认证实战指南:从证书签发到 Broker/Proxy/多语言客户端配置 导读 TLS 认证(TLS Authentic
消息队列后端流处理Apache Pulsar 客户端 Token(JWT)认证:从各语言客户端配置到底层实现解析
Apache Pulsar 客户端 Token(JWT)认证:从各语言客户端配置到底层实现解析 本文围绕 Pulsar 的客户端 Token 认证机制展开,介绍
消息队列后端流处理
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考