22/12/2025
This is the almost final version of my encryption/decryption function that I started to make two weeks ago.
The first version was actually an big giant error, but with the received answers I understood the basic that was needed to be at least "not bad".
I remade everything, with all I understood, knew and could. I really think it is not bad now.
This code is missing only one feature I'm trying to apply, which is a text scrambler at the final result text. When I finish with it, I'll add the link to the final version on the last line of this question, so if you want it (I don't really recommend for REAL sensitive information, but you can always encrypt more), just click the link and copy the function.
This was my first attempt. Take a look at the answers, because they are really good, specially the first, in terms of encryption.
Goal for the code
Encrypts and decrypts an string, keeping it same length (or almost).
CODE
"""
The module basic_py (this file) has some functions that
you can import or copy/paste on you'r project.
*If you are going to copy/paste, pay atention on code
to not forget to copy other depended functions.*
The functions are:
(...other functions on the same file i made...)
X_to_decimal():
Decodes an number coded in X
(type of encoding, like Hexadecimal) to decimal.
get_index():
Gets the index of an object on an given list,
the first time it is found.
basic_py_enc_engine():
First step for basic_py_encrypter() and basic_py_decrypter().
*You don't need to call it.*
Just scrambles an list of characters
based on password hash with sha3-512.
basic_py_encrypter():
Encrypts text based on key using sha3-512.
basic_py_decrypter():
Decrypts texts encrypted with basic_py_encrypter().
basic_ui_bpy_enc():
Is an basic UI for the basic_py_encrypter/decrypter.
Made with the help from @J_H, @toolic, @Chris, @Kate on SO on first attempt.
"""
from hashlib import sha3_512
def x_to_decimal(Digit: str, Lista: list|str = "0123456789abcdef") -> int:
"""Converts Digit coded by Lista
(the 'allphabet' of the encoded digit) to decimal digits.
Lista defalt is Hexadecimal"""
output = 0
for value in range(len(Digit)):
for index, char in enumerate(Lista):
if Digit[((value - len(Digit)) * -1 - 1)] == char:
output += index * (len(Lista) ** (value))
return output
def get_index(Char: str|list, Lista: list|tuple|dict|str) -> int:
"""Gets index of character on given list.
If Char isn't found on Lista, returns None
:Char: Is the character to be searched.
(If whole str is desired, put into an list),
If is an list, gives the index of the first common iten.
:Lista: Is the place to be searched on."""
for _, character in enumerate(Char):
for index, char in enumerate(Lista):
if character == char:
return index
def basic_py_enc_engine(Key: str, Security_word: str = "") -> tuple[str, str]:
"""First code before basic_py_encrypter() and basic_py_decrypter()
:Don't need to call: The basic_py_encr. and basic_py_decr. allreay call it."""
# 1º block some base variables
characters = '¨0123456789abcçdefghijklmnopqrstuvwxyzáàãâéèêíìîóòõôúùûABCÇDEFGHIJKLMNOPQRSTUVWXYZÁÀÃÂÉÈÊÍÌÎÓÒÕÔÚÙÛ !@#$%&*()-_=+´"`[]}{~^<>|/,.;:?¹²³£¢¬§ªº°₢'
# 1 "False" for each character, used later on to verify if every character was used
base_verification_list = [False] * len(characters)
full_key = Key + Security_word
# 2º block hash code
key_hash = x_to_decimal(sha3_512(full_key.encode()).hexdigest())
for _ in range(3): # key_hash needs to be at least ~400 len to scramble every character
key_hash = key_hash ** 2
if key_hash >= 10 ** 4000:
# set key_hash to have at max 1.5k characters if key_hash > 4300 char
time = 0
max_time = 10**2
aceptable_lengh = 10**1500
max_characters = 10**4200
while key_hash > aceptable_lengh:
key_hash = key_hash // 10 ** 20
time += 1
if time >= max_time and key_hash < max_characters:
# it tests if key_hash allready is usable if its taking too long
break
# 3º block allphabet scrambler code
hash_word = str(key_hash) if len(str(key_hash)) % 3 == 0 else str(key_hash) + "0" if len(str(key_hash)) % 3 == 2 else str(key_hash) + "00"
# The hash_word needs to be divisible by 3.
hash_indexes_3len = [hash_word[index: index + 3] for index in range(0, len(hash_word), 3)]
scrambled_allphabet = ""
verification = 0
for _, char in enumerate(hash_indexes_3len):
# prevents from crash if char is bigger than 141
while int(char) > len(characters):
char = str(int(char) - len(characters))
for index, _ in enumerate(characters):
if not base_verification_list[index] and int(char) == index:
base_verification_list[index] = True
verification += 1
scrambled_allphabet += "".join(characters[index])
if verification == len(characters):
break
# Test if allphabet scrambler code have scrambled every character
if verification != len(characters):
for idx in range(len(characters)):
if not base_verification_list[idx]:
scrambled_allphabet += "".join(characters[idx])
return characters, scrambled_allphabet,
def basic_py_encrypter(Key: str, Text: str, Security_word: str = "") -> str:
"""BEFORE saving the encrypted output, be sure that/test if the Key can decrypt it right.
:Key: (String) Is the password to use to encrypt.
:Text: (String) Is the text to be encrypted.
:Security_word: (String) Is the (2º password) word that will be added on encrypted text and used on decryption to test. (If let blank, there wont be an test on decryption).
:OUTPUT: String
:VERSION: v0.95 //Working on text scrambler//"""
characters, scrambled_allphabet = basic_py_enc_engine(Key, Security_word)
full_text = Security_word + Text
output_text = ""
for _, character in enumerate(full_text):
character = '"' if character == "'" else character
letter = characters[get_index(character, scrambled_allphabet)]
output_text += letter
return output_text
def basic_py_decrypter(Key: str, Text: str, Security_word: str = "") -> str:
""":Key: (String) Is the password used to encrypt.
:Text: (String) Is the text to be decrypted.
:Security_word: (String) Is the (2º password) word that you gave or not when encrypting. (Let blank if not used).
:OUTPUT: String
:VERSION: v0.95 //Working on text scrambler//"""
characters, scrambled_allphabet = basic_py_enc_engine(Key, Security_word)
# Turns True or False depending on Security_word
Security = True if Security_word != "" else False
output_text = ""
test = ""
if Security:
security_test_list = [Text[0: len(Security_word)][index] for index in range(len(Security_word))]
for _, index in enumerate(security_test_list):
test += scrambled_allphabet[get_index(index, characters)]
if Security_word != test:
return
text_in_list = [Text[index] for index in range(len(Text))]
verification = len(Security_word)
while verification > 0:
text_in_list.pop(0)
verification -= 1
for _, index in enumerate(text_in_list):
output_text += scrambled_allphabet[get_index(index, characters)]
return output_text
def basic_ui_bpy_enc() -> str:
"""This is an basic User Interface in Comand Prompt for the basic_py_encrypter/decrypter().
Returns 'Q' if "Quit" is chosen."""
while True:
start_choice = input("\nBasic_py_encrypter/decrypter.py V0.95\n[E]ncrypt\n[D]ecrypt\n[Q]uit\n\n> ").strip().lower()
if start_choice == "q":
print("\nBye!\n")
return "Q"
if start_choice != "e" and start_choice != "d":
print("Invalid input.")
continue
break
path_choice = "encrypt" if start_choice == "e" else "decrypt"
text = input(f"\nYou'r text to {path_choice}:\n> ")
key = input(f"\nYou'r key for {path_choice}:\n> ")
security_word = input(f"\nSecurity word?{'' if start_choice == 'e' else ' (If used)'}\n(enter 'n' to leave blanck)\n> ")
security_word = "" if security_word == "n" else security_word
if start_choice == "e":
return basic_py_encrypter(key, text, security_word)
return basic_py_decrypter(key, text, security_word)
if __name__ == "__main__":
# simple use of basic_ui_bpy_enc():
hint = True
print("""\nNotes:
Note #1: Always choose a strong password, containing special characters,
lowercase and uppercase letters and numbers.
Note #2: Always use trusted libraries for creating password hashes.
Note #3: Stop using weak hashing algorithms such as md5, sha1, sha256, etc.""")
while True:
test = basic_ui_bpy_enc()
if test == "Q":
break
print(f"\nYou'r output:\n> {test}")
if hint:
print("...why don't you try encrypting it multiple times with different Keys for more security?...")
hint = False