def encrypt(self, plain_text: bytes) -> Tuple[bytes, int]: """ Encrypts plain bytes according to the current association and connection. Returns the ciphered text and the invocation counter used with the ciphered text. It also increases the internal client invocation counter to make sure a new invocation counter is used at every encryption call. """ if not self.global_encryption_key: raise ProtectionError( "Unable to encrypt plain text. Missing global_encryption_key") if not self.global_authentication_key: raise ProtectionError( "Unable to encrypt plain text. Missing global_authentication_key" ) invocation_counter = self.client_invocation_counter ciphered_text = security.encrypt( self.security_control, system_title=self.client_system_title, invocation_counter=invocation_counter, key=self.global_encryption_key, auth_key=self.global_authentication_key, plain_text=plain_text, ) # updated the client_invocation_counter self.client_invocation_counter += 1 return ciphered_text, invocation_counter
def test_encrypt(): key = b"SUCHINSECUREKIND" auth_key = key text = b"SUPER_SECRET_TEXT" ctext = encrypt( key=key, auth_key=auth_key, invocation_counter=1, security_control=SecurityControlField( security_suite=0, authenticated=True, encrypted=True ), system_title=b"12345678", plain_text=text, ) print(ctext) out = decrypt( key=key, auth_key=auth_key, invocation_counter=1, security_control=SecurityControlField( security_suite=0, authenticated=True, encrypted=True ), system_title=b"12345678", cipher_text=ctext, ) assert text == out
def test_hls_fails(connection_with_hls: DlmsConnection): # Force state into awaiting response connection_with_hls.state.current_state = state.AWAITING_HLS_CLIENT_CHALLENGE_RESULT connection_with_hls.meter_system_title = b"12345678" connection_with_hls.meter_invocation_counter = 1 failing_action_response = xdlms.ActionResponseNormal( status=enumerations.ActionResultStatus.OTHER_REASON ) ciphered = security.encrypt( security_control=connection_with_hls.security_control, system_title=connection_with_hls.meter_system_title, auth_key=connection_with_hls.global_authentication_key, key=connection_with_hls.global_encryption_key, invocation_counter=2, plain_text=failing_action_response.to_bytes(), ) ciphered_action_response = xdlms.GeneralGlobalCipher( security_control=connection_with_hls.security_control, system_title=connection_with_hls.meter_system_title, invocation_counter=2, ciphered_text=ciphered, ) connection_with_hls.receive_data(ciphered_action_response.to_bytes()) connection_with_hls.next_event() assert connection_with_hls.state.current_state == state.NO_ASSOCIATION
def encrypt(self, plain_text: bytes): """ Encrypts plain bytes according to the current association and connection. """ if not self.global_encryption_key: raise ProtectionError( "Unable to encrypt plain text. Missing global_encryption_key") if not self.global_authentication_key: raise ProtectionError( "Unable to encrypt plain text. Missing global_authentication_key" ) return security.encrypt( self.security_control, system_title=self.client_system_title, invocation_counter=self.client_invocation_counter, key=self.global_encryption_key, auth_key=self.global_authentication_key, plain_text=plain_text, )
def test_encrypt_authenticated(): security_control = SecurityControlField( security_suite=0, authenticated=True, encrypted=True ) encryption_key = bytes.fromhex("000102030405060708090A0B0C0D0E0F") authentication_key = bytes.fromhex("D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF") system_title = bytes.fromhex("4D4D4D0000BC614E") invocation_counter = int.from_bytes(bytes.fromhex("01234567"), "big") # Get request attr 2 of clock object. plain_data = bytes.fromhex("C0010000080000010000FF0200") ciphered_text = bytes.fromhex("411312FF935A47566827C467BC7D825C3BE4A77C3FCC056B6B") assert ( encrypt( security_control=security_control, key=encryption_key, auth_key=authentication_key, system_title=system_title, invocation_counter=invocation_counter, plain_text=plain_data, ) == ciphered_text )
def test_encrypt(self): apdu = xdlms.InitiateRequest( proposed_conformance=xdlms.Conformance( general_protection=False, general_block_transfer=False, delta_value_encoding=False, attribute_0_supported_with_set=False, priority_management_supported=True, attribute_0_supported_with_get=True, block_transfer_with_get_or_read=True, block_transfer_with_set_or_write=True, block_transfer_with_action=True, multiple_references=True, data_notification=False, access=False, get=True, set=True, selective_access=True, event_notification=True, action=True, ), proposed_quality_of_service=0, client_max_receive_pdu_size=1200, proposed_dlms_version_number=6, response_allowed=True, dedicated_key=b'\x00\x11"3DUfw\x88\x99\xaa\xbb\xcc\xdd\xee\xff', ) encryption_key = bytes.fromhex("000102030405060708090A0B0C0D0E0F") authentication_key = bytes.fromhex("D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF") system_title = bytes.fromhex("4D4D4D0000BC614E") security_control = security.SecurityControlField( security_suite=0, authenticated=True, encrypted=True, broadcast_key=False, compressed=False, ) invocation_counter = 19088743 ciphered_apdu = xdlms.GlobalCipherInitiateRequest( security_control=security.SecurityControlField( security_suite=0, authenticated=True, encrypted=True, broadcast_key=False, compressed=False, ), invocation_counter=19088743, ciphered_text= b'\x80\x13\x02\xff\x8axt\x13=AL\xed%\xb4%4\xd2\x8d\xb0\x04w `k\x17[\xd5"\x11\xbehA\xdb M9\xeeo\xdb\x8e5hU', ) cipher_text = security.encrypt( security_control=security_control, system_title=system_title, key=encryption_key, auth_key=authentication_key, invocation_counter=invocation_counter, plain_text=apdu.to_bytes(), ) assert cipher_text == ciphered_apdu.ciphered_text