edl/edlclient/Tools/sierrakeygen.py
2024-06-10 01:44:14 +08:00

687 lines
32 KiB
Python
Executable file

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# (c) B.Kerler 2019-2023 under GPLv3 license
# If you use my code, make sure you refer to my name
#
# !!!!! If you use this code in commercial products, your product is automatically
# GPLv3 and has to be open sourced under GPLv3 as well. !!!!!
import copy
import sys
import argparse
import time
import serial.tools.list_ports
from Exscript.protocols.telnetlib import Telnet
from binascii import hexlify, unhexlify
import logging
import logging.config
import logging.handlers
import colorama
class ColorFormatter(logging.Formatter):
LOG_COLORS = {
logging.ERROR: colorama.Fore.RED,
logging.DEBUG: colorama.Fore.LIGHTMAGENTA_EX,
logging.WARNING: colorama.Fore.YELLOW,
}
def format(self, record, *args, **kwargs):
# if the corresponding logger has children, they may receive modified
# record, so we want to keep it intact
new_record = copy.copy(record)
if new_record.levelno in self.LOG_COLORS:
pad = ""
if new_record.name != "root":
print(new_record.name)
pad = "[LIB]: "
# we want levelname to be in different color, so let's modify it
new_record.msg = "{pad}{color_begin}{msg}{color_end}".format(
pad=pad,
msg=new_record.msg,
color_begin=self.LOG_COLORS[new_record.levelno],
color_end=colorama.Style.RESET_ALL,
)
# now we can let standart formatting take care of the rest
return super(ColorFormatter, self).format(new_record, *args, **kwargs)
class LogBase(type):
debuglevel = logging.root.level
def __init__(cls, *args):
super().__init__(*args)
logger_attribute_name = '_' + cls.__name__ + '__logger'
logger_debuglevel_name = '_' + cls.__name__ + '__debuglevel'
logger_name = '.'.join([c.__name__ for c in cls.mro()[-2::-1]])
LOG_CONFIG = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"root": {
"()": ColorFormatter,
"format": "%(name)s - %(message)s",
}
},
"handlers": {
"root": {
# "level": cls.__logger.level,
"formatter": "root",
"class": "logging.StreamHandler",
"stream": "ext://sys.stdout",
}
},
"loggers": {
"": {
"handlers": ["root"],
# "level": cls.debuglevel,
"propagate": False
}
},
}
logging.config.dictConfig(LOG_CONFIG)
logger = logging.getLogger(logger_name)
setattr(cls, logger_attribute_name, logger)
setattr(cls, logger_debuglevel_name, cls.debuglevel)
'''
C7 = 7 0 0 2 7 5 0
C6 = 3 1 7 0 3 0 1
C5 = 0 2 5 3 0 3 2
C8 = 1 3 3 1 5 7 3
C4 = 5 4 1 4 1 1 4
'''
prodtable = {
"MDM8200": dict(openlock=0, openmep=1, opencnd=0, clen=8, init=[1, 3, 5, 7, 0],
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 2, 4, 1, 3, 0, 3, 4, 0)"),
# MC878XC_F1.2.3.15 verified, key may be stored in nvitem 0x4e21;MC8700 M3.0.9.0 verified
"MDM9200": dict(openlock=0, openmep=1, opencnd=0, clen=8, init=[7, 3, 0, 1, 5],
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"),
# AC881U, EM8805 SWI9X15C_05.05.58.00, at!openlock?6A1F1CEA298A14B0 => AT!OPENLOCK="3A9EA70D86FEE58C"
"MDM9200_V1": dict(openlock=2, openmep=1, opencnd=0, clen=8, init=[7, 3, 0, 1, 5],
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"), # AC710
"MDM9200_V2": dict(openlock=3, openmep=1, opencnd=0, clen=8, init=[7, 3, 0, 1, 5],
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"), # AC775
"MDM9200_V3": dict(openlock=8, openmep=1, opencnd=8, clen=8, init=[7, 3, 0, 1, 5],
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"), # AC775
"MDM9x15": dict(openlock=0, openmep=1, opencnd=0, clen=8, init=[7, 3, 0, 1, 5],
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"),
# 9x15C 06.03.32.02, AC340U 1.13.12.14 verified, #AT!CUSTOM=\"ADBENABLE\",1
"MDM9x07": dict(openlock=9, openmep=10, opencnd=9, clen=8, init=[7, 3, 0, 1, 5],
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"),
# SWI9X07Y_02.25.02.01
"MDM9x30": dict(openlock=5, openmep=4, opencnd=5, clen=8, init=[7, 3, 0, 1, 5],
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"),
# MC7455_2.30.01.01 #4
"MDM9x30_V1": dict(openlock=17, openmep=15, opencnd=17, clen=8, init=[7, 3, 0, 1, 5],
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"),
# AC791L/AC790S NTG9X35C_02.08.29.00
"MDM9x40": dict(openlock=11, openmep=12, opencnd=11, clen=8, init=[7, 3, 0, 1, 5],
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"), # AC815s
"MDM9x50": dict(openlock=7, openmep=6, opencnd=7, clen=8, init=[7, 3, 0, 1, 5],
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"), # EM7565
"MDM9x06": dict(openlock=20, openmep=19, opencnd=20, clen=8, init=[7, 3, 0, 1, 5],
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"), # WP77xx
"SDX55": dict(openlock=22, openmep=21, opencnd=22, clen=8, init=[7, 3, 0, 1, 5], # MR5100, MR6400 old fw
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"),
"MDM9x15A": dict(openlock=24, openmep=23, opencnd=24, clen=8, init=[7, 3, 0, 1, 5], # AC779S
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"),
"SDX65": dict(openlock=25, openmep=21, opencnd=26, clen=8, init=[7, 3, 0, 1, 5], # MR6400 new fw
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)")
}
infotable = {
"MDM8200": ["M81A", "M81B", "AC880", "AC881", "MC8780", "MC8781", "AC880E", "AC881E", "EM8780", "EM8781",
"MC8780V", "MC8781V", "MC8700", "AC308U"],
"MDM9200": ["AC710", "MC8775", "MC8775V", "AC875", "MC8700", "AC313U", "MC8801", "MC7700", "MC7750", "MC7710",
"EM7700", "770S", "781S"],
"MDM9200_V1": ["AC710", "MC8775", "MC8775V", "AC875", "MC8700", "AC313U", "MC8801", "MC7700", "MC7750",
"MC7710", "EM7700"],
"MDM9200_V2": ["AC775", "PC7200"],
"MDM9200_V3": ["AC775"],
"MDM9x07": ["SWI9X07Y", "WP76xx"],
"MDM9x06": ["SWI9X06Y", "WP77xx"],
"MDM9x15": ["SWI9X15C", "AR7550", "AR7552", "AR7554", "EM7355", "EM7655", "MC7354", "WP7100", "WP7102", "WP7104",
"MC7305", "EM7305", "MC8805", "EM8805", "MC7350", "MC7350-L", "MC7802", "MC7304", "AR7556", "AR7558",
"WP75xx", "WP85xx", "WP8548", "WP8548G", "AC340U"],
"MDM9x15A": ["AC779S"],
"MDM9x30": ["EM7455", "MC7455", "EM7430", "MC7430"],
"MDM9x30_V1": ["Netgear AC790/MDM9230"],
"MDM9x40": ["MR1100", "AC815s", "AC785s", "AC797S"],
"MDM9x50": ["EM7565", "EM7565-9", "EM7511", "EM7411"],
"SDX55": ["MR5100", "MR5200", "ac797-100eus", "MR6400"],
"SDX65": ["MR6400", "MR6500", "MR6110", "MR6150", "MR6450", "MR6550"]
}
# 0 MC8775_H2.0.8.19 !OPENLOCK, !OPENCND .. MC8765V,MC8765,MC8755V,MC8775,MC8775V,MC8775,AC850,
# AC860,AC875,AC881,AC881U,AC875, AC340U 1.13.12.14
keytable = bytearray([0xF0, 0x14, 0x55, 0x0D, 0x5E, 0xDA, 0x92, 0xB3, 0xA7, 0x6C, 0xCE, 0x84, 0x90, 0xBC, 0x7F, 0xED,
# 1 MC8775_H2.0.8.19 AC340U, OPENMEP default
0x61, 0x94, 0xCE, 0xA7, 0xB0, 0xEA, 0x4F, 0x0A, 0x73, 0xC5, 0xC3, 0xA6, 0x5E, 0xEC, 0x1C, 0xE2,
# 2 AC750,AC710,AC7XX,SB750A,SB750,PC7000,AC313u OPENMEP
0x39, 0xC6, 0x7B, 0x04, 0xCA, 0x50, 0x82, 0x1F, 0x19, 0x63, 0x36, 0xDE, 0x81, 0x49, 0xF0, 0xD7,
# 3 AC775,PC7200
0xDE, 0xA5, 0xAD, 0x2E, 0xBE, 0xE1, 0xC9, 0xEF, 0xCA, 0xF9, 0xFE, 0x1F, 0x17, 0xFE, 0xED, 0x3B,
# 4 MC7455_02.30.01.01 OPENMEP
0xFE, 0xD4, 0x40, 0x52, 0x2D, 0x4B, 0x12, 0x5C, 0xE7, 0x0D, 0xF8, 0x79, 0xF8, 0xC0, 0xDD, 0x37,
# 5 MC7455_02.30.01.01 OPENLOCK
0x3B, 0x18, 0x99, 0x6B, 0x57, 0x24, 0x0A, 0xD8, 0x94, 0x6F, 0x8E, 0xD9, 0x90, 0xBC, 0x67, 0x56,
# 6 SWI9x50 Openmep Key SWI9X50C_01.08.04.00
0x47, 0x4F, 0x4F, 0x44, 0x4A, 0x4F, 0x42, 0x44, 0x45, 0x43, 0x4F, 0x44, 0x49, 0x4E, 0x47, 0x2E,
# 7 SWI9x50 Openlock Key SWI9X50C_01.08.04.00
0x4F, 0x4D, 0x41, 0x52, 0x20, 0x44, 0x49, 0x44, 0x20, 0x54, 0x48, 0x49, 0x53, 0x2E, 0x2E, 0x2E,
# 8 MDM8200 Special
0x8F, 0xA5, 0x85, 0x05, 0x5E, 0xCF, 0x44, 0xA0, 0x98, 0x8B, 0x09, 0xE8, 0xBB, 0xC6, 0xF7, 0x65,
# 9 SWI9x07 Openlock Key 02.25.02.01
0x4D, 0x42, 0xD8, 0xC1, 0x25, 0x44, 0xD8, 0xA0, 0x1D, 0x80, 0xC4, 0x52, 0x8E, 0xEC, 0x8B, 0xE3,
# 10 SWI9x07 Openmep Key 02.25.02.01
0xED, 0xA9, 0xB7, 0x0A, 0xDB, 0x85, 0x3D, 0xC0, 0x92, 0x49, 0x7D, 0x41, 0x9A, 0x91, 0x09, 0xEE,
# 11 NTG9X40C_11.14.08.11 / mdm9x40r11_core AC815s / SWI9x50 MR1100 Openlock Key
0x8A, 0x56, 0x03, 0xF0, 0xBB, 0x9C, 0x13, 0xD2, 0x4E, 0xB2, 0x45, 0xAD, 0xC4, 0x0A, 0xE7, 0x52,
# 12 SWI9x50 MR1100 Openmep Key
0x2A, 0xEF, 0x07, 0x2B, 0x19, 0x60, 0xC9, 0x01, 0x8B, 0x87, 0xF2, 0x6E, 0xC1, 0x42, 0xA8, 0x3A,
# 13 SWI9x50/SWI9x65 Unknown key
0x28, 0x55, 0x48, 0x52, 0x24, 0x72, 0x63, 0x37, 0x14, 0x26, 0x37, 0x50, 0xBE, 0xFE, 0x00, 0x00,
# 14 SWI9x50,SWI9X06Y,SWI9x65 IMEI nv key
0x22, 0x63, 0x48, 0x02, 0x24, 0x72, 0x27, 0x37, 0x19, 0x26, 0x37, 0x50, 0xBE, 0xEF, 0xCA, 0xFE,
# 15 NTG9X35C_02.08.29.00 Openmep Key AC791L/AC790S Old
0x98, 0xE1, 0xC1, 0x93, 0xC3, 0xBF, 0xC3, 0x50, 0x8D, 0xA1, 0x35, 0xFE, 0x50, 0x47, 0xB3, 0xC4,
# 16 NTG9X35C_02.08.29.00 Openmep Key AC791/AC790S, NTGX55_10.25.15.02 MR5100 Alternative, NTG9X40C_30.00.12.00 Alternative
0x61, 0x94, 0xCE, 0xA7, 0xB0, 0xEA, 0x4F, 0x0A, 0x73, 0xC5, 0xC3, 0xA6, 0x5E, 0xEC, 0x1C, 0xE2,
# 17 NTG9X35C_02.08.29.00 Openlock Key AC791/AC790S Old
0xC5, 0x50, 0x40, 0xDA, 0x23, 0xE8, 0xF4, 0x4C, 0x29, 0xE9, 0x07, 0xDE, 0x24, 0xE5, 0x2C, 0x1D,
# 18 NTG9X35C_02.08.29.00 Openlock Key AC791/AC790S, NTGX55_10.25.15.02 MR5100 Alternative, NTG9X40C_30.00.12.00 Alternative
0xF0, 0x14, 0x55, 0x0D, 0x5E, 0xDA, 0x92, 0xB3, 0xA7, 0x6C, 0xCE, 0x84, 0x90, 0xBC, 0x7F, 0xED,
# 19 SWI9X06Y_02.14.04.00 Openmep Key WP77xx
0x78, 0x19, 0xC5, 0x6D, 0xC3, 0xD8, 0x25, 0x3E, 0x51, 0x60, 0x8C, 0xA7, 0x32, 0x83, 0x37, 0x9D,
# 20 SWI9X06Y_02.14.04.00 Openlock Key WP77xx
0x12, 0xF0, 0x79, 0x6B, 0x19, 0xC7, 0xF4, 0xEC, 0x50, 0xF3, 0x8C, 0x40, 0x02, 0xC9, 0x43, 0xC8,
# 21 NTGX55 Openmep Key, NTGX55_10.25.15.02 MR5100, NTG9X40C_30.00.12.00
0x49, 0x42, 0xFF, 0x76, 0x8A, 0x95, 0xCF, 0x7B, 0xA3, 0x47, 0x5F, 0xF5, 0x8F, 0xD8, 0x45, 0xE4,
# 22 NTGX55 Openlock Key, NTGX55_10.25.15.02 MR5100, NTG9X40C_30.00.12.00
0xF8, 0x1A, 0x3A, 0xCC, 0xAA, 0x2B, 0xA5, 0xE8, 0x8B, 0x53, 0x5A, 0x55, 0xB9, 0x65, 0x57, 0x98,
# 23 NTG9X15A Openlock Key, NTG9X15A_01.08.02.00
0x54, 0xC9, 0xC7, 0xA4, 0x02, 0x1C, 0xB0, 0x11, 0x05, 0x22, 0x39, 0xB7, 0x84, 0xEF, 0x16, 0xCA,
# 24 NTG9X15A Openlock Key, NTG9X15A_01.08.02.00
0xC7, 0xE6, 0x39, 0xFE, 0x0A, 0xC7, 0xCA, 0x4D, 0x49, 0x8F, 0xD8, 0x55, 0xEB, 0x1A, 0xCD, 0x8A,
# 25 NTGX65 Openlock Key, NTGX65_10.04.13.03
0xF2, 0x4A, 0x9A, 0x2C, 0xDA, 0x3D, 0xA5, 0xE2, 0x6B, 0x56, 0x9A, 0x45, 0x29, 0x25, 0x77, 0x9A,
# 26 NTGX65 Openadm Key, NTGX65_10.04.13.03
0x46, 0x30, 0x33, 0x43, 0x44, 0x36, 0x42, 0x34, 0x41, 0x32, 0x31, 0x32, 0x30, 0x35, 0x39, 0x37
])
class SierraGenerator:
tbl = bytearray()
rtbl = bytearray()
devicegeneration = None
def __init__(self):
for _ in range(0, 0x14):
self.rtbl.append(0x0)
for _ in range(0, 0x100):
self.tbl.append(0x0)
def run(self, devicegeneration, challenge, _type):
challenge = bytearray(unhexlify(challenge))
self.devicegeneration = devicegeneration
if not devicegeneration in prodtable:
print("Sorry, " + devicegeneration + " not supported.")
exit(0)
mepid = prodtable[devicegeneration]["openmep"]
cndid = prodtable[devicegeneration]["opencnd"]
lockid = prodtable[devicegeneration]["openlock"]
clen = prodtable[devicegeneration]["clen"]
if len(challenge) < clen:
challenge = [0 for _ in range(0, clen - len(challenge))]
challengelen = len(challenge)
if _type == 0: # lockkey
idf = lockid
elif _type == 1: # mepkey
idf = mepid
elif _type == 2: # cndkey
idf = cndid
key = keytable[idf * 16:(idf * 16) + 16]
resp = self.SierraKeygen(challenge=challenge, key=key, challengelen=challengelen, keylen=16)[:challengelen]
resp = hexlify(resp).decode('utf-8').upper()
return resp
def selftest(self):
test_table = [
{"challenge": "8101A18AB3C3E66A", "devicegeneration": "MDM9x15", "response": "D1E128FCA8A963ED"},
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9x40", "response": "1033773720F6EE66"},
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9x30", "response": "1E02CE6A98B7DD2A"},
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9x50", "response": "32AB617DB4B1C205"},
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9x06", "response": "28D718CCD669DEDE"},
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9x07", "response": "F5A4C9A0D402E34E"},
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM8200", "response": "EE702212D9C12FAB"},
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9200_V1", "response": "A9A4E76E2653F753"},
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9200_V2", "response": "8B0FAB4B6F81B080"},
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9200_V3", "response": "4A69AD8A69F390E0"},
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9x30_V1", "response": "6A5E4C9CBCBDA7DC"},
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9200", "response": "EEDBF8BFF8DAE346"},
{"challenge": "20E253156762DACE", "devicegeneration": "SDX55", "response": "03940D7067145323"},
{"challenge": "2387885E7D290FEE", "devicegeneration": "MDM9x15A", "response": "DC3E51897BAA9C1E"},
{"challenge": "4B1FEF9FD43C6DAA", "devicegeneration": "SDX65", "response": "1253C1B1E447B697"}
]
for test in test_table:
challenge = test["challenge"]
devicegeneration = test["devicegeneration"]
response = test["response"]
openlock = self.run(devicegeneration, challenge, 0)
padding = " " * (16 - len(devicegeneration))
if openlock != response:
print(devicegeneration + padding + " FAILED!")
else:
print(devicegeneration + padding + " PASSED :)")
def SierraPreInit(self, counter, key, keylen, challengelen, mcount):
if counter != 0:
tmp2 = 0
i = 1
while i < counter:
i = 2 * i + 1
while True:
tmp = mcount
mcount = tmp + 1
challengelen = (key[tmp & 0xFF] + self.tbl[(challengelen & 0xFF)]) & 0xFF
if mcount >= keylen:
mcount = 0
challengelen = ((challengelen & 0xFF) + keylen) & 0xFF
tmp2 = tmp2 + 1
tmp3 = ((challengelen & 0xFF) & i) & 0xFF
if tmp2 >= 0xB:
tmp3 = counter % tmp3
if tmp3 <= counter:
break
counter = tmp3 & 0xFF
return [counter, challengelen, mcount]
def SierraInit(self, key, keylen):
if keylen == 0 or keylen > 0x20:
retval = [0, keylen]
elif 1 <= keylen <= 0x20:
self.tbl = [(i & 0xFF) for i in range(0, 0x100)]
mcount = 0
cl = keylen & 0xffffff00
i = 0xFF
while i > -1:
t, cl, mcount = self.SierraPreInit(i, key, keylen, cl, mcount)
m = self.tbl[i]
self.tbl[i] = self.tbl[(t & 0xff)]
i = i - 1
self.tbl[(t & 0xFF)] = m
self.rtbl[0] = self.tbl[prodtable[self.devicegeneration]["init"][0]] if \
prodtable[self.devicegeneration]["init"][0] != 0 else self.tbl[(cl & 0xFF)]
self.rtbl[1] = self.tbl[prodtable[self.devicegeneration]["init"][1]] if \
prodtable[self.devicegeneration]["init"][1] != 0 else self.tbl[(cl & 0xFF)]
self.rtbl[2] = self.tbl[prodtable[self.devicegeneration]["init"][2]] if \
prodtable[self.devicegeneration]["init"][2] != 0 else self.tbl[(cl & 0xFF)]
self.rtbl[3] = self.tbl[prodtable[self.devicegeneration]["init"][3]] if \
prodtable[self.devicegeneration]["init"][3] != 0 else self.tbl[(cl & 0xFF)]
self.rtbl[4] = self.tbl[prodtable[self.devicegeneration]["init"][4]] if \
prodtable[self.devicegeneration]["init"][4] != 0 else self.tbl[(cl & 0xFF)]
retval = [1, keylen]
return retval
def sierra_calc8F(self, challenge, a=0, b=1, c=2, d=3, e=4, ret=0, ret2=2):
# MDM9200
self.rtbl[b] = (self.rtbl[b] + self.tbl[(self.rtbl[d] & 0xFF)]) & 0xFF
uVar2 = self.rtbl[c] & 0xFF
bVar1 = self.tbl[uVar2]
uVar4 = self.rtbl[b] & 0xFF
self.tbl[uVar2] = self.tbl[uVar4]
self.rtbl[d] = (self.rtbl[d] + 1) & 0xFF
uVar5 = self.rtbl[a] & 0xFF
self.tbl[uVar4] = self.tbl[uVar5]
uVar3 = self.rtbl[d] & 0xFF
self.tbl[uVar5] = self.tbl[uVar3]
self.tbl[uVar3] = bVar1
self.rtbl[ret] = challenge # c
self.rtbl[ret2] = self.tbl[self.tbl[(self.tbl[(self.rtbl[e] + self.tbl[bVar1]) & 0xFF] + (
self.tbl[uVar5] & 0xFF) + (self.tbl[uVar2] & 0xFF) & 0xff) & 0xFF] & 0xFF] ^ self.tbl[
((self.tbl[uVar4] & 0xFF) + (bVar1 & 0xff)) & 0xFF] ^ challenge # a
self.rtbl[e] = (self.rtbl[e] + self.tbl[bVar1]) & 0xFF
return self.rtbl[ret2] & 0xFF # a
def SierraAlgo(self, challenge, a=0, b=1, c=2, d=3, e=4, ret=3, ret2=1, flag=1): # M9x15
v6 = self.rtbl[e]
v0 = (v6 + 1) & 0xFF
self.rtbl[e] = v0
self.rtbl[c] = (self.tbl[v6 + flag & 0xFF] + self.rtbl[c]) & 0xFF
v4 = self.rtbl[c] & 0xFF
v2 = self.rtbl[b] & 0xFF
v1 = self.tbl[(v2 & 0xFF)]
self.tbl[(v2 & 0xFF)] = self.tbl[(v4 & 0xFF)]
v5 = self.rtbl[d] & 0xFF
self.tbl[(v4 & 0xFF)] = self.tbl[(v5 & 0xFF)]
self.tbl[(v5 & 0xFF)] = self.tbl[(v0 & 0xFF)]
self.tbl[v0] = v1 & 0xFF
u = self.tbl[(self.tbl[(
self.tbl[((self.rtbl[a] + self.tbl[(v1 & 0xFF)]) & 0xFF)] + self.tbl[(v5 & 0xFF)] + self.tbl[
(v2 & 0xFF)] & 0xff)] & 0xFF)]
v = self.tbl[((self.tbl[(v4 & 0xFF)] + v1) & 0xFF)]
self.rtbl[ret] = u ^ v ^ challenge
self.rtbl[a] = (self.tbl[(v1 & 0xFF)] + self.rtbl[a]) & 0xFF
self.rtbl[ret2] = challenge & 0xFF
return self.rtbl[ret] & 0xFF
def SierraFinish(self):
self.tbl = [0 for _ in range(0, 0x100)]
self.rtbl[0] = 0
self.rtbl[1] = 0
self.rtbl[2] = 0
self.rtbl[3] = 0
self.rtbl[4] = 0
return 1
def SierraKeygen(self, challenge: bytearray, key: bytearray, challengelen: int, keylen: int):
challenge = challenge
resultbuffer = bytearray([0 for _ in range(0, 0x100 + 1)])
ret, keylen = self.SierraInit(key, keylen)
if ret:
for i in range(0, challengelen):
exec(prodtable[self.devicegeneration]["run"]) # uses challenge
self.SierraFinish()
return resultbuffer
class connection:
def __init__(self, port="", ip="192.168.1.1"):
self.serial = None
self.tn = None
self.connected = False
if port == "":
port = self.detect(port)
if port == "":
self.tn = Telnet(ip, 5510)
if self.tn:
self.connected = True
else:
self.connected = False
if port != "":
self.serial = serial.Serial(port=port, baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=1)
self.connected = self.serial.is_open
def detect(self, port):
if port == "":
for port in serial.tools.list_ports.comports():
if port.vid == 0x1199:
portid = port.location[-1:]
if int(portid) == 3:
print("Detected Sierra Wireless device at: " + port.device)
return port.device
elif port.vid == 0x8046:
portid = port.location[-1:]
if int(portid) == 3:
print("Detected Netgear device at: " + port.device)
return port.device
return ""
def readreply(self):
info = []
if self.serial is not None:
while True:
tmp = self.serial.readline().decode('utf-8').replace('\r', '').replace('\n', '')
if "OK" in info:
return info
elif ("ERROR" in info) or info == "":
return -1
info.append(tmp)
return info
def send(self, cmd):
if self.tn is not None:
self.tn.write(bytes(cmd + "\r", 'utf-8'))
time.sleep(0.05)
data = ""
while True:
tmp = self.tn.read_eager()
if tmp != "":
data += tmp.strip()
else:
break
return data.split("\r\n")
elif self.serial is not None:
self.serial.write(bytes(cmd + "\r", 'utf-8'))
time.sleep(0.05)
return self.readreply()
def close(self):
if self.tn is not None:
self.tn.close()
self.connected = False
if self.serial is not None:
self.serial.close()
self.connected = False
class SierraKeygen(metaclass=LogBase):
def __init__(self, cn, devicegeneration=None):
self.cn = cn
self.keygen = SierraGenerator()
if devicegeneration is None:
self.detectdevicegeneration()
else:
self.devicegeneration = devicegeneration
def run_selftest(self):
print("Running self-test ...")
self.keygen.selftest()
def detectdevicegeneration(self):
if self.cn.connected:
info = self.cn.send("ATI")
if info != -1:
revision = ""
_model = ""
for line in info:
if "Revision" in line:
revision = line.split(":")[1].strip()
if "Model" in line:
_model = line.split(":")[1].strip()
if revision != "":
if "9200" in revision:
devicegeneration = "MDM9200" # AC762S NTG9200H2_03.05.14.12ap
if "9X07" in revision:
devicegeneration = "MDM9x07"
elif "9X25" in revision:
if "NTG9X25C" in revision:
devicegeneration = "MDM9200" # AC781S NTG9X25C_01.00.57.00
elif "9X15" in revision:
if "NTG9X15A" in revision:
devicegeneration = "MDM9x15A" # Aircard 779S
elif "NTG9X15C" in revision:
devicegeneration = "MDM9200" # AC770S NTG9X15C_01.18.02.00
elif "9X15A" in revision:
devicegeneration = "MDM9x15A"
else:
devicegeneration = "MDM9x15"
elif "9X30" in revision:
if "NTG9X35C" in revision: # 790S NTG9X35C_11.11.15.03
devicegeneration = "MDM9x30_V1"
else:
devicegeneration = "MDM9x30"
elif "9X40" in revision and "9X40C" not in revision:
devicegeneration = "MDM9x40"
elif "9X50" in revision:
if "NTG9X50" in revision:
devicegeneration = "MDM9x40" # MR1100,AC797S NTG9X50C_12.06.03.00
else:
devicegeneration = "MDM9x50"
elif "9X06" in revision:
devicegeneration = "MDM9x06"
elif "X55" in revision or "9X40C" in revision:
if "NTGX55" in revision: # MR5100 NTGX55_10.25.15.02, MR5200 NTGX55_12.04.12.00
devicegeneration = "SDX55"
devicegeneration = "SDX55"
elif "X65" in revision:
if "NTGX65" in revision:
version = revision[revision.find("_") + 1:revision.find(" ")].split(".")
maj = int(version[0]) * 1000000 + int(version[1]) * 10000 + int(version[2]) * 100 + int(
version[3])
if maj < 10041303:
devicegeneration = "SDX55"
else: # MR6400 NTGX65_10.04.13.03
devicegeneration = "SDX65"
# MR6550 NTGX65_12.01.31.00
devicegeneration = "SDX65"
else:
devicegeneration = ""
# Missing:
# SDX24 Sierra
# MR2100 NTGX24_10.17.03.00
# SDX55 Sierra
# AC810S NTG9X40C_11.14.08.16
# AC800S NTG9X40C_11.14.07.00
self.devicegeneration = devicegeneration
else:
print("Error on getting ATI modem response. Wrong port? Aborting.")
self.cn.close()
exit(0)
def openlock(self):
print("Device generation detected: " + self.devicegeneration)
# print("Sending AT!ENTERCND=\"A710\" request.")
# info = self.cn.send("AT!ENTERCND=\"A710\"")
# if info == -1:
# print("Uhoh ... invalid entercnd password. Aborting ...")
# return
print("Sending AT!OPENLOCK? request")
info = self.cn.send("AT!OPENLOCK?")
challenge = ""
if info != -1:
if len(info) > 2:
challenge = info[1]
print("Received challenge: " + info[1])
else:
print("Error on AT!OPENLOCK? request. Aborting.")
return False
if challenge == "":
print("Error: Couldn't get challenge. Aborting.")
return False
resp = self.keygen.run(self.devicegeneration, challenge, 0)
print("Sending AT!OPENLOCK=\"" + resp + "\" response.")
info = self.cn.send("AT!OPENLOCK=\"" + resp + "\"")
if info == -1:
print("Damn. AT!OPENLOCK failed.")
else:
print("Success. Device is now engineer unlocked.")
return True
return False
def main(args):
version = "1.5"
info = 'Sierra Wireless Generator ' + version + ' (c) B. Kerler 2019-2021'
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, description=info)
parser.add_argument(
'-openlock', '-l',
help='AT!OPENLOCK? modem response',
default="")
parser.add_argument(
'-openmep', '-m',
help='AT!OPENMEP? modem response',
default="")
parser.add_argument(
'-opencnd', '-c',
help='AT!OPENCND? modem response',
default="")
parser.add_argument(
'-devicegeneration', '-d',
help='device generation',
default="")
parser.add_argument(
'-port', '-p',
help='use com port for auto unlock',
default="")
parser.add_argument(
'-ip',
help='ip port for unlock, usually 192.168.1.1 or 192.168.2.1',
default="192.168.1.1")
parser.add_argument(
'-unlock', '-u',
help='use com port for openlock',
default=False, action='store_true')
parser.add_argument(
'-selftest', '-s',
help='run selftest',
default=False, action='store_true')
args = parser.parse_args()
openlock = args.openlock
openmep = args.openmep
opencnd = args.opencnd
devicegeneration = args.devicegeneration
if not args.selftest:
if (devicegeneration == "" or (openlock == "" and openmep == "" and opencnd == "")) and not args.unlock:
print(info)
print("------------------------------------------------------------\n")
print("Usage: ./sierrakeygen.py [-l,-m,-c] [challenge] -d [devicegeneration]")
print("Example: ./sierrakeygen.py -l BE96CBBEE0829BCA -d MDM9200")
print("or: ./sierrakeygen.py -u for auto unlock")
print("or: ./sierrakeygen.py -u -p [portname] for auto unlock with given portname")
print("or: ./sierrakeygen.py -s for self-test")
print("Supported devicegenerations :")
for key in infotable:
info = f"\t{key}:\t\t"
count = 0
for item in infotable[key]:
count += 1
if count > 15:
info += "\n\t\t\t\t\t"
count = 0
info += item + ","
info = info[:-1]
print(info)
exit(0)
if devicegeneration == "" and not args.unlock:
print("You need to specific a device generation as well. Option -d")
exit(0)
if devicegeneration == "":
devicegeneration = None
if args.selftest:
kg = SierraKeygen(None, "selftest")
kg.run_selftest()
elif args.unlock:
cn = connection(args.port, args.ip)
if cn.connected:
kg = SierraKeygen(cn, devicegeneration)
if kg.devicegeneration == "":
print("Unknown device generation. Please send me details :)")
else:
kg.openlock()
cn.close()
else:
kg = SierraKeygen(None, devicegeneration)
if openlock != "":
resp = kg.keygen.run(devicegeneration, openlock, 0)
print("AT!OPENLOCK=\"" + resp + "\"")
elif openmep != "":
resp = kg.keygen.run(devicegeneration, openmep, 1)
print("AT!OPENMEP=\"" + resp + "\"")
elif opencnd != "":
resp = kg.keygen.run(devicegeneration, opencnd, 2)
print("AT!OPENCND=\"" + resp + "\"")
if __name__ == '__main__':
main(sys.argv)