You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift实现TR31加密密钥块解包遇unwrapFailure错误求助

TR31密钥解包:Python正常运行但Swift CryptoKit抛出unwrapFailure错误

现有一段Python代码可通过KEK对TR31加密密钥块完成解包,得到明文密钥f039121bec83d26b169bdcd5b22aaf8f,但使用Swift CryptoKit实现相同功能时,出现CryptoKit.CryptoKitError.unwrapFailure错误。以下为两端代码及TR31块结构拆分:

Python 可运行代码

kek = "89E88CF7931444F334BD7547FC3F380C"
encryptedTR31KeyBlock = "A0096K0TD12S0100KS1800604B120F929280000015BE1EA22731B03647031CEA17F516A5B7B14FC7D08BAA4377B803E1"
header, decryptedKey = tr31.unwrap(bytes.fromhex(kek), encryptedTR31KeyBlock)
print(decryptedKey.hex())

Swift 报错代码

let kekBytes2: [UInt8] = [
    0x89, 0xE8, 0x8C, 0xF7, 0x93, 0x14, 0x44, 0xF3,
    0x34, 0xBD, 0x75, 0x47, 0xFC, 0x3F, 0x38, 0x0C,
]

let kek = CryptoKit.SymmetricKey(data: Data(kekBytes2))

let encryptedTR31KeyBlock: [UInt8] = [
    0x15, 0xBE, 0x1E, 0xA2, 0x27, 0x31, 0xB0, 0x36,
    0x47, 0x03, 0x1C, 0xEA, 0x17, 0xF5, 0x16, 0xA5,
    0xB7, 0xB1, 0x4F, 0xC7, 0xD0, 0x8B, 0xAA, 0x43,
]
//unwrap key
let unwrappedKey2 = try AES.KeyWrap.unwrap(encryptedTR31KeyBlock, using: kek)

TR31块结构拆分

  • 头部(header):A0096K0TD12S0100KS1800604B120F9292800000
  • 加密密钥(encrypted key):15BE1EA22731B03647031CEA17F516A5B7B14FC7D08BAA43
  • 消息认证码(MAC):77B803E1

问题原因分析

  1. TR31规范处理差异:Python的tr31.unwrap方法会完整处理TR31块的解析、MAC验证和密钥解包全流程,而Swift代码仅传入了加密密钥部分,跳过了TR31规范要求的MAC校验步骤,也未处理头部中的密钥属性信息。
  2. AES Key Wrap输入要求不匹配:AES Key Wrap(RFC 3394)要求待解包的密钥数据长度必须是8字节的整数倍,虽然本次KEK长度(16字节,对应AES-128)符合要求,但TR31的加密密钥可能包含额外标识位或填充,直接传入会导致解包逻辑不兼容。

解决方案

步骤1:完整解析TR31块

先从原始TR31字符串中拆分出头部、加密密钥和MAC,再按照TR31规范完成MAC有效性验证(通常使用KEK或其衍生密钥计算校验值)。

步骤2:修正Swift解包逻辑

确保传入AES.KeyWrap.unwrap的数据符合RFC 3394要求,同时补全TR31的MAC校验流程。以下是修正后的示例代码:

import CryptoKit

// 原始TR31密钥块十六进制字符串
let tr31Hex = "A0096K0TD12S0100KS1800604B120F929280000015BE1EA22731B03647031CEA17F516A5B7B14FC7D08BAA4377B803E1"

// 解析TR31块:提取加密密钥和MAC部分
let encryptedKeyHex = String(tr31Hex.dropFirst(42).dropLast(8)) // 跳过42字符的头部,去掉最后8字符的MAC
let macHex = String(tr31Hex.suffix(8))

// 转换为字节数据
guard let encryptedKeyData = Data(hexString: encryptedKeyHex),
      let macData = Data(hexString: macHex),
      let kekData = Data(hexString: "89E88CF7931444F334BD7547FC3F380C") else {
    fatalError("数据转换失败")
}

let kek = SymmetricKey(data: kekData)

// 先验证MAC(此处需根据TR31规范实现MAC校验,示例省略具体校验逻辑)
// 提示:TR31通常使用HMAC算法,需根据头部标识选择哈希函数,用KEK计算校验值与提取的MAC对比
// ... 此处添加MAC验证代码 ...

// 执行AES Key Wrap解包
do {
    let unwrappedKey = try AES.KeyWrap.unwrap(encryptedKeyData.bytes, using: kek)
    print("解包后的明文密钥:\(Data(unwrappedKey).hexString)")
} catch {
    print("解包失败:\(error)")
}

// 扩展Data以支持十六进制字符串转换
extension Data {
    init?(hexString: String) {
        let len = hexString.count / 2
        var data = Data(capacity: len)
        var i = hexString.startIndex
        for _ in 0..<len {
            let j = hexString.index(i, offsetBy: 2)
            let bytes = hexString[i..<j]
            if let byte = UInt8(bytes, radix: 16) {
                data.append(byte)
            } else {
                return nil
            }
            i = j
        }
        self = data
    }
    
    var hexString: String {
        return map { String(format: "%02x", $0) }.joined()
    }
}

extension Data {
    var bytes: [UInt8] {
        return Array(self)
    }
}

关键注意点

  • TR31的MAC校验需严格遵循规范,通常使用HMAC-SHA256等哈希算法,密钥为KEK或其衍生值。
  • 确保加密密钥数据长度符合AES Key Wrap的8字节整数倍要求,若TR31密钥包含填充,解包后需去除填充位。

内容的提问来源于stack exchange,提问作者jiffyjhn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 08:15:41