Logic Machine Forum
IP Control of LG TVs - Printable Version

+- Logic Machine Forum (https://forum.logicmachine.net)
+-- Forum: LogicMachine eco-system (https://forum.logicmachine.net/forumdisplay.php?fid=1)
+--- Forum: Scripting (https://forum.logicmachine.net/forumdisplay.php?fid=8)
+--- Thread: IP Control of LG TVs (/showthread.php?tid=2390)



IP Control of LG TVs - jamesng - 16.12.2019

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/hanc8sva8468d18/LG_IP.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


RE: IP Control of LG TVs - admin - 23.12.2019

This is possible to do in LM, can you upload PDF documentation again?


RE: IP Control of LG TVs - AlexLV - 23.12.2019

Hi,

I downloaded file by previous link

Alex


RE: IP Control of LG TVs - jamesng - 24.12.2019

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


RE: IP Control of LG TVs - admin - 24.12.2019

First, you need to encrypt password using PBKDF2. Go to https://8gwifi.org/pbkdf.jsp and input the following data:
Code:
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/showthread.php?tid=2057&pid=12807#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:
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)



RE: IP Control of LG TVs - jamesng - 29.12.2019

Thanks so much for this .. have implemented it this weekend and is working perfectly.


RE: IP Control of LG TVs - cuong.nguyen@vis.solutions - 04.05.2020

Hi, can you check link again??

https://forum.logicmachine.net/showthread.php?tid=2057&pid=12807#pid12807


RE: IP Control of LG TVs - admin - 04.05.2020

The link is correct now


RE: IP Control of LG TVs - cuong.nguyen@vis.solutions - 07.05.2020

Thank you so much.


RE: IP Control of LG TVs - benanderson_475 - 24.12.2020

(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:
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/showthread.php?tid=2057&pid=12807#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:
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’


RE: IP Control of LG TVs - admin - 24.12.2020

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.


RE: IP Control of LG TVs - benanderson_475 - 24.12.2020

(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:
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)



RE: IP Control of LG TVs - admin - 25.12.2020

Try this function:
Code:
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:
reply, err = receive(sock)
log(reply, err)



RE: IP Control of LG TVs - benanderson_475 - 26.12.2020

Many Thanks,

my first attempt only received half the string, now with your function i receive the complete response.
Smile


RE: IP Control of LG TVs - jlodvo - 26.03.2021

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


RE: IP Control of LG TVs - admin - 27.03.2021

Not the right place to ask but on Windows you can run Python, have a look at this library: https://github.com/supersaiyanmode/PyWebOSTV


RE: IP Control of LG TVs - lamgia99 - 17.10.2023

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!


RE: IP Control of LG TVs - admin - 17.10.2023

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/showthread.php?tid=2390&pid=15091#pid15091 and make sure that you input correct pairing code from your TV and use correct hashing parameters (Salt, Iteration, dkLen, PBE Cipher).


RE: IP Control of LG TVs - Igori - 26.04.2024

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/showthread.php?tid=2057&pid=12807#pid12807)

Thanks!