Information Technology Grimoire

Version .0.0.1

IT Notes from various projects because I forget, and hopefully they help you too.

XOR Cipher

XOR Decryption, Python 1 Liner

Replace es with your encrypted string and key with the key. Both key and plaintext are converted to hex.

python3 -c "import sys;e,k=map(bytes.fromhex,sys.argv[1:3]);print(''.join(chr(c^k[i%len(k)])for i,c in enumerate(e)).encode().decode())" "hex es" "hex key"

XOR Encryption, Python 1 Liner

Both key and plaintext are converted to hex.

python3 -c "import sys; p, k = sys.argv[1].encode(), bytes.fromhex(sys.argv[2]); print(''.join(format(c ^ k[i % len(k)], '02x') for i, c in enumerate(p)))" "hex plaintext" "hex key"

XOR Cipher Encrypt/Decrypt Script (Python/tkinter)

import tkinter as tk
from tkinter import ttk, messagebox
import os
import re

'''
Uses XOR cipher
Key should be same length as message
The ease of breaking an XOR cipher does not directly depend on the absolute lengths of the 
key or the message but rather on the relationship between the key length and the message 
length, the randomness of the key, and whether the key is reused.

reusing a key significantly weakens the cipher
'''

XORVERSION=3

def is_hex(s):
    return re.fullmatch(r'[0-9a-fA-F]+', s) is not None

def xor_encrypt_decrypt(input_text, key, is_encrypt=True, output_format='String'):
    if not is_hex(key):
        messagebox.showerror("Error", "Key is not valid hexadecimal.")
        return "Invalid Key"
    
    input_bytes = input_text.encode() if is_encrypt else bytes.fromhex(input_text)
    key_bytes = bytes.fromhex(key)
    
    result_bytes = bytes([b ^ key_bytes[i % len(key_bytes)] for i, b in enumerate(input_bytes)])
    
    if is_encrypt:
        return result_bytes.hex()
    else:
        if output_format == 'String':
            try:
                return result_bytes.decode('utf-8')
            except UnicodeDecodeError:
                return "Error: Resulting bytes don't decode to valid UTF-8."
        elif output_format == 'Hex':
            return result_bytes.hex()
        else:
            return ' '.join(format(byte, '08b') for byte in result_bytes)

def on_decrypt():
    encrypted_hex = entry_encrypted.get()
    key_hex = entry_key_dec.get()
    output_format = combo_output_format.get()
    result = xor_encrypt_decrypt(encrypted_hex, key_hex, is_encrypt=False, output_format=output_format)
    output_text_dec.delete('1.0', tk.END)
    output_text_dec.insert('1.0', result)

def on_encrypt():
    plain_text = entry_plain.get()
    if len(plain_text) > 256:
        messagebox.showwarning("Warning", "Maximum allowed message size is 256 characters. Truncating message.")
        plain_text = plain_text[:256]  # Truncate to 256 characters
        entry_plain.delete(0, tk.END)
        entry_plain.insert(0, plain_text)

    key_hex = entry_key_enc.get()
    result = xor_encrypt_decrypt(plain_text, key_hex, is_encrypt=True)
    output_text_enc.delete('1.0', tk.END)
    output_text_enc.insert('1.0', result)

def generate_random_key():
    plain_text_length = len(entry_plain.get())
    # Ensure the key is at least 64 bits long, or as long as the message
    key_length_bytes = max(8, plain_text_length)
    random_key = os.urandom(key_length_bytes).hex()
    entry_key_enc.delete(0, tk.END)
    entry_key_enc.insert(0, random_key)


# GUI setup
root = tk.Tk()
root.title(f"XOR Cipher v{XORVERSION}")

# Set the "clam" theme
style = ttk.Style()
style.theme_use("clam")

# Configure the style for buttons and entry widgets
style.configure('TButton', font=('Helvetica', 10))
style.configure('TEntry', font=('Helvetica', 10), padding="5 5 5 5")

tab_control = ttk.Notebook(root)

# Encryption Tab
tab_encrypt = ttk.Frame(tab_control)
tab_control.add(tab_encrypt, text="Encrypt")

# Decryption Tab
tab_decrypt = ttk.Frame(tab_control)
tab_control.add(tab_decrypt, text="Decrypt")

# About Tab
tab_about = ttk.Frame(tab_control)
tab_control.add(tab_about, text="About")
tab_control.pack(expand=1, fill="both")

# Encryption Widgets
tk.Label(tab_encrypt, text="Plain Text:").grid(row=0, column=0, sticky="w")
entry_plain = ttk.Entry(tab_encrypt, width=38)
entry_plain.grid(row=0, column=1, pady=(5, 0))

encrypt_button = ttk.Button(tab_encrypt, text="Encrypt", command=on_encrypt)
encrypt_button.grid(row=0, column=2, sticky="w", padx=(5, 0), pady=(5, 0))


tk.Label(tab_encrypt, text="Key (Hex):").grid(row=1, column=0, sticky="w")
entry_key_enc = ttk.Entry(tab_encrypt, width=38)
entry_key_enc.grid(row=1, column=1, sticky="ew", pady=(5, 0))

generate_key_button = ttk.Button(tab_encrypt, text="Generate", command=generate_random_key)
generate_key_button.grid(row=1, column=2, sticky="w", padx=(5, 0), pady=(5, 0))


output_text_enc = tk.Text(tab_encrypt, height=5, width=50)
output_text_enc.grid(row=3, column=0, columnspan=3, padx=(5, 0), pady=(5, 0))

# Decryption Widgets
tk.Label(tab_decrypt, text="Encrypted String (Hex):").grid(row=0, column=0, sticky="w")
entry_encrypted = ttk.Entry(tab_decrypt, width=50)
entry_encrypted.grid(row=0, column=1, columnspan=2, pady=(5, 0))

tk.Label(tab_decrypt, text="Key (Hex):").grid(row=1, column=0, sticky="w")
entry_key_dec = ttk.Entry(tab_decrypt, width=50)
entry_key_dec.grid(row=1, column=1, columnspan=2, pady=(5, 0))

tk.Label(tab_decrypt, text="Output Format:").grid(row=2, column=0, sticky="w")
combo_output_format = ttk.Combobox(tab_decrypt, values=["String", "Hex", "Binary"], state="readonly")
combo_output_format.grid(row=2, column=1, sticky="ew", pady=(5, 0))
combo_output_format.set("String")

decrypt_button = ttk.Button(tab_decrypt, text="Decrypt", command=on_decrypt)
decrypt_button.grid(row=2, column=2, sticky="w", padx=(5, 0), pady=(5, 0))

output_text_dec = tk.Text(tab_decrypt, height=5, width=50)
output_text_dec.grid(row=3, column=0, columnspan=3, padx=(5, 0), pady=(5, 0))

# About Information
about_text = """
XOR Cipher Explained
--------------------
The XOR (exclusive OR) cipher is a type of additive cipher that operates according to the principle that XORing a bit with another bit twice returns the original bit. 

Key Strength:
The strength of an XOR cipher lies in the key. If the key is random, as long as the message itself, and used only once, the cipher is theoretically unbreakable (One-Time Pad). However, if the key is shorter than the message or reused, patterns can emerge that might be exploited for decryption.

For the 256-bit (32 bytes) random key generated in this application, assuming perfect randomness and single-use, the strength is very high against brute-force attacks. Modern desktop CPUs and GPUs, despite their power, would take an impractically long time to crack a 256-bit key through brute force, making it secure for most practical purposes.

However, it's crucial to note that security also depends on key management, randomness, and not reusing the key.

Historical Context:
The concept of XOR encryption is rooted in the idea of the Vernam cipher, which was a perfect secret key cipher when the key was random, as long as the message, and used only once. It's a simple yet powerful method for encrypting data, making it a fundamental concept in the study of cryptography.

Type of Cipher:
XOR ciphers belong to the symmetric key cryptography category, where the same key is used for both encryption and decryption. This simplicity, however, demands strict secrecy of the key.

Educational Relevance:
Understanding XOR ciphers provides a foundational insight into more complex encryption algorithms and the importance of key secrecy, length, and randomness in cryptography.
"""

about_label = tk.Text(tab_about, height=20, width=50, wrap="word")
about_label.grid(row=0, column=0, padx=10, pady=10)
about_label.insert(tk.END, about_text)
about_label.config(state="disabled")  # Make the text read-only


root.mainloop()