1

I'm having trouble encrypting bytes from a PyObject using XOR. For now I only managed to print the bytes as an encoded string (with PyUnicode_AsEncodedString):

Here's what I tried (taken from this SO answer)

PyObject* repr = PyObject_Repr(wf.str); // wf.str is a PyObject *
PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~");
const char *bytes = PyBytes_AS_STRING(str);

printf("REPR: %s\n", bytes);

Py_XDECREF(repr);
Py_XDECREF(str);

From here on, I don't know what to do anymore. I also tried to access bytes only using PyBytes_AS_STRING(wf.str) and then proceed with the encryption, but it only returned one byte.

There is a way to XOR encrypt bytes taken from a PyObject? Something like this:

bytes = getBytesFromPyObject(wf.str)
encrypted = XOREncryption(bytes)
AssignBytesToPyObject(encrypted, wf.str)

Note: I don't know much about C, all of this is almost new to me.

Edit: I'm using C instead of Python because I need to implement a function that uses XOR encryption in a built-in module for Python3.

SAL
  • 547
  • 2
  • 8
  • 25
  • Why use C, if you're more familiar with Python? – Dan Getz Jul 20 '22 at 14:46
  • @DanGetz Because I need to implement a function in a built-in module. – SAL Jul 20 '22 at 15:36
  • 1
    "I also tried to access bytes only using PyBytes_AS_STRING(wf.str) and then proceed with the encryption, but it only returned one byte." - Are you sure about this? It looks like it is returning a byte pointer `byte*`. In C, a pointer to an array is a pointer to the location of the first element in the array. If you add an offset equal to the size of the data you are accessing (in this case, 1 byte), then you should be able to access the following element. – h0r53 Jul 20 '22 at 15:46
  • 1
    @h0r53 I was wrong. I was able to access only to the first 8 bytes because I was using the wrong function to retrieve the size. Now I tried using the function `PyBytes_Size` and now I'm able to access to the whole array. Thanks. – SAL Jul 20 '22 at 16:39

2 Answers2

1

"I also tried to access bytes only using PyBytes_AS_STRING(wf.str) and then proceed with the encryption, but it only returned one byte."

Are you sure about this? It looks like it is returning a byte pointer byte*.

In C, a pointer to an array is a pointer to the location of the first element in the array. If you add an offset equal to the size of the data you are accessing (in this case, 1 byte), then you should be able to access the following element.

The issue is likely that you need some method to determine the size of your byte array, then you can operate on the byte* that you've already accessed and iterate through each byte.

h0r53
  • 3,034
  • 2
  • 16
  • 25
0

I know that @h0r53 has already answered my question, but I want to post the code anyway in case it comes useful to someone.

This was implemented in a function (PyMarshal_WriteObjectToString, used for marshal.dump and marshal.dumps) of my custom version of Python, in the marshal.c file

char *bytes = PyBytes_AS_STRING(wf.str);
const char key[32] = {162, 10, 190, 161, 209, 110, 69, 181,
    119, 63, 176, 125, 158, 134, 48, 185,
    200, 22, 41, 43, 212, 144, 131, 169,
    158, 182, 8, 220, 200, 232, 231, 126
};

Py_ssize_t n = PyBytes_Size(wf.str);
for (int i = 0; i < n; i++) {
    bytes[i] = bytes[i] ^ key[i % (sizeof(key) / sizeof(key[0]))];
}

wf.str = PyBytes_FromStringAndSize(bytes, n);
SAL
  • 547
  • 2
  • 8
  • 25