16.12.2019, 15:05 (This post was last modified: 24.12.2019, 01:25 by jamesng.)
Hi
I'm trying to implement some basic control of an LG television. I have the protocol document from LG however haven't figured out how to script the generation of the encryption key or send the encrypted commands to the TV.
Is this possible with lua?
Turing on the device is pretty straightforward by sending a WOL packet to the MAC address of the TV, however before it will process any commands (like setting inputs, changing the volume or switching off) one must complete the handshake with the tv.
One can view the TV's pairing key code from the TV itself - it is an 8 digit key ie: BK2AT22Y
Handshake notes from LG
Client encrypts the password with PBKDF2 (Password-Based Key Derivation Function 2) method. First 16 Bytes of encrypted password are AES128 key. Following parameters must be used:
Algorithm: sha256
Salt: 0x63,0x61,0xb8,0x0e, 0x9b,0xdc,0xa6,0x63,0x8d,0x07,0x20, 0xf2,0xcc,0x56,0x8f,0xb9 Number of Iteration: 2**14
Thanks for looking into this. The link should be working again now. Any help you could provide with the handshake and encryption would be greatly appreciated
Example, change key to the one that you've generated. Change ip and cmd as needed. \r is added to command automatically.
Code:
ip = '192.168.1.100'
key = 'm7mRFt3BM+CwW3bYunE6sA=='
cmd = 'POWER off'
function encrypt(key, data)
-- padding
local rem = #data % 16
if rem ~= 0 then
rem = 16 - rem
local ch = string.char(rem)
data = data .. string.rep(ch, rem)
end
-- generate iv
local iv = ''
local ts, tu = os.microtime()
math.randomseed(ts - tu)
for i = 1, 16 do
local ch = math.random(0, 255)
iv = iv .. string.char(ch)
end
local aes = require('user.aes')
-- encrypt iv
local aes_128_ecb, err = aes:new(key, nil, aes.cipher(128, 'ecb'), { iv = string.rep('\0', 16) }, nil, 0)
local ivenc = aes_128_ecb:encrypt(iv)
-- encypt data
local aes_128_cbc, err = aes:new(key, nil, aes.cipher(128, 'cbc'), { iv = iv }, nil, 0)
local dataenc = aes_128_cbc:encrypt(data)
return ivenc .. dataenc
end
function send(ip, key, cmd)
local sock = require('socket').tcp()
sock:settimeout(3)
local res, err = sock:connect(ip, 9761)
if res then
key = require('encdec').base64dec(key)
cmd = cmd .. '\r'
local data = encrypt(key, cmd)
res, err = sock:send(data)
if res then
reply = sock:receive(16)
end
end
Example, change key to the one that you've generated. Change ip and cmd as needed. \r is added to command automatically.
Code:
ip = '192.168.1.100'
key = 'm7mRFt3BM+CwW3bYunE6sA=='
cmd = 'POWER off'
function encrypt(key, data)
-- padding
local rem = #data % 16
if rem ~= 0 then
rem = 16 - rem
local ch = string.char(rem)
data = data .. string.rep(ch, rem)
end
-- generate iv
local iv = ''
local ts, tu = os.microtime()
math.randomseed(ts - tu)
for i = 1, 16 do
local ch = math.random(0, 255)
iv = iv .. string.char(ch)
end
local aes = require('user.aes')
-- encrypt iv
local aes_128_ecb, err = aes:new(key, nil, aes.cipher(128, 'ecb'), { iv = string.rep('\0', 16) }, nil, 0)
local ivenc = aes_128_ecb:encrypt(iv)
-- encypt data
local aes_128_cbc, err = aes:new(key, nil, aes.cipher(128, 'cbc'), { iv = iv }, nil, 0)
local dataenc = aes_128_cbc:encrypt(data)
return ivenc .. dataenc
end
function send(ip, key, cmd)
local sock = require('socket').tcp()
sock:settimeout(3)
local res, err = sock:connect(ip, 9761)
if res then
key = require('encdec').base64dec(key)
cmd = cmd .. '\r'
local data = encrypt(key, cmd)
res, err = sock:send(data)
if res then
reply = sock:receive(16)
end
end
sock:close()
return res, err
end
res, err = send(ip, key, cmd)
log(res, err)
Hi
i have the above all working, Many Thanks, how can i decrypt the response from the command sent, i added log (reply) and this is the result string %9����i���%r4
do i need to use
Code:
local aes_128_cbcc, err = aes:new(key, nil, aes.cipher(128, 'cbc'), { iv = iv }, nil, 0)
local datadec = aes_128_cbcc:decrypt(reply)
where do i get the iv from, the doc say to use received iv as below?
5)
Receiver applies decryption with received IV, and encrypted message. For “VOLUME_MUTE on” command, the response from the server is: ce 53 7c e4 b8 82 98 c6 a4 3e 21 89 af 5f 20 2f and after decryption: 4f 4b 0a 00 7d 7d 7d 7d 7d 7d 7d 7d 7d 7d 7d 7d. O K ‘\n’ } } } } } } } } } } } } For now, just ignore characters after ‘\n’
You can use loghex(data) to display binary data as hex. The receiving part of this example is incomplete. First 16 bytes of the reply contain the encrypted IV then one or more 16 byte blocks should follow. Receiving should stop if a decrypted block contains \n character.
24.12.2020, 09:20 (This post was last modified: 24.12.2020, 19:28 by benanderson_475.)
(24.12.2020, 08:58)admin Wrote: You can use loghex(data) to display binary data as hex. The receiving part of this example is incomplete. First 16 bytes of the reply contain the encrypted IV then one or more 16 byte blocks should follow. Receiving should stop if a decrypted block contains \n character.
ok i understand now, so if i read 32 bytes then split into 2 local var then use the iv in the first 16 bytes with the aes ecb, i will get the decrypted response then i need to split the string at \n to receive the full response
This is not guaranteed to work on all TV models, there might be some changes to the protocol depending on the model year. Check that your script has correct key variable set. Follow this guide: https://forum.logicmachine.net/showthrea...1#pid15091 and make sure that you input correct pairing code from your TV and use correct hashing parameters (Salt, Iteration, dkLen, PBE Cipher).
26.04.2024, 14:54 (This post was last modified: 26.04.2024, 19:12 by Igori.)
Hello!
I'm trying to control the TV, I'm running the script, but I see an error in the error log. What could be the problem?
User library aes:184: Symbol not found: EVP_CIPHER_CTX_block_size
stack traceback:
[C]: in function '__index'
User library aes:184: in function 'new'
User script:27: in function 'encrypt'
User script:45: in function 'send'