[python]Hand made cryptography with XOR method.

ord function is to convert a character to its equivalent integer representation.

chr function is to convert the integer to its character representation.

random.choice() method randomly picks a character from a series of characters to form a string of N length, this is the key for encryption and decryption.

A message is taken from user’s input, for each character in a message it is mapped together with a character of a key with the zip function.
The zip object is a collection of a message’s character and key’s character pair, each pair is exclusively ORed and form a string.

itertools.cycle() method is to cycle through the key string, hence there is no need to check the length of the key string.

Without itertools.cycle() the key string length has to be more than or equal to the message otherwise the message will not be fully encrypted causing a lost of original message.

This is a simple demonstration if the key string length is shorter than the message length.

key = "secretkey"
message = "this is my message, see if it can be encrypted completely."

cipher_text = "".join(chr(ord(c1) ^ ord(c2)) for c1, c2 in zip(message, key))
plain_text = "".join(chr(ord(c1) ^ ord(c2)) for c1, c2 in zip(cipher_text, key))

The result is like this:

With itertools.cycle the characters of the key string will be re-cycled until the entire message is completed.

from itertools import cycle

key = "secretkey"
message = "this is my message, see if it can be encrypted completely."

cipher_text = "".join(chr(ord(c1) ^ ord(c2)) for c1, c2 in zip(message, cycle(key)))
plain_text = "".join(chr(ord(c1) ^ ord(c2)) for c1, c2 in zip(cipher_text, cycle(key)))

The result is the entire message is encrypted and preserved after decryption.

Package of all the functions to encrypt and decrypt message.

from itertools import cycle
import random
import string

# The string of lower and upper case alphabets and all digits.
str_types = string.ascii_lowercase + string.ascii_uppercase + string.digits
# tuple of errors.
errors = IOError, OSError

def xor_fn(message, cipher_key):
    This is an Exclusive OR function
    :param message:
        plaintext or cipher text.
    :param cipher_key:
        key chosen by create_key function.
        return a string either cipher text or plain text.
    return "".join(chr(ord(x) ^ ord(y)) for x, y in zip(message, cycle(cipher_key)))

def create_key(key_len=1024):
    Create a key string picked from str_types object.
    :param key_len:
        The length of the key string, default is 1024 bytes.
        return key string.
    return "".join(random.choice(str_types) for _ in range(0, key_len))

def write_file(filename, data):
    Write the string to file
    :param filename:
    :param data:
        the data to be written to the file.
        with open(filename, "w") as file:
        print(f"{filename} is written successfully.")
        return True
    except errors as e:
        return False
    except:  # Generic errors that are not expected.
        print(f"Unknown error has occurred while writing to {filename}.")
        return False

def read_file(filename):
    Open the specified file and read its contents.
    :param filename:
        contents from the file.
        with open(filename, "r") as file:
            data = file.read()
        return data
    except errors as e:
    except:  # Generic errors that are not expected.
        print(f"Unknown error has occurred while reading {filename}.")

So here is the example code that creates the key file, and then prompts user to enter a message for encryption, then after that decrypts the message.

from handmade_crypto import *
import sys
from os.path import exists

if exists("secret.key"):
    message = input("Your secret message: ")
    crypto_key = read_file("secret.key")
    cipher = xor_fn(message, crypto_key)
    print(f"Cipher text is: {cipher}")
    write_file("ciphertext.txt", cipher)
    data = read_file("ciphertext.txt")
    plain = xor_fn(data, crypto_key)
    print(f"Decrypted text: {plain}")
    key = create_key()  # Key length is 1024 bytes long.
    print(f"Key generated: {key}")
    if write_file("secret.key", key):
        print("Key is written to file.")
        print("Key has failed to write to file.")

So here is the result, as there is no key yet, a key is created on the first run.
The secret key string is this 8upGC890zAQeNOxdfgYHV77zpBIWouMWiTxBrNkX1bzsxPN8Xn8D9ic7Hjhf2QAdiOqmIHIJLByIuBo00ZXW4vUNMPvpiu8O8IWDAnY0F38oOi4bLWePlLMkRM4k3DcjSZ7VMUDzaYwM09O11ElRy0WGlEiRwCJ43VXw6vvwPRhQI1mKf34rthXRmqsKyk4qEx22WddcWgkjq2Nct4ZJoWX9Rd8dAVEGH3cVcpfn30vTryWePgb64ZV6VCj1wUHP1ffCmWBqDPDtZGHG45dwwWLwrbbBEWoqbyt5iXgaZOHFknE3h9qERCx51GzdTjK1B2PtObaE2WKQMvvcwefEj7dReJ73nR5BucaYvDcLEqzt2UAQpe4aH4vO123nI5lYStbyEyezVSvJz4G3woMGwVyADfk2jAx2IvnvaCzMDkwVtQaolTPlYwXLtkll0bynl9xqBhUrL1ywSxim3VsFqObHjyePquHduRXUbzOXCK8Jk7caICM5BOdNw18Kf3USS7FH2HwZ2mjsEYCvWCovfZwPrxfBULgVv3kYUSpAKGRnp4ChljflD7063eQqk47jGg5dr3LkkhpBccQkrpTpw7TXnCwOnS7UoIOIREVBykIDHsebglOf9i10Wyt5cs8sbVx3Mj7yye0SeXB0f1VGnveARUJrDRZE39y5kNn9P1kzrcCU9TsYscMy4T2yPoPRSZpWBhi6tYaExlmOeeQWmJtXncS1sRQb99KC9t9rftFJ2vajhyDYI4YfXtuJypcsxVrKK9sz8SuLEM3Q8Wa8Uqvfip4AyVBqxuSwp33KZFX1ft7PrPerJUweBa6f4Url5l57678xbHHqObZtu0NO2Hkqj8JpZRvauw9nXTWS07mNjD5yylkOV9EB5j72Dr5mzkEMQxisyJOyP1fPG7GVXkEOvsZvNKp16SD5Pjsif7BBwA0N1rlZ9wPeBDdDAYT0dAnyRy87CtThG4R97vjkizAsPpyIZAL668xkQ6glsKviAwEV8v1UNeUL5AzI0Jnc which is 1024 characters long.

On the second run a prompt appears to get the message input from user then it encrypts and decrypts with the key file.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s