def decrypt( self, ciphered_text: bytes, ): """ Encrypts ciphered bytes according to the current association and connection. In the case of AARE we have not had the opportunity to """ if not self.global_encryption_key: raise ProtectionError( "Unable to decrypt ciphered text. Missing global_encryption_key" ) if not self.global_authentication_key: raise ProtectionError( "Unable to decrypt ciphered text. Missing global_authentication_key" ) if not self.meter_system_title: raise ProtectionError( "Unable to decrypt ciphered text. Have not received the meters system title." ) return security.decrypt( self.security_control, system_title=self.meter_system_title, invocation_counter=self.meter_invocation_counter, key=self.global_encryption_key, auth_key=self.global_authentication_key, cipher_text=ciphered_text, )
def test_decrypt(self): encryption_key = bytes.fromhex("000102030405060708090A0B0C0D0E0F") authentication_key = bytes.fromhex("D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF") system_title = bytes.fromhex("4D4D4D0000BC614E") 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', ) plain_text = security.decrypt( security_control=apdu.security_control, system_title=system_title, invocation_counter=apdu.invocation_counter, cipher_text=apdu.ciphered_text, key=encryption_key, auth_key=authentication_key, ) unciphered_apdu = XDlmsApduFactory.apdu_from_bytes(plain_text) print(unciphered_apdu) assert isinstance(unciphered_apdu, xdlms.InitiateRequest)
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 unprotect(self, event): """ Removes protection from APDUs and return a new the unprotected version """ if isinstance(event, (acse.ApplicationAssociationResponseApdu, acse.ReleaseResponseApdu)): if event.user_information: if isinstance(event.user_information.content, xdlms.GlobalCipherInitiateResponse): received_invocation_counter = ( event.user_information.content.invocation_counter) self.validate_received_invocation_counter( received_invocation_counter) self.meter_invocation_counter = received_invocation_counter plain_text = security.decrypt( security_control=event.user_information.content. security_control, system_title=self.meter_system_title or event.system_title, invocation_counter=event.user_information.content. invocation_counter, key=self.global_encryption_key, auth_key=self.global_authentication_key, cipher_text=event.user_information.content. ciphered_text, ) event.user_information.content = ( xdlms.InitiateResponseApdu.from_bytes(plain_text)) elif isinstance(event, xdlms.GeneralGlobalCipherApdu): self.validate_received_invocation_counter(event.invocation_counter) self.meter_invocation_counter = event.invocation_counter plain_text = security.decrypt( security_control=event.security_control, system_title=event.system_title, invocation_counter=event.invocation_counter, key=self.global_encryption_key, auth_key=self.global_authentication_key, cipher_text=event.ciphered_text, ) event = XDlmsApduFactory.apdu_from_bytes(plain_text) else: raise RuntimeError( f"Unable to handle decryption/unprotection of {event}") return event
def to_plain_apdu(self, encryption_key, authentication_key) -> bytes: plain_text = decrypt( security_control=self.security_control, key=encryption_key, auth_key=authentication_key, invocation_counter=self.invocation_counter, cipher_text=self.ciphered_text, system_title=self.system_title, ) return bytes(plain_text)
def test_decrypt_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 ( decrypt( security_control=security_control, key=encryption_key, auth_key=authentication_key, system_title=system_title, invocation_counter=invocation_counter, cipher_text=ciphered_text, ) == plain_data )