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

Microsoft Graph API负载解密疑问:AES与HMAC密钥推导问题

Microsoft Teams Shifts自定义集成中AES+HMAC密钥推导方案修正

我在基于Microsoft Graph API开发Teams Shifts自定义劳动力集成时,对接完成后Graph API会发送AES-256-CBC-HMAC-SHA256加密的负载,使用的是步骤4提供的64字符十六进制密钥。但文档没说明如何从这个密钥推导AES(32字节)和HMAC(32字节)密钥。我尝试将十六进制解码后拆分前32字节做AES密钥、后32字节做HMAC密钥,但解码后只有32字节,导致HMAC密钥为空,请问这个推导方式错在哪里?

原实现代码:

-- Hex character to value lookup table
local hexMap = {
    ["0"] = 0,  ["1"] = 1,  ["2"] = 2,  ["3"] = 3,
    ["4"] = 4,  ["5"] = 5,  ["6"] = 6,  ["7"] = 7,
    ["8"] = 8,  ["9"] = 9,  ["a"] = 10, ["b"] = 11,
    ["c"] = 12, ["d"] = 13, ["e"] = 14, ["f"] = 15,
    ["A"] = 10, ["B"] = 11, ["C"] = 12, ["D"] = 13,
    ["E"] = 14, ["F"] = 15
}

-- Function to decode hex string to binary data
local function hexDecode(hexStr)
    if #hexStr % 2 ~= 0 then
        error("Hex string must have even length")
    end
    
    local result = {}
    for i = 1, #hexStr, 2 do
        local high = hexStr:sub(i, i)
        local low = hexStr:sub(i+1, i+1)
        
        if not hexMap[high] or not hexMap[low] then
            error("Invalid hex characters at position "..i)
        end
        
        local byte = hexMap[high] * 16 + hexMap[low]
        table.insert(result, string.char(byte))
    end
    
    return table.concat(result)
end

local secret = hexDecode(secretHex)
local key_enc = secret:sub(1, 32)
local key_mac = secret:sub(33, 64)

问题分析与修正方案

你的推导方式核心错误在于对密钥长度的认知:64字符的十六进制字符串解码后是32字节(每2个十六进制字符对应1字节),根本无法拆分成两个32字节的密钥。正确做法是使用**HKDF(基于HMAC的密钥派生函数)**从这32字节的主密钥中分别派生出AES加密密钥和HMAC校验密钥。

以下是修正后的Lua实现代码:

-- 依赖LuaCrypto库提供HMAC-SHA256和SHA256功能,需提前安装:luarocks install luacrypto
local crypto = require("crypto")

-- 保留原十六进制解码函数
local hexMap = {
    ["0"] = 0,  ["1"] = 1,  ["2"] = 2,  ["3"] = 3,
    ["4"] = 4,  ["5"] = 5,  ["6"] = 6,  ["7"] = 7,
    ["8"] = 8,  ["9"] = 9,  ["a"] = 10, ["b"] = 11,
    ["c"] = 12, ["d"] = 13, ["e"] = 14, ["f"] = 15,
    ["A"] = 10, ["B"] = 11, ["C"] = 12, ["D"] = 13,
    ["E"] = 14, ["F"] = 15
}

local function hexDecode(hexStr)
    if #hexStr % 2 ~= 0 then
        error("Hex string must have even length")
    end
    
    local result = {}
    for i = 1, #hexStr, 2 do
        local high = hexStr:sub(i, i)
        local low = hexStr:sub(i+1, i+1)
        
        if not hexMap[high] or not hexMap[low] then
            error("Invalid hex characters at position "..i)
        end
        
        local byte = hexMap[high] * 16 + hexMap[low]
        table.insert(result, string.char(byte))
    end
    
    return table.concat(result)
end

-- HKDF实现:包含提取和扩展两个步骤
local function hkdf(salt, ikm, info, length)
    -- 提取步骤:生成伪随机密钥(PRK)
    local prk = crypto.hmac.digest("sha256", ikm, salt, true)
    
    -- 扩展步骤:从PRK派生出指定长度的密钥
    local t = ""
    local previous = ""
    local iterations = math.ceil(length / 32)
    for i = 1, iterations do
        previous = crypto.hmac.digest("sha256", previous .. info .. string.char(i), prk, true)
        t = t .. previous
    end
    
    return t:sub(1, length)
end

-- 主流程:派生AES和HMAC密钥
local secretHex = "你的64字符十六进制密钥"
local masterKey = hexDecode(secretHex)

-- 用不同的info字段区分两个密钥,确保派生结果唯一
local aesKey = hkdf("", masterKey, "Teams Shifts AES Encryption Key", 32)
local hmacKey = hkdf("", masterKey, "Teams Shifts HMAC Verification Key", 32)

-- 验证密钥长度(均应为32字节)
print("AES Key Length: " .. #aesKey)
print("HMAC Key Length: " .. #hmacKey)

关键说明

  1. 必须使用密钥派生函数(如HKDF)从单个主密钥生成多个子密钥,直接拆分的方式因主密钥长度不足不可行。
  2. 两个子密钥的info参数需唯一,避免派生结果冲突,这里用明确的业务标识字符串区分。
  3. 代码依赖LuaCrypto库,需通过LuaRocks安装后方可运行。

内容的提问来源于stack exchange,提问作者Man Hen Choy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 21:34:51