Thanks @akbooer - you’re so right i cant believe i missed that, I’m supposed to decode, not encode ! Doh !!
FYI - Here’s the source.. https://github.com/florianholzapfel/panasonic-viera/issues/9#issuecomment-476919658
How did the rest look ? Here’s my Lua inline with the source.
-- import binascii
-- import base64
-- import hmac, hashlib
-- from Crypto.Cipher import AES
local bit = require("bit")
local mime = require("mime")
local binascii = require("binascii")
-- # Example challenge (which is our IV)
-- iv = base64.b64decode("mUQdS7/RyJTMsiojPz9i1Q==")
local challenge_key = "iL9XqQOMfkFWz2rvh0Xm+w=="
local challenge_Key_unb64 = mime.unb64(challenge_key)
print (challenge_Key_unb64)
-- # Get character codes from IV bytes
-- iv_vals = [ord(c) 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(c) for c in key_vals)
local challenge_Key_unb64 = "ˆ¿W©Œ~AVÏjï‡Eæû"
local challengekey_vals = { challenge_Key_unb64:byte(1, -1) }
local key_vals = {}
for i = 1, 16, 4 do
key_vals[ i ] = bit.band(bit.bnot(challengekey_vals[ i + 3 ]), 0xFF)
key_vals[ i + 1 ] = bit.band(bit.bnot(challengekey_vals[ i + 2 ]), 0xFF)
key_vals[ i + 2 ] = bit.band(bit.bnot(challengekey_vals[ i + 1 ]), 0xFF)
key_vals[ i + 3 ] = bit.band(bit.bnot(challengekey_vals[ i ]), 0xFF)
end
local key = string.char(unpack(key_vals))
print(key) -- "V¨@w¾sü•0©ºx "
-- # Initialise HMAC key mask (taken from libtvconnect.so)
-- hmac_key_mask_vals = [ord(c) 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(c) for c in hmac_vals)
local challenge_Key_unb64 = "ˆ¿W©Œ~AVÏjï‡Eæû"
local challengekey_vals = { challenge_Key_unb64:byte(1, -1) }
local hmac_key_mask = binascii.unhexlify('15C95AC2B08AA7EB4E228F811E34D04FA54BA7DCAC9879FA8ACDA3FC244F3854')
local hmac_key_mask_vals = { hmac_key_mask:byte(1, -1) }
local hmac_vals = {}
for i = 1, 32, 4 do
hmac_vals[i] = bit.bxor(hmac_key_mask_vals[ i ], challengekey_vals[ bit.band(i + 1, 0xF) + 1 ])
hmac_vals[i+1] = bit.bxor(hmac_key_mask_vals[ i + 1 ], challengekey_vals[ bit.band(i + 2, 0xF) + 1 ])
hmac_vals[i+2] = bit.bxor(hmac_key_mask_vals[ i + 2 ], challengekey_vals[ bit.band(i - 1, 0xF) + 1 ])
hmac_vals[i+3] = bit.bxor(hmac_key_mask_vals[ i + 3 ], challengekey_vals[ bit.band(i, 0xF) + 1 ])
end
local hmac_key = string.char(unpack(hmac_vals))
print(hmac_key) --"B`Ò}Îˤg$ÍÙNøÏWòâ/cÒÙzvà"õ3´¿""
-- # 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
local payload = '000000000000' -- First 12 bytes are randomised
local pincode = "<X_PinCode>1234</X_PinCode>" -- Next 4 bytes are from the pincode prompted by the TV
n = #pincode
payload = payload .. string.char(bit.band(bit.rshift(n, 24), 0xFF))
payload = payload .. string.char(bit.band(bit.rshift(n, 16), 0xFF))
payload = payload .. string.char(bit.band(bit.rshift(n, 8), 0xFF))
payload = payload .. string.char(bit.band(n, 0xFF))
payload = payload .. pincode
local iv = payload
print(iv) -- "0000000000001234"
-- # 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)
Still the AES/CBC bit to get working, but hopefully this is progress..