Skip to content

Commit c62f9a3

Browse files
bunnisiMicknl
andauthored
Add new EncryptionMethod MD5_NONCE (#352)
This Encryption Method addresses #297 for Model FAST 5688S with software version SG_SIB2_05.008 --------- Co-authored-by: Mick <[email protected]>
1 parent 6024463 commit c62f9a3

File tree

3 files changed

+27
-3
lines changed

3 files changed

+27
-3
lines changed

sagemcom_api/client.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
API_ENDPOINT,
2828
DEFAULT_TIMEOUT,
2929
DEFAULT_USER_AGENT,
30+
UINT_MAX,
3031
XMO_ACCESS_RESTRICTION_ERR,
3132
XMO_AUTHENTICATION_ERR,
3233
XMO_INVALID_SESSION_ERR,
@@ -91,10 +92,10 @@ def __init__(
9192
self.username = username
9293
self.authentication_method = authentication_method
9394
self.password = password
95+
self._current_nonce = None
9496
self._password_hash = self.__generate_hash(password)
9597
self.protocol = "https" if ssl else "http"
9698

97-
self._current_nonce = None
9899
self._server_nonce = ""
99100
self._session_id = 0
100101
self._request_id = -1
@@ -126,14 +127,31 @@ async def close(self) -> None:
126127
"""Close the websession."""
127128
await self.session.close()
128129

129-
def __generate_nonce(self):
130+
def __generate_nonce(self, upper_limit=500000):
130131
"""Generate pseudo random number (nonce) to avoid replay attacks."""
131-
self._current_nonce = math.floor(random.randrange(0, 500000))
132+
self._current_nonce = math.floor(random.randrange(0, upper_limit))
132133

133134
def __generate_request_id(self):
134135
"""Generate sequential request ID."""
135136
self._request_id += 1
136137

138+
def __generate_md5_nonce_hash(self):
139+
"""Build MD5 with nonce hash token. UINT_MAX is hardcoded in the firmware."""
140+
141+
def md5(input_string):
142+
return hashlib.md5(input_string.encode()).hexdigest()
143+
144+
n = (
145+
self.__generate_nonce(UINT_MAX)
146+
if self._current_nonce is None
147+
else self._current_nonce
148+
)
149+
f = 0
150+
l_nonce = ""
151+
ha1 = md5(self.username + ":" + l_nonce + ":" + md5(self.password))
152+
153+
return md5(ha1 + ":" + str(f) + ":" + str(n) + ":JSON:/cgi/json-req")
154+
137155
def __generate_hash(self, value, authentication_method=None):
138156
"""Hash value with selected encryption method and return HEX value."""
139157
auth_method = authentication_method or self.authentication_method
@@ -146,6 +164,9 @@ def __generate_hash(self, value, authentication_method=None):
146164
if auth_method == EncryptionMethod.SHA512:
147165
return hashlib.sha512(bytes_object).hexdigest()
148166

167+
if auth_method == EncryptionMethod.MD5_NONCE:
168+
return self.__generate_md5_nonce_hash()
169+
149170
return value
150171

151172
def __get_credential_hash(self):

sagemcom_api/const.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@
1515
XMO_UNKNOWN_PATH_ERR = "XMO_UNKNOWN_PATH_ERR"
1616
XMO_MAX_SESSION_COUNT_ERR = "XMO_MAX_SESSION_COUNT_ERR"
1717
XMO_LOGIN_RETRY_ERR = "XMO_LOGIN_RETRY_ERR"
18+
19+
UINT_MAX = 4294967295

sagemcom_api/enums.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ class EncryptionMethod(StrEnum):
1616
"""Encryption method defining the password hash."""
1717

1818
MD5 = "MD5"
19+
MD5_NONCE = "MD5_NONCE"
1920
SHA512 = "SHA512"

0 commit comments

Comments
 (0)