I've been working on this for a while, and now that I've got a working program I thought I'd see what other people think about it.
Basically if there is anything you think would make it faster or make it simpler, or make it better in general, please share your thoughts. As for actual strength, I have no idea how to test that. And yes, I know I should just use AES, but this is just for practice/fun more than anything.
Anyway, here's the code. (255 lines, sorry)
import base64
import os
import random
# from datetime import datetime
def add_padding(s, i=128):
padding = len(s) % i
for j in range(i - padding):
s += '='
s = ascii_to_bin(s)
# make last byte equal to number of padding bytes
s = s[:len(s) - 8] + decimal_to_binary([i - padding])
return s
def xor_string(k, s):
xored_secret = ''
for i in range(len(s) // len(k)):
if i > 0:
k = round_key(k)
xored_secret += decimal_to_binary([bin_to_decimal(k, len(k))[0] ^ bin_to_decimal(s[i * len(k):len(k) + (i * len(k))], len(k))[0]], len(k))
return xored_secret
def generate_key(k):
if len(k) == 128:
k = ascii_to_bin(k)
return k
elif len(k) < 128:
k = ascii_to_decimal(k)
for i in range(128 - len(k)):
b = decimal_to_binary([k[i]])
b = xor_string(decimal_to_binary([int(sum(k) / len(k))]), b[::-1])
k.append(int(b, 2))
s = ''
for i in k:
s += str(i)
j = str(s[:len(s) // 2])
y = str(s[len(s) // 2:])
s = decimal_to_binary([int(y + j)])
s = s[:1024]
return s
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 ascii_to_bin(string):
return decimal_to_binary(ascii_to_decimal(string))
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]
# returns an list of ints
return decimal
def decimal_to_binary(decimal, length=8):
output = ''
for i in range(len(decimal)):
output += str(bin(decimal[i])[2:].zfill(length))
# returns a string
return output
def ascii_to_decimal(string):
# returns a list of ints
return [ord(i) for i in string]
def bin_to_ascii(binary):
x = bin_to_decimal(binary)
s = ''
for i in x:
s += chr(i)
# returns a string
return s
def base64_to_bin(base):
decoded = ''
for letter in base64.b64decode(base):
# print(letter)
decoded += bin(letter)[2:].zfill(8)
return decoded
def matrix_to_str(m):
s = ''
for i in range(32):
for j in range(32):
s += str(m[i][j])
return s
def obfuscate(binary, k, x, xd):
b = ''
d = k # donkey kong
for i in range(len(binary) // 1024):
if i > 0:
d = round_key(d)
# m = [list(binary[j * 32 + i * 1024:j * 32 + i * 1024 + 32]) for j in range(32)]
if x:
m = [list(binary[j * 32 + i * 1024:j * 32 + i * 1024 + 32]) for j in range(32)]
m = shuffle(m, bin_to_decimal(d, 1024)[0], xd)
b += xor_string(d, matrix_to_str(m))
elif not x:
xor = xor_string(d, 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(d, 1024)[0], xd)
b += matrix_to_str(m)
return xor_string(k, b)
def shuffle(m, d, xd):
for j in range(xd):
# 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(d)):
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, d, xd):
for j in range(xd):
# 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(d)):
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(d):
random.seed(d)
lst = list(range(1024))
random.shuffle(lst)
return lst
def round_key(k):
k = [[k[(j * 32 + n)] for n in range(32)] for j in range(32)]
# get the last column
col = [i[-1] for i in k]
# 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 k:
cols += row[i]
cols = cols[16:] + cols[:16]
new_key += xor_string(''.join(str(ele) for ele in col), cols)
return new_key
def encrypt(p, s, xd):
k = generate_key(p)
s = add_padding(s)
s = xor_string(k, s)
s = obfuscate(s, k, True, xd)
s = bin_to_base64(s)
return s
def decrypt(p, b, xd):
k = generate_key(p)
b = base64_to_bin(b)
b = xor_string(k, b)
b = obfuscate(b, k, False, xd)
pad = b[len(b) - 8:]
b = bin_to_ascii(b)
b = b[:len(b) - bin_to_decimal(pad)[0]]
return b
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)}') # the 1 is the number of loops, I'm not sure how many I should do :/
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
If you need clarification on anything, just ask. Thanks!