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
问题原因分析
- TR31规范处理差异:Python的
tr31.unwrap方法会完整处理TR31块的解析、MAC验证和密钥解包全流程,而Swift代码仅传入了加密密钥部分,跳过了TR31规范要求的MAC校验步骤,也未处理头部中的密钥属性信息。 - 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
相关产品推荐
相关产品推荐

