def _MAC_X919(KEY, DATA, MAC_IV = 8*'\x00'): u""" 银联POS 用 (1) ANSI X9.19MAC算法只使用双倍长密钥。 (2) MAC数据先按8字节分组,表示为D0~Dn,如果Dn不足8字节时,尾部以字节00补齐。 (3) 用MAC密钥左半部加密D0,加密结果与D1异或作为下一次的输入。 (4) 将上一步的加密结果与下一分组异或,然后用MAC密钥左半部加密。 (5) 直至所有分组结束。 (6) 用MAC密钥右半部解密(5)的结果。 (7) 用MAC密钥左半部加密(6)的结果。 (8) 取(7)的结果的左半部作为MAC。#未截取,自行截取 """ if len(KEY) != 16: log.error("Param KEY should be 16 Byte") raise ValueError("Param KEY should be 16 Byte") if len(MAC_IV) != 8: log.error("Param MAC_IV should be 8 BYTE") raise ValueError("Param MAC_IV should be 8 BYTE") while len(DATA) % 8 != 0: DATA += '\x00' tmp_xor = XOR(MAC_IV, DATA[:8]) tmpDes = DES(KEY[:8]) for pm8b in Str2List(DATA[8:],8): tmpData = tmpDes.encrypt(tmp_xor) tmp_xor = XOR(tmpData, pm8b) res = DES3( KEY ) return res.encrypt(tmp_xor)
def _MAC_X99(KEY, DATA, MAC_IV = 8*'\x00'): u"""银联标准算法 MAC CBC (1) ANSI X9.9MAC算法只使用单倍长密钥。 (2) MAC数据先按8字节分组,表示为D0~Dn,如果Dn不足8字节时,尾部以字节00补齐。 (3) 用MAC密钥加密D0,加密结果与D1异或作为下一次的输入。 (4) 将上一步的加密结果与下一分组异或,然后再用MAC密钥加密。 (5) 直至所有分组结束,取最后结果的左半部作为MAC。#未截取,自行截取 """ if len(KEY) != 8: log.error("Param KEY should be 8 Byte") raise ValueError("Param KEY should be 8 Byte") if len(MAC_IV) != 8: log.error("Param MAC_IV should be 8 BYTE") raise ValueError("Param MAC_IV should be 8 BYTE") res = DES( KEY ) while len(DATA) % 8 != 0: DATA += '\x00' tmp_xor = XOR(MAC_IV, DATA[:8]) for pm8b in Str2List(DATA[8:],8): tmpData = res.encrypt(tmp_xor) tmp_xor = XOR(tmpData, pm8b) return res.encrypt(tmp_xor)
def _MAC_XOR (KEY, DATA, MAC_IV = 8*'\x00'): u""" XOR MAC 银联商务 采用不足填充\x00 (1) XOR MAC算法可以使用单倍长、双倍长、三倍长密钥。 (2) MAC数据先按8字节分组,表示为D0~Dn,如果Dn不足8字节时,尾部以字节00补齐。 (3) D0~Dn所有分组异或,然后用MAC密钥加密。 (4) 取加密结果的左半部作为MAC。 """ if len(MAC_IV) != 8: log.error("Param MAC_IV should be 8 BYTE") raise ValueError("Param MAC_IV should be 8 BYTE") while len(DATA) % 8 != 0: DATA += '\x00' tmp_xor = XOR(MAC_IV, DATA[:8]) for pm8b in Str2List(DATA[8:],8): tmp_xor = XOR(tmp_xor, pm8b) if len(KEY) ==8: res = DES( KEY) else: res = DES3( KEY) return res.encrypt(tmp_xor)
def _MAC_3DES(KEY, DATA, MAC_IV = 8*'\x00', PadMode='FORCE80'): u"""一般强制填充\x80...""" if len(KEY) != 16: log.error("Param KEY should be 32 HexKey") raise ValueError("Param KEY should be 32 HexKey") if PadMode == 'FORCE80': DATA += '\x80' while len(DATA) % 8 != 0: DATA += '\x00' else: if len(DATA) % 8 != 0: DATA += '\x80' while len(DATA) % 8 != 0: DATA += '\x00' if len(MAC_IV) != 8: log.error("Param MAC_IV should be 8 BYTE") raise ValueError("Param MAC_IV should be 8 BYTE") tmp_xor = XOR(MAC_IV, DATA[:8]) tmpDes = DES( KEY[:8] ) for pm8b in Str2List(DATA[8:],8): tmpData = tmpDes.encrypt(tmp_xor) tmp_xor = XOR(tmpData, pm8b) res = DES3( KEY ) return res.encrypt(tmp_xor)
def CVN(KEY, PAN, MM, YY, ServiceID): u""" KEY: CVV业务的明文密钥,双倍长,32个HexString MM: 失效月份 01-12 数字 YY: 失效年份 00-99 数字 PAN: 用户的IC卡号,19个数字字符 ServiceID: 服务码3个数字 """ #去除空格 KEY=KEY.replace(" ", "") PAN=PAN.replace(" ", "") if len(KEY) != 32: raise ValueError("KEY") #if len(PAN) != 19: # raise ValueError("PAN") if MM not in range(1,13): raise ValueError("MM") if YY not in range(100): raise ValueError("YY") if ServiceID not in range(1000): raise ValueError("ServiceID") try: unhexs(KEY) int(PAN) except TypeError as et: raise ValueError("KEY") except ValueError as ev: raise ValueError("PAN") #检测完毕 计算 KeyA=unhexs(KEY[:16]) KeyB=unhexs(KEY[16:]) log.debug(u'CVV step1:\nKeyA:['+ HexOut(hexs(KeyA).upper()) +']KeyB:['+HexOut(hexs(KeyB).upper())+']') hData = "%s%02d%02d%03d" % (PAN, YY, MM, ServiceID) while len(hData) != 32: hData += "0" bData = unhexs(hData) log.debug(u'CVV step2:'+HexOut(hexs(bData).upper()) ) data1 = bData[:8] data2 = bData[8:] log.debug(u"CVV step3:\nBlock1:["+HexOut(hexs(data1).upper()) +"]Block2:["+HexOut(hexs(data2).upper()+']') ) ka=DES(KeyA) kb=DES(KeyB) fData = ka.encrypt(data1) log.debug(u'CVV step4:'+HexOut(hexs(fData).upper()) ) fData = XOR(fData, data2) log.debug(u'CVV step5:'+HexOut(hexs(fData).upper()) ) ###以下3步加解密事实上就是3DES对于双倍长密钥的加密方式的拆分 fData = ka.encrypt(fData) log.debug(u'CVV step6:'+HexOut(hexs(fData).upper()) ) fData = kb.decrypt(fData) log.debug(u'CVV step7:'+HexOut(hexs(fData).upper()) ) fData = ka.encrypt(fData) fHexs = hexs(fData).upper() resNum = getNum(fHexs) log.debug(u'CVV step8:'+ HexOut(resNum) ) resHex = getHex(fHexs) log.debug(u'CVV step9.1:'+ HexOut(resHex) ) resHex_Num = "" for i in resHex: resHex_Num += str(int(i,16) % 10) log.debug(u'CVV step9.2:' + HexOut(resHex_Num) ) Resault = resNum + resHex_Num log.debug(u'CVV setp10:RES:' + HexOut(Resault) ) return Resault[:3]