Skip to content

Instantly share code, notes, and snippets.

@analogic
Created June 21, 2019 11:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save analogic/243c07d5b411101798af9fbdd8ad418a to your computer and use it in GitHub Desktop.
Save analogic/243c07d5b411101798af9fbdd8ad418a to your computer and use it in GitHub Desktop.
"""
Decoder for the Huawei AES256 encryption scheme. Further details are
available at the following URL:
http://blog.emaze.net/2013/12/yet-another-huawei-weak-password.html
Author: Roberto Paleari (@rpaleari)
"""
from Crypto.Cipher import AES
PASSWORD_DELIMITER = "%$%$"
AES_KEY = [0xB8, 0x36, 0x3C, 0x9B, 0x77, 0xDA, 0xED, 0x4B,
0x9A, 0xBB, 0x9F, 0x2F, 0x6D, 0xF5, 0xF1, 0xD5,
0xCB, 0x64, 0x97, 0x5D, 0x5D, 0x3B, 0xCE, 0xE8,
0x82, 0x7F, 0x2F, 0x42, 0x23, 0x5F, 0x92, 0x29]
AES_IV = [0x17, 0x81, 0x6F, 0x96, 0x5B, 0x07, 0x1E, 0xD4,
0xEC, 0x52, 0x84, 0xFF, 0x94, 0xFF, 0x71, 0x76]
AES_MANGLE = [11, 17, 23, 29]
BLOCK_SIZE = 24
def AscUnvisible(s):
r = ""
for c in s:
if c == "~":
c = "?"
c = chr(ord(c) - 0x21)
r += c
return r
def DesEnhSysToLong(d):
assert len(d) >= 4
x = 1
r = 0
for i in range(0, 5):
v0 = ((x << 1) + x) & 0xffffffff
v1 = (v0 << 5) & 0xffffffff
r += ord(d[i]) * x
x = (v1 - v0) & 0xffffffff
return r
def PlainToBin_AES(s):
out = []
for i in range(0, 16, 4):
r = DesEnhSysToLong(s[(i/4)*5:])
out.append(r)
r = ""
for x in out:
r += struct.pack(">I", x)
return r
def GenRandPwdKey_AES(key, salt):
assert len(key) == 32 and len(salt) == 4
r = list(key[:])
for i in range(len(AES_MANGLE)):
r[AES_MANGLE[i]] = ord(salt[i])
return "".join([chr(x) for x in r])
def decrypt_password(s):
assert s.startswith(PASSWORD_DELIMITER) and s.endswith(PASSWORD_DELIMITER), \
"[!] Not a Huawei AES256 password :-("
t = s[len(PASSWORD_DELIMITER):-len(PASSWORD_DELIMITER)]
t = AscUnvisible(t)
plaintext = ""
for block_offset in range(0, len(t), BLOCK_SIZE):
block = t[block_offset:block_offset + BLOCK_SIZE]
# Last 4 chars are the salt
salt = block[20:]
r = GenRandPwdKey_AES(AES_KEY, salt)
block = PlainToBin_AES(block)
iv = "".join([chr(x) for x in AES_IV])
cipher = AES.new(r, AES.MODE_CBC, iv)
msg = cipher.decrypt(block)
plaintext += msg
plaintext = plaintext.rstrip("\x00")
return plaintext
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment