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

如何在PHP中基于32位Hex密钥生成ISO/IEC 9797-1 MAC?

PHP实现符合ISO/IEC 9797-1标准的MAC计算

问题背景

需要基于XML内容和32位十六进制密钥生成ISO/IEC 9797-1标准MAC,要求与指定在线工具计算结果一致(填充方法1),但现有代码无法得到正确输出。

现有代码的问题

  1. 密钥处理错误:直接对十六进制字符串做子串截取,未先转换为二进制密钥,导致实际使用的是ASCII字符而非正确的加密密钥。
  2. 填充逻辑错误:仅补0字节,未按照填充方法1的要求先添加0x80再补0,不符合标准规范。
  3. CBC-MAC实现错误:直接用ECB模式加密整个消息,未遵循CBC-MAC逐块异或前一次加密结果的核心逻辑。
  4. 最终变换错误:错误地对消息最后一块做3DES加密,而非对CBC-MAC的中间结果执行密钥解密再加密的标准变换。

正确实现代码

function calculateISO9797MAC(string $messageHex, string $keyHex): string {
    // 将十六进制消息和密钥转换为二进制
    $message = hex2bin($messageHex);
    $keyBin = hex2bin($keyHex);
    
    // 拆分密钥:K1(前8字节)、K2(后8字节)
    $k1 = substr($keyBin, 0, 8);
    $k2 = substr($keyBin, 8, 8);
    
    // 应用填充方法1:先加0x80,再补0至8字节的整数倍
    $message .= chr(0x80);
    $paddingLength = 8 - (strlen($message) % 8);
    if ($paddingLength !== 8) {
        $message .= str_repeat(chr(0x00), $paddingLength);
    }
    
    // 计算CBC-MAC(初始向量为全0)
    $mac = str_repeat(chr(0x00), 8); // 初始IV
    $blockCount = strlen($message) / 8;
    for ($i = 0; $i < $blockCount; $i++) {
        $block = substr($message, $i * 8, 8);
        // 当前块与前一次MAC结果异或
        $xorBlock = '';
        for ($j = 0; $j < 8; $j++) {
            $xorBlock .= chr(ord($block[$j]) ^ ord($mac[$j]));
        }
        // 用K1加密异或后的块
        $mac = openssl_encrypt($xorBlock, 'DES-ECB', $k1, OPENSSL_RAW_DATA);
    }
    
    // 执行最终变换:K2解密 -> K1加密(ISO/IEC 9797-1算法3)
    $decrypted = openssl_decrypt($mac, 'DES-ECB', $k2, OPENSSL_RAW_DATA);
    $finalMac = openssl_encrypt($decrypted, 'DES-ECB', $k1, OPENSSL_RAW_DATA);
    
    // 转换为十六进制大写,取前8个字符(对应4字节,匹配工具输出)
    return strtoupper(substr(bin2hex($finalMac), 0, 8));
}

// 使用示例
$xmlContent = '<your-xml-content-here>';
$messageHex = bin2hex($xmlContent); // 将XML转换为十六进制
$keyHex = 'your-32-hex-characters-key'; // 32位十六进制密钥

$calculatedMAC = calculateISO9797MAC($messageHex, $keyHex);
echo $calculatedMAC;

关键说明

  • 密钥转换:必须将十六进制密钥转换为二进制,否则无法正确用于DES加密。
  • 填充方法1:严格遵循标准,无论原消息长度是否为8字节倍数,都需先添加0x80,再补0至块大小。
  • CBC-MAC逻辑:初始向量为全0,每块需与前一次加密结果异或后再加密,确保符合标准计算流程。
  • 最终变换:通过K2解密中间MAC结果,再用K1加密,对应ISO/IEC 9797-1的算法3,是匹配工具结果的核心步骤。

内容的提问来源于stack exchange,提问作者Mario de M. Barros Neto

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 01:09:51