This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

IP Control of LG TVs
#1
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

Here is the link to the full protocol  https://www.dropbox.com/s/hanc8sva8468d1...P.pdf?dl=0

Here's as far as I got with my send command

function sendCommand(command)
  socket = require("socket").tcp() 
  data, err = socket:connect('192.168.1.100', 9761)  

  -- add logic to complete handshake and encrypt command before sending

  data, err = socketConfusedend(command .. '\x0D\x0A')  
  
end


Initially all I'd like to send is the 'POWER off' and 'INPUT_SELECT hdmi1' command as detailed in the dropbox link.

Any help would be greatly appreciated.

Kind Regards
James
Reply
#2
This is possible to do in LM, can you upload PDF documentation again?
Reply
#3
Hi,

I downloaded file by previous link

Alex

Attached Files
.pdf   LG_IP.pdf (Size: 1.22 MB / Downloads: 189)
Reply
#4
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

Cheers
James
Reply
#5
First, you need to encrypt password using PBKDF2. Go to https://8gwifi.org/pbkdf.jsp and input the following data:
Code:
12345
Master Password: your pairing code (BK2AT22Y) Salt: Y2G4DpvcpmONByDyzFaPuQ== Iteration: 16384 dkLen: 128 PBE Ciphers: PBKDF2WithHmacSHA256

Use aes.lua from this post: https://forum.logicmachine.net/showthrea...7#pid12807
Save it as a user library named aes

Example, change key to the one that you've generated. Change ip and cmd as needed. \r is added to command automatically.
Code:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
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)
Reply
#6
Thanks so much for this .. have implemented it this weekend and is working perfectly.
Reply
#7
Hi, can you check link again??

https://forum.logicmachine.net/showthrea...7#pid12807
Reply
#8
The link is correct now
Reply
#9
Thank you so much.
Reply
#10
(24.12.2019, 06:48)admin Wrote: First, you need to encrypt password using PBKDF2. Go to https://8gwifi.org/pbkdf.jsp and input the following data:
Code:
12345
Master Password: your pairing code (BK2AT22Y) Salt: Y2G4DpvcpmONByDyzFaPuQ== Iteration: 16384 dkLen: 128 PBE Ciphers: PBKDF2WithHmacSHA256

Use aes.lua from this post: https://forum.logicmachine.net/showthrea...7#pid12807
Save it as a user library named aes

Example, change key to the one that you've generated. Change ip and cmd as needed. \r is added to command automatically.
Code:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
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:
12
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’
Reply
#11
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.
Reply
#12
(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

i have it with the below

Code:
12345678910111213
reply = sock:receive(32)             res_iv = string.sub(reply, 0, 16)       enc_res = string.sub(reply, 17, 32)           -- decript iv       local aes_128_ecb, err = aes:new(key, nil, aes.cipher(128, 'ecb'), { iv = string.rep('\0', 16) }, nil, 0)       local ivdec = aes_128_ecb:decrypt(res_iv)             -- decrypt encryped reply       local aes_128_cbcc, err = aes:new(key, nil, aes.cipher(128, 'cbc'), { iv = ivdec}, nil, 0)       local datadec = aes_128_cbcc:decrypt(enc_res)       loghex(datadec)
Reply
#13
Try this function:
Code:
12345678910111213141516171819202122232425262728293031
function receive(sock)   local iv = sock:receive(16)   if not iv then     return nil, 'cannot receive iv'   end   local aes_128_ecb, err = aes:new(key, nil, aes.cipher(128, 'ecb'), { iv = string.rep('\0', 16) }, nil, 0)   local ivdec = aes_128_ecb:decrypt(iv)   local aes_128_cbc, err = aes:new(key, nil, aes.cipher(128, 'cbc'), { iv = ivdec }, nil, 0)   local buf = ''   sock:settimeout(0.1)   while true do     local data, err = sock:receive(16)     if data then       buf = buf .. data     else       break     end   end   sock:settimeout(3)   if #buf > 0 then     return aes_128_cbc:decrypt(buf)   else     return nil, 'receive failed'   end end

Use this like this:
Code:
12
reply, err = receive(sock) log(reply, err)
Reply
#14
Many Thanks,

my first attempt only received half the string, now with your function i receive the complete response.
Smile
Reply
#15
hello wanted to ask if this can be done using windows 10 and maybe a powershell script? i wanted to make a powershell to change to hdmi 1 or hdmi 2
Reply
#16
Not the right place to ask but on Windows you can run Python, have a look at this library: https://github.com/supersaiyanmode/PyWebOSTV
Reply
#17
When I run this program, I receive the following log: * arg: 1
  * number: 32
* arg: 2
  * nil
and i can't control my tv .
can you help me!

(04.05.2020, 05:19)admin Wrote: The link is correct now

When I run this program, I receive the following log: * arg: 1
  * number: 32
* arg: 2
  * nil
and i can't control my tv .
can you help me!
Reply
#18
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).
Reply
#19
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'

(updated aes library, post #7, https://forum.logicmachine.net/showthrea...7#pid12807)

Thanks!
Reply
#20
Try the attached library.

Attached Files
.lua   aes.lua (Size: 9.36 KB / Downloads: 16)
Reply


Forum Jump: