user2629659 user2629659 - 2 months ago 8
C Question

Cryptography: converting C function to python

I am trying to solve a cryptography problem (https://callicode.fr/pydefis/Reverse/txt), the alghorithm make use of the following C function (F1).
I don't know C, I tried to convert it to python(F2) without success. Thank you in advance for letting me know what I did wrong.

F1:

void Encrypt(unsigned char key[20], unsigned char *pPlainBuffer, unsigned char *pCipherBuffer, unsigned int nLength)
{
int nKeyPos = 0;
unsigned int n;
unsigned char KeyA = 0;

if ((pPlainBuffer != NULL) && (pCipherBuffer != NULL)) {
for (n = 0; n < 20; n++)
KeyA ^= key[n];
nKeyPos = KeyA % 20;
for (n = 0; n < nLength; n++) {
pCipherBuffer[n] = pPlainBuffer[n]^(key[nKeyPos]*KeyA);
KeyA += pCipherBuffer[n];
nKeyPos = pCipherBuffer[n] % 20;
}
}
}


F2:

def Encrypt(plainText, key): # plainText is a list of hexadecimals representing ascii
# characters, key is a list of int size 20 each int
# beetween 0 and 255
keyA = 0

for n in range(20):
keyA ^= key[n]

nKeyPos = KeyA % 20

for n in range(len(plainText)):
codedText[n] = plainText[n]^(key[nKeyPos]*KeyA)
keyA += codedText[n]
nKeyPos = codedText[n] % 20

BPL BPL
Answer

Here's a little working example:

def Encrypt(key, pPlainBuffer):
    nKeyPos = 0
    KeyA = 0

    if pPlainBuffer is not None:
        pCipherBuffer = []
        for n in range(20):
            KeyA = KeyA ^ key[n]
        nKeyPos = KeyA % 20

        for n in range(len(pPlainBuffer)):
            pCipherBuffer.append(pPlainBuffer[n] ^ (key[nKeyPos] * KeyA))
            KeyA += pCipherBuffer[n]
            nKeyPos = pCipherBuffer[n] % 20

        return pCipherBuffer


def Decrypt(key, pCipherBuffer):
    nKeyPos = 0
    KeyA = 0

    if pCipherBuffer is not None:
        pPlainBuffer = []
        for n in range(20):
            KeyA ^= key[n]
        nKeyPos = KeyA % 20

        for n in range(len(pCipherBuffer)):
            pPlainBuffer.append(pCipherBuffer[n] ^ (key[nKeyPos] * KeyA))
            KeyA += pCipherBuffer[n]
            nKeyPos = pCipherBuffer[n] % 20

        return pPlainBuffer

if __name__ == "__main__":
    import random

    key = [random.randint(0, 255) for k in range(20)]

    pPlainBuffer = [ord(c) for c in "this is the unencrypted message"]
    a = Encrypt(key, pPlainBuffer)
    b = Decrypt(key, a)

    print("-"*80)
    print("Encrypted message")
    print("-"*80)
    print(":".join("{:02x}".format(c) for c in a))
    print("-"*80)
    print("Decrypted message")
    print("-"*80)
    print("".join([chr(c) for c in b]))

    # --------------------------------------------------------------------------------
    # Encrypted message
    # --------------------------------------------------------------------------------
    # 1ba:2678:197df9:bec4844:2d163e70c:1d01cf925ab:45512ab14a9b:4724251445d50:550934523b78ca:1f34a7cfbb7db6a1:1bfb485c731bcdb713:161112a22402868312ad:b1696bc757013314e2975:531cf11bdcc471dc32befef:a2627edf4f99a01240ba016f:839c3758163127edc2e955cc63:100437038699e709cce258a3ed1b:6c7fa638eaa735df4ae48a03e32a9:58911d1d6ea1c00863052f0fa160a0d:2c7f52a5aa98fec79d57f011bf256acf0:22559e3d644a5d56f620427531855711f90:81693c9711311b3cfe601f0f44c5ec6c8eb9:6a628fdbfce204d77db6eb221a161b683dee6a:c86f7e57fa208eaff7fbe01b26048cae230f1a8:308b00994e93e28e9e0f004693351a122c7da861d:2bc2e905f06bc052ef96e3dd7d68389e9df11483546:9717a6cd2ce3ac9b8757110bab10b835b11adda93df2:12072f89ef89b60cbd3d4c3735dda19daddbeecfd47b5d:1084c8b9afea8c4ece5432ef4130712f4f9a5a403acac323:27679b285784a6a9f1d42189acfc9433655c776e5ce16d191:1c6f807e0f27d47ad8ee72ba6740cb5dee4d918da413efe2f6d
    # --------------------------------------------------------------------------------
    # Decrypted message
    # --------------------------------------------------------------------------------
    # --------------------------------------------------------------------------------
    # this is the unencrypted message

That'd be almost a 1:1 c++ rewrited version but if you wanted a more pythonic one:

def encrypt(key, plain_buffer):
    key_pos = 0
    key_a = 0

    cipher_buffer = []

    if plain_buffer is not None:
        for k in key:
            key_a = key_a ^ k
        key_pos = key_a % 20

        for n, d in enumerate(plain_buffer):
            cipher_buffer.append(d ^ (key[key_pos] * key_a))
            key_a += cipher_buffer[n]
            key_pos = cipher_buffer[n] % 20

    return cipher_buffer


def decrypt(key, cipher_buffer):
    key_pos = 0
    key_a = 0

    plain_buffer = []

    if cipher_buffer is not None:
        for k in key:
            key_a ^= k
        key_pos = key_a % 20

        for n, d in enumerate(cipher_buffer):
            plain_buffer.append(d ^ (key[key_pos] * key_a))
            key_a += cipher_buffer[n]
            key_pos = cipher_buffer[n] % 20

    return plain_buffer

if __name__ == "__main__":
    import random
    random.seed(1)

    key = [random.randint(0, 255) for k in range(20)]

    plain_buffer = [ord(c) for c in "this is the unencrypted message"]
    a = encrypt(key, plain_buffer)
    b = decrypt(key, a)

    print("-" * 80)
    print("Encrypted message")
    print("-" * 80)
    print(":".join("{:02x}".format(c) for c in a))
    print("-" * 80)
    print("Decrypted message")
    print("-" * 80)
    print("".join([chr(c) for c in b]))

Although is not using unsigned chars, that's why the encrypted message looks that big.