本文根據《中國銀聯直聯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值。

資料封包:
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

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);