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..