This is a follow-up question to this one.
I have tried to implement all the recommended things in the answers (except commenting, and not being OS specific). Again, if you see anything that needs improvement, or would make it faster, please tell me!
Here's the code. Only 222 lines this time :).
#!/usr/bin/env python
# not sure if I did this right
import base64
import random
import os
def add_padding(plain_text, block_size=128):
plain_text = plain_text.encode()
padding = -(len(plain_text) + 1) % block_size # Amount of padding needed to fill block
padded_text = plain_text + b'=' * padding + bytes([padding + 1])
return decimal_to_binary(padded_text)
def xor_string(key, secret):
xored_secret = ''
for i in range(len(secret) // len(key)):
if i > 0:
key = get_round_key(key)
xored_secret += decimal_to_binary([bin_to_decimal(key, len(key))[0] ^ bin_to_decimal(secret[i * len(key):len(key) + (i * len(key))], len(key))[0]], len(key))
return xored_secret
def generate_key(key):
if len(key) >= 128:
key = decimal_to_binary(key.encode())
return key[:1024]
elif len(key) < 128:
key = key.encode()
for i in range(128 - len(key)):
b = decimal_to_binary([key[i]])
b = xor_string(decimal_to_binary([sum(key) // len(key)]), b[::-1])
key += bytes([int(b, 2)])
new_key = ''.join(str(i) for i in key)
half1 = new_key[:len(new_key) // 2]
half2 = new_key[len(new_key) // 2:]
new_key = decimal_to_binary([int(half1 + half2)])
new_key = new_key[:1024]
return new_key
def bin_to_base64(binary):
return base64.b64encode(bytes([int(binary[i * 8:8 + i * 8], 2) for i in range(len(binary) // 8)])).decode()
def bin_to_decimal(binary, length=8):
b = [binary[i * length:length + (i * length)] for i in range(len(binary) // length)]
decimal = [int(i, 2) for i in b]
return decimal
def decimal_to_binary(decimal, length=8):
return ''.join(str(bin(num)[2:].zfill(length)) for num in decimal)
def base64_to_bin(base):
decoded = ''
for letter in base64.b64decode(base):
decoded += bin(letter)[2:].zfill(8)
return decoded
def matrix_to_str(m):
return ''.join(str(m[i][j]) for i in range(32) for j in range(32))
def obfuscate(binary, key, encrypting, loops):
shuffled_binary = ''
round_key = key
for i in range(len(binary) // 1024):
if i > 0:
round_key = get_round_key(round_key)
if encrypting:
m = [list(binary[j * 32 + i * 1024:j * 32 + i * 1024 + 32]) for j in range(32)]
m = shuffle(m, bin_to_decimal(round_key, 1024)[0], loops)
shuffled_binary += xor_string(round_key, matrix_to_str(m))
else:
xor = xor_string(round_key, binary[i * 1024:i * 1024 + 1024])
m = [list(xor[j * 32:j * 32 + 32]) for j in range(32)]
m = reverse_shuffle(m, bin_to_decimal(round_key, 1024)[0], loops)
shuffled_binary += matrix_to_str(m)
return xor_string(key, shuffled_binary)
def shuffle(m, key, loops):
for j in range(loops):
# move columns to the right
m = [row[-1:] + row[:-1] for row in m]
# move rows down
m = m[-1:] + m[:-1]
shuffled_m = [[0] * 32 for _ in range(32)]
for idx, sidx in enumerate(test(key)):
shuffled_m[idx // 32][idx % 32] = m[sidx // 32][sidx % 32]
m = shuffled_m
# cut in half and flip halves
m = m[len(m) // 2:] + m[:len(m) // 2]
# test
m = list(map(list, zip(*m)))
return m
def reverse_shuffle(m, key, loops):
for j in range(loops):
# test
m = list(map(list, zip(*m)))
# cut in half and flip halves
m = m[len(m) // 2:] + m[:len(m) // 2]
shuffled_m = [[0] * 32 for _ in range(32)]
for idx, sidx in enumerate(test(key)):
shuffled_m[sidx // 32][sidx % 32] = m[idx // 32][idx % 32]
m = shuffled_m
# move rows up
m = m[1:] + m[:1]
# move columns to the left
m = [row[1:] + row[:1] for row in m]
return m
def test(seed):
random.seed(seed)
lst = list(range(1024))
random.shuffle(lst)
return lst
def get_round_key(key):
key = [[key[(j * 32 + n)] for n in range(32)] for j in range(32)]
# get the last column
col = [i[-1] for i in key]
# interweave
col = [x for i in range(len(col) // 2) for x in (col[-i - 1], col[i])]
new_key = ''
for i in range(32):
cols = ''
for row in key:
cols += row[i]
cols = cols[16:] + cols[:16]
new_key += xor_string(''.join(str(ele) for ele in col), cols)
return new_key
def bin_to_bytes(binary):
return int(binary, 2).to_bytes(len(binary) // 8, byteorder='big')
def encrypt(password, secret, loops):
key = generate_key(password)
secret = add_padding(secret)
secret = xor_string(key, secret)
secret = obfuscate(secret, key, True, loops)
secret = bin_to_base64(secret)
return secret
def decrypt(password, base, loops):
key = generate_key(password)
binary = base64_to_bin(base)
binary = xor_string(key, binary)
binary = obfuscate(binary, key, False, loops)
binary = bin_to_bytes(binary)
pad = binary[-1]
binary = binary[:-pad]
return binary.decode()
if __name__ == '__main__':
while True:
os.system('cls')
com = input('1)Encrypt Text \n2)Decrypt Text\n3)Exit\n')
if com == '1':
os.system('cls')
secret = input('Enter the text you wish to encrypt: ')
os.system('cls')
key = input('Enter your key: ')
os.system('cls')
print(f'Encrypted text: {encrypt(key, secret, 1)}')
input()
elif com == '2':
os.system('cls')
b64 = input('Enter the text you wish to decrypt: ')
os.system('cls')
key = input('Enter your key: ')
os.system('cls')
print(f'Decrypted text: {decrypt(key, b64, 1)}')
input()
elif com == '3':
break