mirror of
https://github.com/Lekensteyn/lglaf.git
synced 2025-04-03 16:50:03 -04:00
Add KILO challenge/response
Credits: @joeblowma => Initial reverse engineering @snoremaster3000 => Porting the C code to python @steadfasterX => Pushing the code along to this repo
This commit is contained in:
parent
87ec43709a
commit
dd2fc9d54c
2 changed files with 68 additions and 1 deletions
33
laf_crypto.py
Normal file
33
laf_crypto.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
from Crypto.Cipher import AES
|
||||
from lglaf import int_as_byte
|
||||
|
||||
|
||||
def key_transform(old_key):
|
||||
new_key = b''
|
||||
for x in range(32, 0, -1):
|
||||
new_key += int_as_byte(old_key[x-1] - (x % 0x0C))
|
||||
return new_key
|
||||
|
||||
|
||||
def xor_key(key, kilo_challenge):
|
||||
# Reserve key
|
||||
key_xor = b''
|
||||
pos = 0
|
||||
for i in range(8):
|
||||
key_xor += int_as_byte(key[pos] ^ kilo_challenge[3])
|
||||
key_xor += int_as_byte(key[pos + 1] ^ kilo_challenge[2])
|
||||
key_xor += int_as_byte(key[pos + 2] ^ kilo_challenge[1])
|
||||
key_xor += int_as_byte(key[pos + 3] ^ kilo_challenge[0])
|
||||
pos += 4
|
||||
return key_xor
|
||||
|
||||
|
||||
def encrypt_kilo_challenge(encryption_key, kilo_challenge):
|
||||
plaintext = b''
|
||||
for k in range(0, 16):
|
||||
# Assemble 0x00 0x01 0x02 ... 0x1F byte-array
|
||||
plaintext += int_as_byte(k)
|
||||
encryption_key = key_transform(encryption_key)
|
||||
xored_key = xor_key(encryption_key, kilo_challenge)
|
||||
obj = AES.new(xored_key, AES.MODE_ECB)
|
||||
return obj.encrypt(plaintext)
|
36
lglaf.py
36
lglaf.py
|
@ -7,7 +7,7 @@
|
|||
|
||||
from __future__ import print_function
|
||||
from contextlib import closing
|
||||
import argparse, logging, re, struct, sys
|
||||
import argparse, logging, re, struct, sys, binascii
|
||||
|
||||
# Enhanced prompt with history
|
||||
try: import readline
|
||||
|
@ -29,6 +29,15 @@ except: pass
|
|||
if '\0' == b'\0': int_as_byte = chr
|
||||
else: int_as_byte = lambda x: bytes([x])
|
||||
|
||||
# laf crypto for KILO challenge/response
|
||||
try:
|
||||
import laf_crypto
|
||||
except ImportError:
|
||||
_logger.warning("LAF Crypto failed to import!")
|
||||
pass
|
||||
|
||||
# Use Manufacturer key for KILO challenge/response
|
||||
USE_MFG_KEY = False
|
||||
|
||||
laf_error_codes = {
|
||||
0x80000000: "FAILED",
|
||||
|
@ -329,6 +338,24 @@ class USBCommunication(Communication):
|
|||
def close(self):
|
||||
usb.util.dispose_resources(self.usbdev)
|
||||
|
||||
def challenge_response(comm, mode):
|
||||
request_kilo = make_request(b'KILO', args=[b'CENT', b'\0\0\0\0', b'\0\0\0\0', b'\0\0\0\0'])
|
||||
kilo_header, kilo_response = comm.call(request_kilo)
|
||||
kilo_challenge = kilo_header[8:12]
|
||||
_logger.debug("Challenge: %s" % binascii.hexlify(kilo_challenge))
|
||||
if USE_MFG_KEY:
|
||||
key = b'lgowvqnltpvtgogwswqn~n~mtjjjqxro'
|
||||
else:
|
||||
key = b'qndiakxxuiemdklseqid~a~niq,zjuxl'
|
||||
kilo_response = laf_crypto.encrypt_kilo_challenge(key, kilo_challenge)
|
||||
_logger.debug("Response: %s" % binascii.hexlify(kilo_response))
|
||||
mode_bytes = struct.pack('<I', mode)
|
||||
kilo_metr_request = make_request(b'KILO', args=[b'METR', b'\0\0\0\0', mode_bytes, b'\0\0\0\0'],
|
||||
body=bytes(kilo_response))
|
||||
metr_header, metr_response = comm.call(kilo_metr_request)
|
||||
_logger.debug("KILO METR Response -> Header: %s, Body: %s" % (
|
||||
binascii.hexlify(metr_header), binascii.hexlify(metr_response)))
|
||||
|
||||
def try_hello(comm):
|
||||
"""
|
||||
Tests whether the device speaks the expected protocol. If desynchronization
|
||||
|
@ -426,6 +453,8 @@ def command_to_payload(command, rawshell):
|
|||
parser = argparse.ArgumentParser(description='LG LAF Download Mode utility')
|
||||
parser.add_argument("--skip-hello", action="store_true",
|
||||
help="Immediately send commands, skip HELO message")
|
||||
parser.add_argument("--cr", action="store_true",
|
||||
help="Do initial challenge response (KILO CENT/METR)")
|
||||
parser.add_argument('--rawshell', action="store_true",
|
||||
help="Execute shell commands as-is, needed on recent devices. "
|
||||
"CAUTION: stderr output is not redirected!")
|
||||
|
@ -449,6 +478,11 @@ def main():
|
|||
comm = autodetect_device()
|
||||
|
||||
with closing(comm):
|
||||
if args.cr:
|
||||
# Mode 2 seems standard, will maybe
|
||||
# change in other protocol versions
|
||||
_logger.debug("Doing KILO challenge response")
|
||||
challenge_response(comm, mode=2)
|
||||
if not args.skip_hello:
|
||||
try_hello(comm)
|
||||
_logger.debug("Hello done, proceeding with commands")
|
||||
|
|
Loading…
Add table
Reference in a new issue