TP-Link / Kaza cipher

I am working on a project to write to and read from a TP Link / Kaza power strip or smart plug.

The data that is sent is encrypted json that has been "autokey encrypted".

So far I have been able to convert a typescript encrypt function and it works well. I get the expected result. However, I need to add a "header" to my encrypted data. That data is 3 null bytes followed by a byte that is a measure of the length of the encrypted bytes.

The same typescript has this bit to encrypt with headers, however, I've hit a bit of a wall trying to convert it to something usable. Can someone nudge me along the path ?

First are the two typescript functions: (borrowed from tplink-smarthome-crypto/index.ts at main · plasticrake/tplink-smarthome-crypto · GitHub)

/**
 * Encrypts input where each byte is XOR'd with the previous encrypted byte.
 *
 * @param input - Data to encrypt
 * @param firstKey - Value to XOR first byte of input
 * @returns encrypted buffer
 */
export function encrypt(input: Buffer | string, firstKey = 0xab): Buffer {
  const buf = Buffer.from(input);
  let key = firstKey;
  for (let i = 0; i < buf.length; i += 1) {
    // eslint-disable-next-line no-bitwise
    buf[i] ^= key;
    key = buf[i];
  }
  return buf;
}
/**
 * Encrypts input that has a 4 byte big-endian length header;
 * each byte is XOR'd with the previous encrypted byte.
 *
 * @param input - Data to encrypt
 * @param firstKey - Value to XOR first byte of input
 * @returns encrypted buffer with header
 */
export function encryptWithHeader(
  input: Buffer | string,
  firstKey = 0xab
): Buffer {
  const msgBuf = encrypt(input, firstKey);
  const outBuf = Buffer.alloc(msgBuf.length + 4);
  outBuf.writeUInt32BE(msgBuf.length, 0);
  msgBuf.copy(outBuf, 4);
  return outBuf;
}

Second is what I have so far. This part works well and produces the expected results

// This part works well and produces the expected results
String encrypt(String input)
{
    int16_t firstKey = 0xab;
    String buf;
    int key;
    int i;
    buf = input;
    key = firstKey;
    i = 0;
    for (;i < buf.length();(i = i + 1))
    {
        buf[i] ^= key;
        key = buf[i];
    }
    return buf;
}

// This does not function yet, as I'm pretty lost..
// This was orginally converted from typescript with https://andrei-markeev.github.io/ts2c/
// I started work on converting this, but ran into errors I don't know how to solve. 

String encryptWithHeader(String input){
    String msgBuf;
    String outBuf;
    int16_t firstKey = 0xab;
    char * null = NULL;
    msgBuf = encrypt(input);
    outBuf = msgBuf.length() +1;
  
//this is where I got lost...  
    assert(null != NULL);
    null[0] = '\0';
    strncat(null, outBuf, msgBuf.length());
    str_int16_t_cat(null, 4);
    outBuf = msgBuf + 4
    return outBuf;

}

Finally, the data:

//this is the unencrypted json
String offMsg = "{\"system\":{\"set_relay_state\":{\"state\":0}}}";

//current encrypt function produces:
d0f281f88bff9af7d5ef94b6c5a0d48bf99cf091e8b7c4b0d1a5c0e2d8a381f286e793f6d4eedea3dea3

//the working "withheaders" would produce:

00002ad0f281f88bff9af7d5ef94b6c5a0d48bf99cf091e8b7c4b0d1a5c0e2d8a381f286e793f6d4eedea3dea3 

Admittedly my C/C++ ability is very limited and I can spell typescript, that's about all. I have a very extensive history with PHP. As useful as that is. So, I understand the basics of data structures and whatnot, but I'm venturing off into areas I've never been in. Any help would be greatly appreciated.

I think you will have trouble with storing binary bytes into a String. I recommend you use byte arrays. If the data length is limited to 255 you can fit any message plus header into a 259-byte array.

my understanding of byte arrays and whatnot is quite limited. can you show me an example that might help me get this code where needs to be?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.