Level 5: Implement repeating-key XOR

Task

Here is the opening stanza of an important work of the English language:

Burning 'em, if you ain't quick and nimble
I go crazy when I hear a cymbal

Encrypt it, under the key "ICE", using repeating-key XOR.

In repeating-key XOR, you'll sequentially apply each byte of the key; the first byte of plaintext will be XOR'd against I, the next C, the next E, then I again for the 4th byte, and so on.

It should come out to:

0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272
a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f

Encrypt a bunch of stuff using your repeating-key XOR function. Encrypt your mail. Encrypt your password file. Your .sig file. Get a feel for it. I promise, we aren't wasting your time with this.


Explanation

How repeating-key works?

Repeating-key XOR is a method where the key is shorter than the string to encrypt. Once the key's characters are exhausted, it cycles back to the beginning and repeats until the entire string is processed.

Example:

String: B u r n i n g

Key: I C E

XOR: B ⊕ I, u ⊕ C, r ⊕ E, n ⊕ I, i ⊕ C, n ⊕ E, g ⊕ I

  • B ⊕ I means that the first character of the string is XORed with the first character of the key.

  • Once the last character of the key is reached, it loops back to the first character.

  • This cycle continues until all characters in the string have been XORed.


Resolution

First, we are going to create a file named task5.py

Understanding the code

  • repeating_key_xor(plaintext: str, key:str) -> str is a function that takes two string parameters and returns a string.

    • Three variables are created

      • plaintext_bytes stores the plaintext encoded to bytes.

      • key_bytes stores the key encoded to bytes.

      • key_length stores the length of key_bytes.

    • ciphertext_bytes is created as a result of the following expression:

      • bytes(plaintext_bytes[i] ^ key_bytes[i % key_lenght] for i in range(len(plaintext_bytes))

        • plaintext_bytes[i] represents the byte at the i-th position of the plaintext.

        • key_bytes[i % key_lenght] is the key byte used for XOR.

          • i % key_lenght is the trick that allows the key to repeat when it reaches the end.

        • ^ is the XOR operator, which performs the XOR operation between the plaintext byte and the key byte.

        • range(len(plaintext_bytes)) iterates over all the plaintext bytes.

Following the previous example, it works as shown:

i

plaintext character

byte (plaintext_bytes[i])

key character

Byte (key_bytes[i % key_lenght])

XOR result

0

B

66

I

73

11

1

u

117

C

67

54

2

r

114

E

69

55

3

n

110

I

73

39

4

i

105

C

67

46

5

n

110

E

69

43

6

g

103

I

73

46

  • Finally, plaintext is initialized with the string provided by Cryptopals, and key is initialized with the key provided by Cryptopals. The result of the repeating_key_xor function is printed.


Result

Last updated