1

I'm trying to encrypt/decrypt a file using XOR. I have the following encryption/decryption routine where every byte is xor'd and the result is being subtracted by the value of the byte that is located at the previous location. The ASM representation is as follows

crypt:
mov dl, [eax+ecx]   ; read byte
xor dl, 0C5h        ; xor it with oxC5
sub dl, [eax+ecx-1] ; sub the previous byte
mov [eax+ecx], dl   ; save the new byte
dec eax             ; decrement pointer
test   eax, eax
jg   short crypt     ;

That is what my encryption routine should look like, I'm trying to port this this C/C++. My code is as follows

#include <stdio.h>

unsigned int xorkey = 0xC5;

int main(int argc, char *argv[])
{
if(argc < 3)
{
    printf("usage: encoder input output\n");
    return -1;
}

FILE *in = fopen(argv[1], "rb");
if(in == NULL)
{
    printf("failed to open: %s", argv[2]);
    return -1;
}

FILE *out = fopen(argv[2], "wb");

if(out == NULL)
{
    fclose(in);
    printf("failed to open '%s' for writing.",argv[2]);
    return -1;
}

int count;
char buffer[1024];

while(count = fread(buffer, 1, 1024, in))
{
    int i;
    int end = count;

    for(i = 0;i < end; ++i)
    {
            ((unsigned int *)buffer)[i] ^= xorkey;
    }
    if(fwrite(buffer, 1, count, out) != count)
    {
            fclose(in);
            fclose(out);

            printf("fwrite() error\n");

            return -1;
    }
}

fclose(in);
fclose(out);

return 0;
}

I cannot figure out how to do the subtracting of bytes in C++. The XOR routine itself looks correct though, no? Please note that I'm also trying to encrypt the file starting from the end of the file till the beginning. Any ideas?

Thanks!

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • 3
    Kinda hard to read "encrypt" and "XOR" in the same sentence without a negative between... obfuscate? Sure. Yes. Totally. Encrypt? Not so much. – bbum Feb 16 '11 at 06:51
  • What you have with XOR is obfuscation, not encryption. – Keith Feb 16 '11 at 06:51
  • I know it's not safe for real world applications, this is simply for a personal project. – Brian Blankenship Feb 16 '11 at 06:55
  • Well I know my C/C++ code is incorrect but I'm trying to implement the algorithm exactly as in the ASM code. Working the buffer from bottom to top and skipping the first byte. How would I go about doing this? – Brian Blankenship Feb 16 '11 at 07:15
  • 4
    There's no such language as C/C++. It's either C *or* C++. Pick one. (And I hope you pick C, for this code.) – GManNickG Feb 16 '11 at 09:36
  • 1
    @Keith You have obviously never taken a cryptography class or even bothered to read the definition of the word *encryption* for that matter. The [XOR cipher is __absolutely__ an encryption method](http://en.wikipedia.org/wiki/XOR_cipher). – arkon Mar 26 '13 at 08:18
  • @b1naryatr0phy XOR can be trivially broken so I don't consider it a *real* encryption, though technically it is. – Keith Mar 26 '13 at 08:31
  • 1
    @Keith Virtually any problem can be trivial if there's an intelligent enough mind solving it. Encryption is encryption, it isn't a loosely defined term. – arkon Mar 26 '13 at 08:49
  • @b1naryatr0phy You can use your XOR, I'll use AES. Since it's not loosely defined, it shouldn't make any difference. Right? – Keith Mar 26 '13 at 13:18
  • 1
    @Keith Tell you what, I'll throw together an XOR algorithm in 5 minutes that you yourself couldn't solve if I gave you 5 years :) It all comes down to context. – arkon Mar 26 '13 at 14:52

3 Answers3

2

Here's how you could write that assembly language function in C. I've kept the variable names the same as the register names so you can see how the various parts match up.

void do_xor_crypt(char *buffer, int count) {
    char *ecx = buffer;
    int eax = count - 1;
    if (eax > 0) {
        do {
            char dl = ecx[eax];
            dl ^= 0xC5;
            dl -= ecx[eax-1];
            ecx[eax] = dl;
            eax--;
        } while (eax > 0);
    }
}

Note that I have checked to make sure eax is greater than zero (meaning count is two or more) so that the loop has something to subtract. You could integrate this code into your reading loop like:

while (count = fread(buffer, 1, 1024, in))
{
    do_xor_crypt(buffer, count);
    if (fwrite(buffer, 1, count, out) != count)
    {
        // ...
    }
}
Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
1

There are a couple things wrong with your C code.

The asm code starts at the end of the buffer and works its way down and stops when eax == 0. The asm code operates on a byte at a time, xor'ing and subtracting from the previous byte.

The asm code would seem to leave the first byte of the buffer untouched.

Your C code moves an index and xors the four bytes pointed by that byte index with 0xC5. That code is reading three bytes too many and only affecting the lowest byte with the XOR.

Plus your for-loop starts at the front and works its way to the end - the opposite of your asm routine.

Assuming chars are byte-sized, then to mimic the asm routine, your subtraction step would be:

buffer[i] = buffer[i] - buffer[i-1];

which can be rewritten as:

buffer[i] -= buffer[i-1];

...assuming you fix your for-loop to go from the end-1 of the array to index 1.

typo.pl
  • 8,812
  • 2
  • 28
  • 29
  • +1: solid analysis, but someone asking the question would probably still have trouble understanding the fixes required from your explanation. Boils down to reading the last part of the file first (or all of it into memory at once), then increment downwards xoring with `((unsigned char *)buffer)[i]`, subtracting the previous byte. – Tony Delroy Feb 16 '11 at 07:09
  • Well I know my C/C++ code is incorrect but I'm trying to implement the algorithm exactly as in the ASM code. Working the buffer from bottom to top and skipping the first byte. How would I go about doing this? – Brian Blankenship Feb 16 '11 at 07:16
0

You need to change buffer to type unsigned char, and change your for loop to:

for (i = count - 1; i > 0; i--)
{
    buffer[i] ^= xorkey;
    buffer[i] -= buffer[i - 1];
}

Note though that this code works on the file in 1024-byte chunks from the start, and then works on each chunk in reverse. If you want to work on the whole file in reverse, you'll need to start reading from the end of it, and have special handling for the first character in each chunk.

caf
  • 233,326
  • 40
  • 323
  • 462