18.01.2020, 01:07
(10.03.2016, 14:32)admin Wrote: Try these functions, they are untested so might not work at all. You have to parse any XML response manuallyNow in my region as of 2019 Panasonic have implemented Auth before i can send commands,
Code:function request(host, url, urn, action, args)
local body, http, ltn12, sink, res, err
ltn12 = require('ltn12')
http = require('socket.http')
body = [[<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body><u:]] .. action .. [[ xmlns:u="urn:]] .. urn .. [[">]] .. args .. [[</u:]] .. action .. [[></s:Body>
</s:Envelope>]]
sink = {}
res, err = http.request({
url = 'http://' .. host .. ':55000/' .. url,
method = 'POST',
headers = {
['soapaction'] = '"urn:' .. urn .. '#' .. action .. '"',
['Content-Length'] = #body,
},
sink = ltn12.sink.table(sink),
source = ltn12.source.string(body),
})
if res then
return table.concat(sink)
else
return nil, err
end
end
function sendkey(host, code)
local args = '<X_KeyEvent>' .. code .. '</X_KeyEvent>'
return request(host, 'nrc/control_0', 'panasonic-com:service:p00NetworkControl:1', 'X_SendKey', args)
end
function getmute(host)
return request(host, 'dmr/control_0', 'schemas-upnp-org:service:RenderingControl:1', 'GetMute', '<InstanceID>0</InstanceID><Channel>Master</Channel>')
end
IP = '192.168.1.2'
log(getmute(IP))
i found this (https://github.com/florianholzapfel/pana...a/issues/9) explaining how it is achieved, but it is python, im not sure where to start to work out how to port it to lua,
I have soap command working to return the iv key my goal is to return the encrypted_payload to send to the tv to make connection.
import binascii
import base64
import hmac, hashlib
from Crypto.Cipher import AES
# Example challenge (which is our IV)
iv = base64.b64decode("mUQdS7/RyJTMsiojPz9i1Q==")
# Get character codes from IV bytes
iv_vals = [ord© for c in iv]
# Initialise key character codes array
key_vals = [0] * 16
# Derive key from IV
i = 0
while i < 16:
key_vals[i] = ~iv_vals[i + 3] & 0xFF
key_vals[i + 1] = ~iv_vals[i + 2] & 0xFF
key_vals[i + 2] = ~iv_vals[i + 1] & 0xFF
key_vals[i + 3] = ~iv_vals[i] & 0xFF
i += 4
# Convert our key character codes to bytes
key = ''.join(chr© for c in key_vals)
# Initialise HMAC key mask (taken from libtvconnect.so)
hmac_key_mask_vals = [ord© for c in binascii.unhexlify("15C95AC2B08AA7EB4E228F811E34D04FA54BA7DCAC9879FA8ACDA3FC244F3854")]
# Initialise HMAC key character codes array
hmac_vals = [0] * 32
# Calculate HMAC key using HMAC key mask and IV
i = 0
while i < 32:
hmac_vals[i] = hmac_key_mask_vals[i] ^ iv_vals[(i + 2) & 0xF]
hmac_vals[i + 1] = hmac_key_mask_vals[i + 1] ^ iv_vals[(i + 3) & 0xF]
hmac_vals[i + 2] = hmac_key_mask_vals[i + 2] ^ iv_vals[i & 0xF]
hmac_vals[i + 3] = hmac_key_mask_vals[i + 3] ^ iv_vals[(i + 1) & 0xF]
i += 4
# Convert our HMAC key character codes to bytes
hmac_key = ''.join(chr© for c in hmac_vals)
# This is our plaintext SOAP argument for the pin code shown on the TV
authinfo = "<X_PinCode>4410</X_PinCode>"
# First 12 bytes are randomised, let's just set them to 0 because it doesn't matter
payload = "000000000000"
# The next 4 bytes contain the plaintext (SOAP arg) length in big endian
n = len(authinfo)
payload += chr(n >> 24)
payload += chr((n >> 16) & 0xFF)
payload += chr((n >> 8) & 0xFF)
payload += chr(n & 0xFF)
# Now we concatenate our payload, which is starting at byte 17 of the payload
payload += authinfo
# Let's encrypt it with AES-CBC! We need to make sure we pad it to a multiple of 16 bytes beforehand
aes = AES.new(key, AES.MODE_CBC, iv)
ciphertext = aes.encrypt(pad(payload))
# Calculate the HMAC-SHA-256 signature of our encrypted payload
sig = hmac.new(hmac_key, ciphertext, hashlib.sha256).digest()
# Concatenate the HMAC signature to the encrypted payload and base64 encode it, and we're done!
encrypted_payload = base64.b64encode(ciphertext + sig)