You need to enable JavaScript to run this app. 基于pycrypto实现XML加密解析LCP编码文件的LCP DRM调试问题
优惠活动
大模型
产品
解决方案
定价
更多

基于pycrypto实现XML加密解析LCP编码文件的LCP DRM调试问题

LCP DRM 实现调试问题修复点

当前流程存在的核心偏差

  • 对key_check字段的加密明文对象理解错误,错误移除了许可证id中的横杠,使用32位无分隔的UUID串作为加密明文,实际规范要求的明文是完整保留横杠的原始许可证id的UTF-8字节串,长度为36字节
  • 验证逻辑方向偏差:当前思路是自行加密明文拼接IV来复现key_check值,反而增加了填充逻辑出错的概率,正确的验证方式是拆解key_check结构后解密,将明文与许可证id做对比
  • 对所有加密字段的通用结构认知不清晰:从key_check到内容密钥、再到加密的目标文件,统一遵循「16字节随机IV + 带PKCS7填充的AES-256-CBC密文」的结构,解码后直接拆分前16字节为IV即可,不需要额外推导IV的取值

正确的调试实现步骤

  1. 用户密钥生成:将输入的用户口令做SHA256哈希,得到32字节的哈希值作为AES-256的用户密钥,这一步的实现逻辑是完全正确的
  2. key_check验证流程:
    • 将key_check字段的Base64串解码为原始字节流
    • 拆分字节流:前16字节为AES初始化向量IV,剩余部分为加密后的密文
    • 用之前生成的用户密钥初始化AES-256-CBC解密器,对密文解密后移除PKCS7填充
    • 将解密得到的明文与许可证原始id(带横杠)做等值对比,匹配则代表用户口令正确
  3. 内容密钥解密流程:
    • 对content_key下的encrypted_value做同样的拆解解密操作,使用用户密钥解密得到32字节的内容密钥
  4. 目标文件解密流程:
    • 将目标文件的密文Base64解码,同样拆分为前16字节IV、剩余密文的结构
    • 使用内容密钥初始化AES解密器,解密并移除PKCS7填充
    • 对解密得到的Deflate压缩字节流做zlib解压,即可得到原始的xhtml文件,校验长度是否为792字节即可确认解密是否成功

调试代码修正参考

import codecs
import zlib
from Crypto.Hash import SHA256
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad

# 1. 生成用户密钥
user_pass = b'4EeffRhPz6'
user_key = SHA256.new(user_pass).digest()

# 2. 验证key_check
key_check_b64 = b"pFoXDupsQReQ5H5e9Vg6JtHkjkbVkOlkGYUWvWmFSgfZN8anAyMP7T6+zW3FJn+GzQpatvRQW7W54wixrUeorQ=="
key_check_raw = codecs.decode(key_check_b64, 'base64')
kv_iv = key_check_raw[:16]
kv_cipher = key_check_raw[16:]
aes_kv = AES.new(user_key, AES.MODE_CBC, kv_iv)
decrypted_kv = unpad(aes_kv.decrypt(kv_cipher), AES.block_size)
license_id = b'6666065a-e7bd-44b4-93ad-abd0336374dd'
assert decrypted_kv == license_id, "用户口令验证失败"

# 3. 解密内容密钥
ck_b64 = b'itxQlsi5sxcSZ89eW2m80UCOyEDqBZzgTX3E/kG3rqWstvnFXOqOXVwiodlHUmtUSqxdbToy02fubOSt1/37AQ=='
ck_raw = codecs.decode(ck_b64, 'base64')
ck_iv = ck_raw[:16]
ck_cipher = ck_raw[16:]
aes_ck = AES.new(user_key, AES.MODE_CBC, ck_iv)
content_key = unpad(aes_ck.decrypt(ck_cipher), AES.block_size)

# 4. 解密目标xhtml文件
file_cipher_b64 = b'CJIqkyl4gAsQjaKJo8+D5imSgTc4jEJdm+xHmKr0kV/Nyyf87OclI+1hUCsXuvp42gSZOgSLejjVek3wguvE/4XBE6Mq/KWcAeoXbB/mMYMyQD66QfpL1j5tWPo/kSFVt8TNVebcvUQRCY43VkmEAryjmpg1CzLJIDfJrJqmfeHYO5uP5kOV5xL+dF4NQCPCFdvRExF1X+XprMoq7Cj1BMNyUfUBMVx1Z8emKBBaW+AkSVJIw3cjSJdeTo0hBzm/7Qu78YwkA184fLTtEQ0dD3HzzkvMfL052i0mJT6cSR/LVWt7BZTbxRVf7s6fvjhK4LYT8arLNIvKy7UianJIngn3MRUFXexs7rLPrhw5nXDazexEh3rWzGTBxHBySL1ldjs2cvlc0BKhpCyWfGGbaEPZl1mHt7tIHQhO5oHHl079K1t/oL2Q5FJ6RdCnKIL9sxbPMcFnmPZFyVE0GK6Ucx1KiaC8xoQirEJWDB7iTniwp8Vl/t/HeHUh+/nbVdx6ohQm10lxmOoRTMtYAUo7kg=='
file_raw = codecs.decode(file_cipher_b64, 'base64')
file_iv = file_raw[:16]
file_cipher = file_raw[16:]
aes_file = AES.new(content_key, AES.MODE_CBC, file_iv)
decrypted_file = unpad(aes_file.decrypt(file_cipher), AES.block_size)
original_xhtml = zlib.decompress(decrypted_file)
assert len(original_xhtml) == 792, "文件解密失败"

注意:调试时优先使用解密对比的方式验证逻辑,避免自行处理加密填充时的格式错误,所有字段的结构保持统一即可大幅降低调试阻塞点。

内容的提问来源于stack exchange,提问作者Mark C.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.30 18:54:03