天天看点

POS DES MAC 算法

本文根据《中国银联直联pos终端规范》的阐述,用c语言编程实现,该算法在实际的商业pos终端中使用。pos终端采用ECB的加密方式,简述如下:

a) 将欲发送给pos中心的消息中,从消息类型(mti)到63域之间的部分构成mac 

elemement block (mab)。

b) 对mab,按每8个字节做异或(不管信息中的字符格式),如果最后不满8个字节,则添加“0x00”。

示例 :

mab = m1 m2 m3 m4

其中: 

m1 = ms11 ms12 ms13 ms14 ms15 ms16 ms17 ms18

m2 = ms21 ms22 ms23 ms24 ms25 ms26 ms27 ms28

m3 = ms31 ms32 ms33 ms34 ms35 ms36 ms37 ms38

m4 = ms41 ms42 ms43 ms44 ms45 ms46 ms47 ms48

按如下规则进行异或运算:

ms11 ms12 ms13 ms14 ms15 ms16 ms17 ms18

xor) ms21 ms22 ms23 ms24 ms25 ms26 ms27 ms28

---------------------------------------------------

temp block1 = tm11 tm12 tm13 tm14 tm15 tm16 tm17 tm18

然后,进行下一步的运算:

tm11 tm12 tm13 tm14 tm15 tm16 tm17 tm18

xor) ms31 ms32 ms33 ms34 ms35 ms36 ms37 ms38

temp block2 = tm21 tm22 tm23 tm24 tm25 tm26 tm27 tm28

再进行下一步的运算:

tm21 tm22 tm23 tm24 tm25 tm26 tm27 tm28

xor) ms41 ms42 ms43 ms44 ms45 ms46 ms47 ms48

result block = tm31 tm32 tm33 tm34 tm35 tm36 tm37 tm38

c) 将异或运算后的最后8个字节(result block)转换成16 个hexdecimal:

= tm311 tm312 tm321 tm322 tm331 tm332 tm341 tm342 ||

tm351 tm352 tm361 tm362 tm371 tm372 tm381 tm382

d) 取前8 个字节用mak加密:

enc block1 = emak(tm311 tm312 tm321 tm322 tm331 tm332 tm341 tm342)

= en11 en12 en13 en14 en15 en16 en17 en18

e) 将加密后的结果与后8 个字节异或:

en11 en12 en13 en14 en15 en16 en17 en18

xor) tm351 tm352 tm361 tm362 tm371 tm372 tm381 tm382

------------------------------------------------------------

temp block= te11 te12 te13 te14 te15 te16 te17 te18

f) 用异或的结果temp block 再进行一次单倍长密钥算法运算。

enc block2 = emak(te11 te12 te13 te14 te15 te16 te17 te18)

= en21 en22 en23 en24 en25 en26 en27 en28

g) 将运算后的结果(enc block2)转换成16 个hexdecimal:

enc block2 = en21 en22 en23 en24 en25 en26 en27 en28

= em211 em212 em221 em222 em231 em232 em241 em242 ||

em251 em252 em261 em262 em271 em272 em281 em282

enc result= %h84, %h56, %hb1, %hcd, %h5a, %h3f, %h84, %h84

转换成16 个hexdecimal:

“8456b1cd5a3f8484”

h) 取前8个字节作为mac值。

取”8456b1cd”为mac值。

POS DES MAC 算法

数据报文:  

0x 1234567890abcdefabcdef1234567890   //$body  

mak:2222222222222222  

mac计算:  

m1 = 0x 1234567890abcdef   

m2 = 0x abcdef1234567890  

m1 xor m2 结果: 0x b9f9b96aa4fdb57f  

扩展成16字节数据:0x 42394639423936414134464442353746  

mak加密前半部分数据结果:0x 9fde90a34cf73b2e  

加密结果与后半部分数据异或,结果:0x deead6e70ec20c68  

mak加密异或结果:0x e267b6e21913d339  

扩展成16字节数据:0x45323637423645323139313344333339  

mac:e267b6e2  

php mac

POS DES MAC 算法

public function splitdata($hexmacdatasource, $num=16)  

{  

    $len = 0;  

    $modvalue = strlen($hexmacdatasource) % $num;  

    if($modvalue != 0)  

    {  

        $hexsrcdatalen = strlen($hexmacdatasource);  

        $totallen = $hexsrcdatalen + ($num - $modvalue);  

        $hexmacdatasource = str_pad($hexmacdatasource, $totallen, "0");//16进制右补0  

    }  

    $len = strlen($hexmacdatasource) / $num;  

    $ds = array();  

    for ($i = 0; $i < $len; $i++)  

        if (strlen($hexmacdatasource) >= $num)  

        {  

            $ds[] = substr($hexmacdatasource,0, $num);  

            $hexmacdatasource = substr($hexmacdatasource,$num);  

        } else  

            throw new exception("填充的数据非法!",6008);  

        }  

    return $ds;  

}  

public function hexxor($hexstr1 , $hexstr2)  

    return str_pad(strtoupper(gmp_strval(gmp_xor(gmp_init($hexstr1, 16),gmp_init($hexstr2, 16)), 16)),16,'0',str_pad_left);  

public function getbodymac($body)  

    //拆分mac数据源,每组16位hex(8 byte())  

    $ds = $this->splitdata($body);  

    $des = "";  

    for ($i = 0; $i < count($ds); $i++)  

        if ($i == 0)  

            $des = $ds[$i];//$ds[$i] 是16进制数  

            $des = $this->hexxor($des, $ds[$i]);  

    #异或结果扩展成 16字节 的 hex  

    $hexstr16 = $this->encodehex($des);  

    #加密前8字节数据  

    $left8  = substr($hexstr16,0,16);  

    $right8 = substr($hexstr16,16,16);  

    $tmpxor = $this->hexxor($this->encryptbydes($left8,$this->mackey), $right8);  

    $bodymac =  substr($this->encryptbydes($tmpxor,$this->mackey),0,8);  

    return $bodymac;  

public function encodehex($str)  

    return strtoupper(bin2hex($str));  

#开始4个字节报文长度

$requestbodylength = intval(trim(substr($request, 0, 4)));

$body = substr($request, 4, $requestbodylength);

#报文体

$requestbody = substr($body, 0, $requestbodylength - 8);

#最后8个字节为mac

$requestmac = substr($body, -8);

继续阅读