Trying to understand the MicroPython pack() function to convert to Arduino C

Hi, I wonder if someone could help me, please. I'm trying to convert the following MicroPython functions into Arduino code but I'm not sure what the pack() function is doing. I tried to read up on it, but it does not make sense to me!

def encrypt(string):
    key = 123
    result = pack(">I", len(string))
    for i in string:
        a = key ^ ord(i)
        key = a
        result += bytes([a])
    return result

def decrypt(string):
    key = 123
    result = ""
    for i in string:
        a = key ^ i
        key = i
        result += chr(a)
    return result

This should explain what is happening and give some insight into a C function:

https://stackoverflow.com/questions/1550721/python-struct-pack-equivalent-in-c

Maybe one our forum experts know of an Arduino function library to simplify the port.

pack() seems to be roughly equivalent to "sprintf()", so the code looks like it makes an "encrypted" string with the length specified at the beginning. (but that's not very consistent with the defintion of decrypt(), which doesn't seem to know anything about a length.)

The format string ">I" means "Big Endian; uint32_t) so the length of 'string' is converted into a four-byte integer.

Maybe in Python the receiving code strips off the length field (4 bytes) before passing the remaining bytes to decrypt().

void encrypt(String &string, byte *buffer)
{
  uint32_t len = string.length();

  // First 4 bytes are length in BigEndian format
  buffer[0] = (len >> 24) & 0xFF;
  buffer[1] = (len >> 16) & 0xFF;
  buffer[2] = (len >>  8) & 0xFF;
  buffer[3] = len & 0xFF;

  byte key = 123;

  for (size_t i = 0; i < len; i++)
  {
    key = string[i] ^ key;
    buffer[i + 4] = key;
  }
}

String decrypt(byte *buffer)
{
  // First 4 bytes are length in BigEndian format
  uint32_t len = (uint32_t)buffer[0] << 24 | (uint32_t)buffer[1] << 16 | buffer[2] << 8 | buffer[3];

  String string;

  byte key = 123;

  for (size_t i = 0; i < len; i++)
  {
    key = buffer[i+4] ^ key;
    string += key;
  }

  return string;
}

Thank you for the code. I don't understand how to use the Arduino function.

For example, if I want to encrypt the string "hello" what do I need to work out for the second argument *buffer?

String cmd = "Hello";
Serial.println(encrypt(cmd,???));

You can't put arbitrary binary bytes in a String so you need to provide a byte array for the encrypted data. It has to be large enough to hold the characters in the string plus four bytes of length.

Note: I had a mistake in the decrypt function. Fixed below.

void encrypt(String &string, byte *buffer)
{
  uint32_t len = string.length();

  // First 4 bytes are length in BigEndian format
  buffer[0] = (len >> 24) & 0xFF;
  buffer[1] = (len >> 16) & 0xFF;
  buffer[2] = (len >>  8) & 0xFF;
  buffer[3] = len & 0xFF;

  byte key = 123;

  for (size_t i = 0; i < len; i++)
  {
    key = string[i] ^ key;
    buffer[i + 4] = key;
  }
}

String decrypt(byte *buffer)
{
  // First 4 bytes are length in BigEndian format
  uint32_t len = (uint32_t)buffer[0] << 24 
    | (uint32_t)buffer[1] << 16
    | buffer[2] << 8
    | buffer[3];

  String string;

  byte key = 123;

  for (size_t i = 0; i < len; i++)
  {
    string += (char) (buffer[i+4]  ^ key);
    key = buffer[i+4];
  }

  return string;
}

void setup()
{
  Serial.begin(115200);
  delay(200);
  
  String cmd = "Hello";
  Serial.println(cmd);
  
  byte buffer[cmd.length() + 4];
  encrypt(cmd, buffer);
  for (size_t i=0; i< sizeof buffer; i++)
  {
    Serial.print(buffer[i], HEX);
    Serial.print(' ');
  }
  Serial.println();

  Serial.println(decrypt(buffer));
}

void loop() {}

Thank you for clearing that up for me. I appreciate your time and effort. I kind of understood I needed a buffer to hold the data, I just wasn't sure how to work out the size or what type it was.

Thanks for converting this code. I was in the process of working on the same exact code.

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