我正在try 使用PHP中的32字符十六进制密钥从XML生成ISO/IEC 9797-1 MAC,但我无法获得预期的结果.

我try 了使用open_ssl和phpseclib的各种方法,但都没有产生预期的输出. 为了验证我的MAC,我使用网站https://paymentcardtools.com/emv-misc/mac-calculator,在那里我在数据字段中将我的XML转换为十六进制,使用填充方法1,并输入我的32位密钥.

我需要知道如何在PHP中实现同样的结果.以前有人做过这样的事吗?

$length = strlen($message);
        $padding = 8 - ($length % 8);
        $message .= str_repeat(chr(0), $padding);

        // Separate the first DES key and 3DES key
        $des_key = substr($key, 0, 8);
        $tripledes_key = substr($key, 8, 16);

        // Use the first DES key for CBC-MAC
        $cbc_mac = openssl_encrypt($message, 'DES-ECB', $des_key, OPENSSL_RAW_DATA);

        // Use 3DES for the final block
        $last_block = substr($message, -8);
        $tripledes_cipher = openssl_encrypt($last_block, 'DES-EDE3-ECB', $tripledes_key, OPENSSL_RAW_DATA);

        // The result is the last 8 bytes of the triple DES cipher
        return substr(strtoupper(bin2hex(substr($tripledes_cipher, -8))), 0, 8);

推荐答案

确定MAC所需的步骤(根据算法3)为(here):

  • 填充法(OP应用方法一),S,here
  • 输入/初始转换1,S.here和迭代,S.here.
  • 输出转化3,S.here.
  • 截断,S.here.

一种可能的PHP实现是(包括测试数据):

<?php
function xored($data1, $data2) {
    $result = '';
    for($n = 0; $n < strlen($data1); $n++){
        $result .= substr($data1, $n, 1) ^ substr($data2, $n, 1);
    }
    return $result;    
}

function encrypt($data, $key){
    return openssl_encrypt($data, 'DES-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
}

function decrypt($data, $key){
    return openssl_decrypt($data, 'DES-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
}

$messageHex = '54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67';
$message = hex2bin($messageHex);

// get 1st and 2nd DES key
$keyHex = '04984575FE4A526123D6F876B3E3371A';
$key = hex2bin($keyHex);
$desKey1 = substr($key, 0, 8);
$desKey2 = substr($key, 8, 16);

// padding method 1: zero pad only if length criterion is not met
$length = strlen($message);
$padding = (8 - ($length % 8)) % 8; 
$message .= str_repeat(chr(0), $padding);

// input/initial transformation 1 and iteration
$messageLen = strlen($message);
for ($i = 0; $i < $messageLen; $i = $i + 8) {
    $d = substr($message, $i, 8);
    $i == 0 ? $in = $d : $in = xored($d, $h);
    $h = encrypt($in, $desKey1);
}

// output transformation 3
$innerDecryption = decrypt($h, $desKey2);
$outerEncryption = encrypt($innerDecryption, $desKey1);

// truncation
$mac = substr($outerEncryption, 0, 8);

print(bin2hex($mac) . PHP_EOL); // 37b44913c7a43700
?>

对于使用的测试数据,根据链接的网站,MAC为0x37b44913c7a43700:

enter image description here

Php相关问答推荐

Laravel迁移返回SQL错误,但SQL有效且工作正常

Symfony Api平台:按自定义实体方式排序结果

如何在Laravel Model中自定义多个日期属性的日期格式?

基于服务器的不同地平线配置

fpm-php + nginx + POST数据

Rappasoft Datatables V2(我想在另一个表具有相同值列时显示数据)

用ajax获取文件 - CORS问题&;设置缓存?

htaccess 配置提供静态文件和动态文件

使用 secure 和 httponly 选项删除 php 中的 cookie 值得吗?

使用自定义规则进行 Livewire 验证不会显示错误

如何使用不同的方法编写嵌套连接查询并将两列连接成一列在 laravel 查询生成器中

Google Sheets PHP API - 添加多个选项卡时出现问题

显示时间范围内的可用空位,同时考虑已预订的空位

PHP header() 是否缓存重定向,如果是,如何防止它这样做?

PHP / DOM : 解析 HTML 以提取基于类的数​​据

为什么在 phpunit 的开头测试 PHP_VERSION?

我需要获取传递到这个数组中的数据,但我没有得到它,因为在 Laravel 中数组是这样出现的

php-http/discovery 插件 1.15.1 是否仍在使用自己的模块 destruct Contao 4.13 中的composer 安装?

WordPress 函数 get_post(post_id) 是否查询数据库?

复杂的mysql查询问题