Skip to content

Instantly share code, notes, and snippets.

@BigNerd95
Last active February 19, 2025 15:08
Show Gist options
  • Save BigNerd95/c572412036fe682afaf53ce3d2544f1f to your computer and use it in GitHub Desktop.
Save BigNerd95/c572412036fe682afaf53ce3d2544f1f to your computer and use it in GitHub Desktop.
Protocol dumper and cipher for Tecnoalarm Security Systems
#!/usr/bin/env python3
from Crypto.Cipher import AES
class TACipher():
def __init__(self, key, iv):
self._key = key # bytes
self._iv = iv # bytes
self._tail = bytes()
self._padding = 0
self.__setup_cipher__(self._key, self._iv)
def __calc_padding__(self, size):
padding = 0
mod = size % 16
if mod > 0:
padding = 16 - mod
return padding
def __add_tail_padding__(self, data):
# add precedent tail
buf = self._tail + data
# calculate padding (it is needed because the cipher has a segement_size of 16 bytes)
self._padding = self.__calc_padding__(len(buf))
# add padding
return buf + bytes(self._padding)
def __remove_tail_padding__(self, data):
# remove padding
res = data[:len(data) - self._padding]
# remove precedent tail
return res[len(self._tail):]
def __update_tail_iv__(self, data):
# add precedent tail
buf = self._tail + data
if len(buf) >= 16:
mod = len(buf) % 16
# get the new IV from last multiple of 16 bytes
if mod > 0:
self._tail = buf[-mod:] # buf: ----|----|----|----|XX
self._iv = buf[-mod - 16 : -mod] # buf: ----|----|----|XXXX|--
else:
self._tail = bytes() # buf: ----|----|----|----|
self._iv = buf[-16:] # buf: ----|----|----|XXXX|
else:
self._tail = buf # buf: XX
def __update_cipher__(self, data):
self.__update_tail_iv__(data)
self.__setup_cipher__(self._key, self._iv)
def __setup_cipher__(self, key, iv):
self.cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
def decrypt(self, data): # data (bytes)
buf = self.__add_tail_padding__(data)
buf = self.cipher.decrypt(buf)
buf = self.__remove_tail_padding__(buf)
self.__update_cipher__(data)
return buf
def encrypt(self, data): # data (bytes)
buf = self.__add_tail_padding__(data)
buf = self.cipher.encrypt(buf)
buf = self.__remove_tail_padding__(buf)
self.__update_cipher__(buf)
return buf
def main():
key = b'0123456789abcdef' # 16 bytes
iv = b'fedcba9876543210' # 16 bytes (should be random)
data = b'abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd' # any length
cipher_send = TACipher(key, iv)
cipher_recv = TACipher(key, iv)
for x in range(1,10):
encrypted_data_to_send = cipher_send.encrypt(data)
decrypted_data_received = cipher_recv.decrypt(encrypted_data_to_send)
print("Original data:", data)
print("Encrypted data:", encrypted_data_to_send)
print("Decrypted data:", decrypted_data_received) # on receiver side
print()
if __name__ == "__main__":
main()
#!/usr/bin/env python3
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
import sys
import Tecnoalarm
IP_telefono = "192.168.0.40"
IP_centrale = "192.168.0.30"
PORT_centrale = 10001
def v_print(*arg):
if 'VERBOSE' in globals():
print(*arg)
def init(dump_file):
v_print("Parsing file:", dump_file)
packet_dump = rdpcap(dump_file)
telefono_to_centrale = packet_dump.filter(lambda packet: packet.payload.src == IP_telefono and packet.payload.dst == IP_centrale and TCP in packet and packet.payload.dport == PORT_centrale and Raw in packet[TCP])
centrale_to_telefono = packet_dump.filter(lambda packet: packet.payload.src == IP_centrale and packet.payload.dst == IP_telefono and TCP in packet and packet.payload.sport == PORT_centrale and Raw in packet[TCP])
if len(telefono_to_centrale) < 1 or len(centrale_to_telefono) < 1:
print("No packet found!")
sys.exit(-1)
IV = telefono_to_centrale[0][Raw].load # IV is the first message from Phone to Central
telefono_to_centrale = telefono_to_centrale[1:] # remove IV from messages from Phone to Central
return (IV, telefono_to_centrale, centrale_to_telefono)
def hexs(data):
s = ""
for b in data:
s += str(hex(b)) + " "
return s
def print_packets(key, iv, packets):
cipher_recv = Tecnoalarm.TACipher(key, iv)
for pkt in packets:
plain = cipher_recv.decrypt(pkt[Raw].load)
print(hexs(plain))
def main(key, iv, tel2cen, cen2tel):
v_print("IV:", len(iv), "bytes")
v_print("Phone --> Central:", len(tel2cen), "packets")
v_print("Central --> Phone:", len(cen2tel), "packets")
print("\nPackets Phone --> Central")
print_packets(key, iv, tel2cen)
print("\nPackets Central --> Phone")
print_packets(key, iv, cen2tel)
if __name__ == "__main__":
if len(sys.argv) > 2:
if len(sys.argv) > 3 and sys.argv[3] == "-v":
global VERBOSE
VERBOSE = True
if len(sys.argv[2]) == 16:
iv, tel2cen, cen2tel = init(sys.argv[1])
main(sys.argv[2], iv, tel2cen, cen2tel)
else:
print("Password must be 16 bytes long")
else:
print("Usage:", sys.argv[0], "file.pcap PASSWORD [-v]" )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment