def _decrypt_pinblock(self, encrypted_pinblock, encrypted_terminal_key): """ Decrypt pin block """ if encrypted_terminal_key[0:1] in [b'U']: clear_terminal_key = self.cipher.decrypt( B2raw(encrypted_terminal_key[1:])) else: clear_terminal_key = self.cipher.decrypt( B2raw(encrypted_terminal_key)) cipher = DES3.new(clear_terminal_key, DES3.MODE_ECB) decrypted_pinblock = cipher.decrypt(B2raw(encrypted_pinblock)) return raw2B(decrypted_pinblock)
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 check_key_parity(self, _key): """ """ if self.skip_parity_check: return True else: key = _key[1:] if _key[0:1] in [b'U'] else _key return check_key_parity(self.cipher.decrypt(B2raw(key)))
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 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 test_B2raw(self): self.assertEqual(B2raw(b'DF1267EEDCBA9876'), b'\xdf\x12g\xee\xdc\xba\x98v')
def test_modify_key_parity_default_TPK(self): self.assertEqual( modify_key_parity(b'2t<\xd2\x82>\xf97\xa8e\xa1\x8a\x8a:\x16W'), B2raw(b'33743CD2823FF939A965A38B8B3A1759'))
def translate_pinblock(self, request): """ Get response to CA command (Translate PIN from TPK to ZPK) """ response = OutgoingMessage(header=self.header) response.set_response_code('CB') pinblock_format = request.get('Destination PIN block format') if request.get('Destination PIN block format') != request.get( 'Source PIN block format'): raise ValueError( 'Cannot translate PIN block from format {} to format {}'. format( request.get('Source PIN block format').decode('utf-8'), request.get('Destination PIN block format').decode( 'utf-8'))) if request.get('Source PIN block format') != b'01': raise ValueError('Unsupported PIN block format: {}'.format( request.get('Source PIN block format').decode('utf-8'))) # Source key parity check if not self.check_key_parity(request.get('TPK')): self._debug_trace('Source TPK parity error') if self.approve_all: self._debug_trace( 'Forced approval as --approve-all option set') response.set_error_code('00') else: response.set_error_code('10') return response # Destination key parity check if not self.check_key_parity(request.get('Destination Key')): self._debug_trace('Destination ZPK parity error') if self.approve_all: self._debug_trace( 'Forced approval as --approve-all option set') response.set_error_code('00') else: response.set_error_code('11') return response decrypted_pinblock = self._decrypt_pinblock( request.get('Source PIN block'), request.get('TPK')) self._debug_trace('Decrypted pinblock: {}'.format( decrypted_pinblock.decode('utf-8'))) pin_length = decrypted_pinblock[0:2] destination_key = request.get('Destination Key') if destination_key[0:1] in [b'U']: destination_key = destination_key[1:] cipher = DES3.new(B2raw(destination_key), DES3.MODE_ECB) translated_pin_block = cipher.encrypt(B2raw(decrypted_pinblock)) response.set_error_code('00') response.set('PIN Length', decrypted_pinblock[0:2]) response.set('Destination PIN Block', raw2B(translated_pin_block)) response.set('Destination PIN Block format', pinblock_format) return response
def get_message_length(self, message): return B2raw(bytes(str(len(message)).zfill(4), 'utf-8'))