aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Crute <mcrute@gmail.com>2013-09-07 18:39:43 -0400
committerMike Crute <mcrute@gmail.com>2013-09-07 18:39:43 -0400
commitef2a2420c9602d36c1d85df09e3f4b0b55203771 (patch)
tree4adb67d7c66a4122edbe85878a6af9303ec578df
parent62bcc93047f677f322422fb1c9a0fab3f1923008 (diff)
downloadubntmfi-ef2a2420c9602d36c1d85df09e3f4b0b55203771.tar.bz2
ubntmfi-ef2a2420c9602d36c1d85df09e3f4b0b55203771.tar.xz
ubntmfi-ef2a2420c9602d36c1d85df09e3f4b0b55203771.zip
Adding inform reader
-rw-r--r--inform.py102
-rw-r--r--inform_protocol.txt30
2 files changed, 132 insertions, 0 deletions
diff --git a/inform.py b/inform.py
new file mode 100644
index 0000000..8c4b3e0
--- /dev/null
+++ b/inform.py
@@ -0,0 +1,102 @@
1import struct
2import binascii
3from Crypto.Cipher import AES
4
5
6class BinaryDataStream(object):
7
8 def __init__(self, data):
9 self.data = data
10
11 def read_int(self):
12 return struct.unpack(">i", self.data.read(4))[0]
13
14 def read_short(self):
15 return struct.unpack(">h", self.data.read(2))[0]
16
17 def read_string(self, length):
18 return self.data.read(length)
19
20
21class Cryptor(object):
22
23 def __init__(self, key, iv):
24 self.iv = iv
25 self.key = key
26 self.cipher = AES.new(key.decode("hex"), AES.MODE_CBC, iv)
27
28 @staticmethod
29 def unpad(s):
30 return s[0:-ord(s[-1])]
31
32 @staticmethod
33 def pad(s, BS=16):
34 return s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
35
36 def decrypt(self, payload):
37 return self.unpad(self.cipher.decrypt(payload))
38
39
40class InformParser(object):
41
42 PROTOCOL_MAGIC = 1414414933
43 MAX_VERSION = 1
44
45 ENCRYPTED_FLAG = 0x1
46 COMPRESSED_FLAG = 0x2
47
48 def __init__(self, input_stream, key):
49 self.input_stream = input_stream
50 self.key = key
51
52 self.magic_number = None
53 self.version = None
54 self.mac_addr = None
55 self.flags = None
56 self.iv = None
57 self.data_version = None
58 self.data_length = None
59 self.payload = None
60
61 @classmethod
62 def open(cls, filename, key):
63 return cls(BinaryDataStream(open(filename, "rb")), key)
64
65 @staticmethod
66 def _format_mac_addr(mac_bytes):
67 return "-".join([binascii.hexlify(i) for i in mac_bytes])
68
69 def _has_flag(self, flag):
70 return self.flags & flag != 0
71
72 @property
73 def formatted_mac_addr(self):
74 return self._format_mac_addr(self.mac_addr)
75
76 @property
77 def is_encrypted(self):
78 return self._has_flag(self.ENCRYPTED_FLAG)
79
80 @property
81 def is_compressed(self):
82 return self._has_flag(self.COMPRESSED_FLAG)
83
84 @property
85 def decrypted_payload(self):
86 return Cryptor(self.key, self.iv).decrypt(self.payload)
87
88 def parse(self):
89 self.magic = self.input_stream.read_int()
90 assert self.magic == self.PROTOCOL_MAGIC
91
92 self.version = self.input_stream.read_int()
93 assert self.version < self.MAX_VERSION
94
95 self.mac_addr = self.input_stream.read_string(6)
96 self.flags = self.input_stream.read_short()
97 self.iv = self.input_stream.read_string(16)
98 self.data_version = self.input_stream.read_int()
99 self.data_length = self.input_stream.read_int()
100 self.payload = self.input_stream.read_string(self.data_length)
101
102 return self
diff --git a/inform_protocol.txt b/inform_protocol.txt
new file mode 100644
index 0000000..f4d9c41
--- /dev/null
+++ b/inform_protocol.txt
@@ -0,0 +1,30 @@
1Ubiquiti Inform Protocol
2========================
3
4These are just some unstructured notes about the inform protocol at this point.
5
6Packet Structure
7----------------
84 bytes magic number integer
94 bytes version integer
106 bytes hwaddr string
112 bytes flags short
1216 bytes initialization vector string
134 bytes data version integer
144 bytes data length integer
15n bytes encrypted payload string
16
17
18magic must == 1414414933
19data version must < 1
20flags & 0x1 != 0 means encrypted
21flags & 0x2 != 0 means compressed
22
23
24The payload is AES encrypted in CBC mode using PKCS5 padding. They key is the
25device auth key from the database or a master key that is hard coded if the
26device hasn't been provisioned yet. The master key is hard coded in the
27controller code in the DeviceManager class and pretty easy to find.
28
29
30MASTER_KEY = "ba86f2bbe107c7c57eb5f2690775c712"