How to Encrypt and Decrypt Files in Python Using XOR and Secrets

Learn to build a simple file encryption tool in Python by leveraging XOR operations and the secrets module to generate random keys, with step‑by‑step code for encrypting, decrypting, and handling text files securely.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
How to Encrypt and Decrypt Files in Python Using XOR and Secrets

In daily life we sometimes need to encrypt important files; Python provides convenient libraries such as hashlib and base64.

For learning purposes we can use the XOR operation to implement a simple file encryption program, which also helps strengthen programming skills.

Basic Knowledge

In Python the XOR operator is ^, also called XOR. Bitwise XOR yields 0 when the bits are the same and 1 when they differ. The four possible cases are:

0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0

From this we can derive two useful rules (A is 0 or 1):

0 ^ A = A

1 ^ A = ~A (the complement of A)

Properties of XOR for binary numbers:

A binary number XORed with itself yields 0 (b ^ b = 0).

XOR is associative and commutative: a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c.

0 XOR a = a, and (a ^ b) ^ b = a.

Principle

Understanding the properties of XOR makes the encryption principle clear.

Encryption operation

First convert the file to a binary number, then generate a random key of the same length, and XOR the binary data with the key to obtain the encrypted binary data.

Decryption operation

XOR the encrypted binary data with the same key to recover the original binary data, then convert it back to a text file.

Generate random key

The secrets module (available from Python 3.6) provides a suitable pseudo‑random generator. token_bytes creates a random byte string of a specified length, and int.from_bytes converts it to an integer.

from secrets import token_bytes

def random_key(length):
    key = token_bytes(nbytes=length)
    key_int = int.from_bytes(key, 'big')
    return key_int

Encryption unit

The encrypt function takes a str object and returns a tuple (int, int). It encodes the string to bytes, converts the bytes to an integer, generates a random key of the same length, and XORs the integer with the key.

def encrypt(raw):
    raw_bytes = raw.encode()
    raw_int = int.from_bytes(raw_bytes, 'big')
    key_int = random_key(len(raw_bytes))
    return raw_int ^ key_int, key_int

Decryption unit

The decrypt function receives the encrypted integer and the key, XORs them to obtain the original integer, calculates the required byte length, converts the integer back to bytes, and decodes to a string.

def decrypt(encrypted, key_int):
    decrypted = encrypted ^ key_int
    length = (decrypted.bit_length() + 7) // 8
    decrypted_bytes = int.to_bytes(decrypted, length, 'big')
    return decrypted_bytes.decode()

Using these functions we can easily encrypt and decrypt text files.

>> raw = '画图省识春风面,环珮空归夜月魂'
>>> encrypted = encrypt(raw)
>>> encrypted
(217447100157746604585..., 9697901906831571319...)
>>> decrypt(*encrypted)
'画图省识春风面,环珮空归夜月魂'

Encrypt text file

The encrypt_file function reads a file, encrypts its contents, and writes the encrypted integer and key to JSON files. If no key path is provided, a key file is created in the same directory.

import json
from pathlib import Path

def encrypt_file(path, key_path=None, *, encoding='utf-8'):
    path = Path(path)
    cwd = path.cwd() / path.name.split('.')[0]
    path_encrypted = cwd / path.name
    if key_path is None:
        key_path = cwd / 'key'
    if not cwd.exists():
        cwd.mkdir()
        path_encrypted.touch()
        key_path.touch()
    with path.open('rt', encoding=encoding) as f1, \
         path_encrypted.open('wt', encoding=encoding) as f2, \
         key_path.open('wt', encoding=encoding) as f3:
        encrypted, key = encrypt(f1.read())
        json.dump(encrypted, f2)
        json.dump(key, f3)

Decrypt file

def decrypt_file(path_encrypted, key_path=None, *, encoding='utf-8'):
    path_encrypted = Path(path_encrypted)
    cwd = path_encrypted.cwd()
    path_decrypted = cwd / 'decrypted'
    if not path_decrypted.exists():
        path_decrypted.mkdir()
        path_decrypted /= path_encrypted.name
        path_decrypted.touch()
    if key_path is None:
        key_path = cwd / 'key'
    with path_encrypted.open('rt', encoding=encoding) as f1, \
         key_path.open('rt', encoding=encoding) as f2, \
         path_decrypted.open('wt', encoding=encoding) as f3:
        decrypted = decrypt(json.load(f1), json.load(f2))
        f3.write(decrypted)

After encrypting and decrypting a file, the decrypted file matches the original, as illustrated below:

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Pythonfile encryptionxorCode Tutorialsecrets module
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.