def generate_key(self, request): """ Get response to HC command TODO: generating keys for different schemes """ response = OutgoingMessage(data=None, header=self.header) response.set_response_code('HD') response.set_error_code('00') new_clear_key = modify_key_parity(bytes(os.urandom(16))) self._debug_trace('Generated key: {}'.format(raw2str(new_clear_key))) current_key = request.get('Current Key') if current_key[0:1] in [b'U']: current_key = current_key[1:] clear_current_key = self.cipher.decrypt(B2raw(current_key)) curr_key_cipher = DES3.new(clear_current_key, DES3.MODE_ECB) new_key_under_current_key = curr_key_cipher.encrypt(new_clear_key) new_key_under_lmk = self.cipher.encrypt(new_clear_key) response.set('New key under the current key', b'U' + raw2B(new_key_under_current_key)) response.set('New key under LMK', b'U' + raw2B(new_key_under_lmk)) return response
def info(self): """ """ dump = '' dump += 'LMK: {}\n'.format(raw2str(self.LMK)) dump += 'Firmware version: {}\n'.format(self.firmware_version) if self.header: dump += 'Message header: {}\n'.format(self.header.decode('utf-8')) return dump
def __init__(self, host=None, port=None, id=None, merchant=None, master_key=None, terminal_key=None, show_keys=None): """ Terminal initialization """ self.pinblock_format = '01' # Host to connect to self.host = host if host else '127.0.0.1' # Port ot connect to try: self.port = int(port) if port else 1337 except ValueError: raise ValueError('Invalid TCP port: {}'.format(port)) # Terminal ID self.terminal_id = id if id else '10001337' # Merchant ID self.merchant_id = merchant if merchant else '999999999999001' self.currency = '643' self.country_code = '643' # Keys self.keyfile_name = '.terminalkey.cache' self.master_key = bytes.fromhex( master_key) if master_key else bytes.fromhex( 'CF7730DBA6CAC5E13C3FB45CAF8D71E1') if terminal_key: self.terminal_key = bytes.fromhex(terminal_key) else: stored_key = self.get_stored_key() if stored_key: self.terminal_key = bytes.fromhex(stored_key) else: self.terminal_key = bytes.fromhex( 'FA9F90D49CB27B7D14A3FA9CCCFF6CB7') self.store_terminal_key(raw2str(self.terminal_key)) self.tpk_cipher = DES3.new(self.terminal_key, DES3.MODE_ECB) self.tmk_cipher = DES3.new(self.master_key, DES3.MODE_ECB) self.show_keys = show_keys self.print_keys()
def translate_zpk(self, request): """ Get response to FA command """ response = OutgoingMessage(header=self.header) response.set_response_code('FB') response.set_error_code('00') zmk_under_lmk = request.get('ZMK')[1:33] if zmk_under_lmk: clear_zmk = self.cipher.decrypt(B2raw(zmk_under_lmk)) self._debug_trace('Clear ZMK: {}'.format(raw2str(clear_zmk))) zmk_key_cipher = DES3.new(clear_zmk, DES3.MODE_ECB) zpk_under_zmk = request.get('ZPK')[1:33] if zpk_under_zmk: clear_zpk = zmk_key_cipher.decrypt(B2raw(zpk_under_zmk)) self._debug_trace('Clear ZPK: {}'.format(raw2str(clear_zpk))) zpk_under_lmk = self.cipher.encrypt(clear_zpk) response.set('ZPK under LMK', b'U' + raw2B(zpk_under_lmk)) response.set('Key Check Value', key_CV(raw2B(zpk_under_lmk), 6)) response.set_error_code('00') else: self._debug_trace('ERROR: Invalid ZPK') response.set_error_code('01') else: self._debug_trace('ERROR: Invalid ZMK') response.set_error_code('01') return response
def get_encrypted_pin(self, clear_pin, card_number): """ Get PIN block in ISO 0 format, encrypted with the terminal key """ if not self.terminal_key: print('Terminal key is not set') return '' if self.pinblock_format == '01': try: pinblock = bytes.fromhex(get_pinblock(clear_pin, card_number)) #print('PIN block: {}'.format(raw2str(pinblock))) except TypeError: return '' encrypted_pinblock = self.tpk_cipher.encrypt(pinblock) return raw2str(encrypted_pinblock) else: print('Unsupported PIN Block format') return ''
def generate_key_a0(self, request): """ Get response to A0 command """ response = OutgoingMessage(header=self.header) response.set_response_code('A1') response.set_error_code('00') new_clear_key = modify_key_parity(bytes(os.urandom(16))) self._debug_trace('Generated key: {}'.format(raw2str(new_clear_key))) new_key_under_lmk = self.cipher.encrypt(new_clear_key) response.set('Key under LMK', b'U' + raw2B(new_key_under_lmk)) zmk_under_lmk = request.get('ZMK/TMK')[1:33] if zmk_under_lmk: clear_zmk = self.cipher.decrypt(B2raw(zmk_under_lmk)) zmk_key_cipher = DES3.new(clear_zmk, DES3.MODE_ECB) new_key_under_zmk = zmk_key_cipher.encrypt(new_clear_key) response.set('Key under ZMK', b'U' + raw2B(new_key_under_zmk)) response.set('Key Check Value', key_CV(raw2B(new_clear_key), 6)) return response
def set_terminal_key(self, encrypted_key): """ Change the terminal key. The encrypted_key is a hex string. encrypted_key is expected to be encrypted under master key """ if encrypted_key: try: new_key = bytes.fromhex(encrypted_key) if len(self.terminal_key) != len(new_key): # The keys must have equal length return False self.terminal_key = self.tmk_cipher.decrypt(new_key) self.store_terminal_key(raw2str(self.terminal_key)) self.tpk_cipher = DES3.new(self.terminal_key, DES3.MODE_ECB) self.print_keys() return True except ValueError: return False return False
def test_raw2str(self): self.assertEqual(raw2str(b'\xdf\x12g\xee\xdc\xba\x98v'), 'DF1267EEDCBA9876')
def print_keys(self): if self.show_keys: print(' Master key: {}'.format(raw2str(self.master_key))) print('Terminal key: {}'.format(raw2str(self.terminal_key)))
def get_terminal_key(self): """ Get string representation of terminal key (needed mostly for debugging purposes) """ return raw2str(self.terminal_key)