1

I am trying to XOR a 12-bits long message against an 8-bits long key.

Method of wrapping the key that seems to work (when scaled-up and used against a 269-bit long encrypted message) is the following:

message = "110111101010"

key = "01100001"

def adjust_key_length(message, key):
    multiplier = len(message) / len(key)
    modulo = len(message) % len(key)
    adjusted_key = key[0:modulo] + key * multiplier
    return adjusted_key

Code above translates to:

multiplier = 1
modulo = 4
adjusted_key = "0110" + "01100001"

As I've said above, this method of adjusting the key length seems to work on an actual encrypted message, yielding a decrypted English plaintext, with one exception: The first ASCII character of the encrypted word seems to be missing, as the word reads "ooking".

I'm presuming it's supposed to be "cooking".

What is the right way to XOR a longer message against a one-byte key?

Pat Res
  • 97
  • 1
  • 7

1 Answers1

2

Your adjusted_key is not correct.

def adjust_key_length(message, key):
    multiplier = len(message) / len(key)
    modulo = len(message) % len(key)
    adjusted_key = multiplier* key + key[0:modulo] 
    return adjusted_key

message = "110111101010"

key = "01100001"

print( adjust_key_length(message, key))

We expect a repeat of the key than some part

output   : 011000010110

If we talk about the proper method about encrypting a text via X-OR, you definitely need a longer keystream. You can generate by urandom for cryptographic use.

update on comments:

  1. In general Cryptographic challenges uses uppercase characters as historical ciphers.
  2. Binary conversion need fill in the beginning. '1b' is converted as 11011 not as 00011011. You can see from this answer

The upper part.

hex_string = "1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736"

num_of_bits = len(hex_string) * 4

binary_string = bin(int(hex_string, 16))[2:].zfill(num_of_bits)

# list of english characters
#chars = "abcdefghijklmnopqrstuvwxyz"
chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

# list comprehension, creating binary forms of above characters,
# making them 8 bits long by adding zeroes to the beginning
binary_chars = [format(ord(char), 'b').zfill(8) for char in chars]

def adjust_key_length(message, key):
    multiplier = int(len(message) / len(key))
    modulo = len(message) % len(key)
    adjusted_key = multiplier * key  + key[0:modulo]
    return adjusted_key
kelalaka
  • 5,064
  • 5
  • 27
  • 44
  • I've tried your approach before, but it didn't yield any readable plaintext. That's why I tried adding the partial key to the front of the key itself and it magically worked, producing a readable string. If you wonder what's the programming challenge I'm facing, you may look it up at https://cryptopals.com/sets/1/challenges/3 – Pat Res Jul 13 '19 at 20:26
  • Readable plaintext? You only gave your `adjust_key_length` method that has a mistake in repeating key context. How can we be sure that your other methods are correct? – kelalaka Jul 13 '19 at 20:29
  • It is hex encoded. I would rather convert first bytes then x-or then characters... – kelalaka Jul 13 '19 at 20:32
  • You are absolutely right, I might be wrong on more than one occasion. Here's a solution I came up with. https://repl.it/@PatRes/CryptoPals3 Run it and see the output given by key "x" (third from end). That's the only notion of human readable plaintext I'm getting. – Pat Res Jul 13 '19 at 21:02
  • I've found all of your mistakes. Printing what you calculated is always is a good practice, that is how I found your mistakes. – kelalaka Jul 13 '19 at 21:39
  • Incredible. Thank you for your time and effort. I understood everything, but one thing: why is num_of_bits equal to len(hex_string) * 4? Why is it four? – Pat Res Jul 14 '19 at 11:01
  • A hex number represents 4-bit, therefore, the number of bits in your hex string is `len(hex_string) * 4` – kelalaka Jul 14 '19 at 13:17