1

I am 14 years old and I have just created an encryption program with a friend. I wanted to know if anyone here could give me back any feedback on it.

Here is how the program works,

Imagine you want to encrypt the word 'hi',

Depending on the key that can be generated with the program, the computer will choose between 2 strings of two letters randomly for every letter that needs to be encrypted. The strings are embedded in an encryption/decryption key.

Example: 'h' when encrypted will be either 'tn' or 'io' and 'i' when encrypted will be either 'ac' or 'vu'

So when 'hi' will be encrypted, it can be,

'tnac'; 'tnvu'; 'ioac'; 'iovu'

This is chosen randomly by the computer so it is impossible to predict what outcome will be.

#######################################################################
#                                                                     #
#                  AGENCRYPTION program V.1.1                         #
#            Made by Elio Hayman and Valentino Magniette              #
#                           Have fun                                  #
#                                                                     #
#######################################################################

version = 'Version 1.1'
from random import *
import tkinter as tk

current_key = ''

account = ''
in_debug = False
def debug(text):
    if in_debug:
        print('[Debug]', text) 

key = ''
def decrypt(crypted):
    debug(crypted)
    global current_key
    key = current_key
    if key == '':
        print('[Error] Please insert a key before utilisation. To do so, do readkey <yourKey>.')
        return
    basemsg = ''
    key_list = []
    while not key == '':
        key_list.append(key[:5])
        key = key[5:]
    new_key = []
    for i in key_list:
        new_key_thing = []
        new_key_thing.append(i[0])
        new_key_thing.append(i[1:3])
        new_key_thing.append(i[3:])
        new_key.append(new_key_thing)
    key = new_key
    searchlength = 1
    msgleft = crypted
    found = False
    while len(msgleft) > 0:
        searchlength = 0
        found = False
        while found == False:
            if searchlength == 0 and len(msgleft) > 0:
                for x in key:
                    if found == False:
                        if msgleft[0] in x[1:]:
                            basemsg = basemsg + x[0]
                            msgleft = msgleft[1:]
                            found = True
            elif searchlength > 0 and len(msgleft) > 0:
                for x in key:
                    if found == False:
                        if msgleft[:searchlength-1] in x[1:]:
                            basemsg = basemsg + x[0]
                            msgleft = msgleft[searchlength-1:]
                            found = True
            searchlength += 1
    basemsg = basemsg.replace('^', ' ')
    return basemsg
def encrypt(message):
    global current_key
    key = current_key
    if key == '':
        print('[Error] Please insert a key before utilisation. To do so, do readkey <yourKey>.')
        return
    message = message.replace(' ', '^')
    endmsg = ''
    key_list = []
    while not key == '':
        key_list.append(key[:5])
        key = key[5:]
    new_key = []
    for i in key_list:
        new_key_thing = []
        new_key_thing.append(i[0])
        new_key_thing.append(i[1:3])
        new_key_thing.append(i[3:])
        new_key.append(new_key_thing)
    for char in message:
        for x in new_key:
            if x[0] == char:
                endmsg = endmsg + x[randint(1, len(x)-1)]
                break
    return endmsg

def readkey(input_key):
    all_chars = 'aabcdefghijklmnopqrstuvwxyz1234567890&²é~"#\'{([-|è`_\\çà@)]=}°+.+-*/,?;:!§ù%*µ$£¤^¨ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    key_list = []
    if len(input_key) == 779:
        print('Key loading...')
        parts = list()
        for i in range(109):
            key_part = input_key[:5]
            letter = key_part[0]
            part1 = key_part[1:3]
            part2 = key_part[3:5]
            list_thing = list()
            list_thing.append(letter)
            list_thing.append(part1)
            list_thing.append(part2)
            parts.append(input_key[:5])
            input_key = input_key[5:]

        print('Key inserted')
        print('Caution, this key will only stay in the program as long as it is running or when replaced by another one')
    else:
        print('[Error] This key is unsupported by the program. Make sure it is correct and that you are using the latest version.')
        return None
    return ''.join(parts)
def genkey():
    all_chars = 'aabcdefghijklmnopqrstuvwxyz1234567890&²é~"#\'{([-|è`_\\ç^à@)]=}°+.+-*/,?;:!§ù%*µ$£¤^¨ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    char_list = list('aabcdefghijklmnopqrstuvwxyz1234567890&²é~"#\'{([-|è`_\\ç^à@)]=}°+.+-*/,?;:!§ù%*µ$£¤^¨ABCDEFGHIJKLMNOPQRSTUVWXYZ')
    shuffle(char_list)
    all_chars = ''.join(char_list)
    key = list()
    security = 2
    for x in range(len(all_chars)*security):
        valid = False
        while valid == False:
            char1 = all_chars[randint(0,35)]
            char2 = all_chars[randint(0,35)]
            if not (char1 + char2) in key:
                key.append(char1 + char2)
                valid = True
    speshul_chars_letters = list()
    for i in range(117):
        valid = False
        while valid == False:
            char1 = all_chars[randint(0,35)]
            char2 = all_chars[randint(0,35)]
            if not (char1 + char2) in key or (char1 + char2) in speshul_chars_letters:
                speshul_chars_letters.append(char1 + char2)
                valid = True
    key_list = []
    for i in all_chars:
        chars = [i]
        for xx in range(security):
            chars.append(key[0])
            del key[0]
        key_list.append(chars)
    key_text = ''
    key_text_list = []
    for y in key_list:
        key_text_list.append(''.join(y))
    speshul_chars_letters_text = ''.join(speshul_chars_letters)
    return ''.join(key_text_list) + speshul_chars_letters_text

import tkinter as tk
from time import *
mw = tk.Tk()

mw.title('AGE v1.1')
mw.geometry("800x500")
mw.resizable(0, 0)

back = tk.Frame(master=mw,bg='#24b1db')
back.pack_propagate(0)
back.pack(fill=tk.BOTH, expand=1)

mode = 0

def purgescreen():
    if mode == 1:
        encryption_text_input.destroy()
        encryption_text_output.destroy()
        encrypt_main.destroy()
    elif mode == 2:
        decryption_text_input.destroy()
        decryption_text_output.destroy()
        decrypt_main.destroy()
    elif mode == 3:
        keygen_text_output.destroy()
        keygen_main.destroy()
        directapply_main.destroy()
    elif mode == 4:
        keyread_text_input.destroy()
        keyread_main.destroy()
    elif mode == 5:
        info_main.destroy()
        info_copyright.destroy()
        info_website.destroy()
        info_terms.destroy()
        info_version.destroy()
    elif mode == 6:
        help_main.destroy()
    elif mode == 7:
        welcome_main.destroy()

def encrypt_shortcut():
    message = encryption_text_input.get("1.0",'end-1c')
    encrypted = encrypt(message)
    encryption_text_output.delete("1.0","end")
    encryption_text_input.delete("1.0","end")
    encryption_text_output.insert("1.0",encrypted)

def encryption_button():
    global encryption_text_input
    global encryption_text_output
    global encrypt_main
    global mode
    purgescreen()
    mode = 1
    encryption_text_input = tk.Text(back, height=10, width=70)
    encryption_text_input.place(relx=.25 , rely=0)

    encryption_text_output = tk.Text(back, height=10, width=70)
    encryption_text_output.place(relx=.25, rely=.6)

    encrypt_main = tk.Button(master=back, text='Encrypt', command=encrypt_shortcut)
    encrypt_main.config(height=3, width=15)
    encrypt_main.place(relx=.5, rely=.4)

def decrypt_shortcut():
    message = decryption_text_input.get("1.0",'end-1c')
    decrypted = decrypt(message)
    decryption_text_output.delete("1.0","end")
    decryption_text_input.delete("1.0","end")
    decryption_text_output.insert("1.0",decrypted)

def decryption_button():
    global decryption_text_input
    global decryption_text_output
    global decrypt_main
    global mode
    purgescreen()
    mode = 2
    decryption_text_input = tk.Text(back, height=10, width=70)
    decryption_text_input.place(relx=.25 , rely=0)

    decryption_text_output = tk.Text(back, height=10, width=70)
    decryption_text_output.place(relx=.25, rely=.6)

    decrypt_main = tk.Button(master=back, text='Decrypt', command=decrypt_shortcut)
    decrypt_main.config(height=3, width=15)
    decrypt_main.place(relx=.5, rely=.4)

def keygen_shortcut():
    key = genkey()
    key = ''.join(key)
    keygen_text_output.delete("1.0",'end')
    keygen_text_output.insert("1.0",key)

def apply_shortcut():
    key = keygen_text_output.get("1.0","end-1c")
    global current_key
    current_key = key

def keygen_button():
    global keygen_text_output
    global keygen_main
    global mode
    global directapply_main
    purgescreen()
    mode = 3
    keygen_text_output = tk.Text(back, height=15, width=70)
    keygen_text_output.place(relx=.25 , rely=.4)

    keygen_main = tk.Button(master=back, text='Generate Key', command=keygen_shortcut)
    keygen_main.config(height=3, width=15)
    keygen_main.place(relx=.4, rely=.2)

    directapply_main = tk.Button(master=back, text='Apply Key', command=apply_shortcut)
    directapply_main.config(height=3, width=15)
    directapply_main.place(relx=.6, rely=.2)

def keyread_shortcut():
    key = keyread_text_input.get("1.0","end-1c")
    keyread_text_input.delete("1.0","end")
    global current_key
    current_key = key

def keyread_button():
    global keyread_text_input
    global keyread_main
    global mode
    purgescreen()
    mode = 4

    keyread_text_input = tk.Text(back, height=15, width=70)
    keyread_text_input.place(relx=.25, rely=.1)

    keyread_main = tk.Button(master=back, text='Insert Key', command=keyread_shortcut)
    keyread_main.config(height=3, width=15)
    keyread_main.place(relx=.5, rely=.7)

def info_button():
    global info_main
    global info_copyright
    global info_website
    global info_version
    global info_terms
    global mode
    purgescreen()
    mode = 5

    info_main = tk.Label(master=back, text='This program is made by \n Valentino Magniette and iWaroz.', bg='#24b1db')
    info_main.config(height=3, width=70)
    info_main.place(relx=.25, rely=.1)

    info_copyright = tk.Label(master=back, text='Copying this program or resseling it \n without permission from its creators is forbidden.', bg='#24b1db')
    info_copyright.config(height=3, width=70)
    info_copyright.place(relx=.25, rely=.3)

    info_terms = tk.Label(master=back, text='AGencryption and its creators are not responsible for any legal problems regarding \n  encrypting sensible documentation that the authorities want decrypted. ', bg='#24b1db')
    info_terms.config(height=3, width=70)
    info_terms.place(relx=.25, rely=.5)

    info_website = tk.Label(master=back, text='You can get the program for free at: http://realtasting.com/AGE-Version1.exe', bg='#24b1db')
    info_website.config(height=3, width=70)
    info_website.place(relx=.25, rely=.7)

    info_version = tk.Label(master=back, text='Version 1.1', bg='#24b1db')
    info_version.config(height=3, width=70)
    info_version.place(relx=.25, rely=.9)

def help_button():
    global help_main
    global mode
    purgescreen()
    mode = 6

    help_main = tk.Label(master=back, text='If any help is needed. \n Go to our discord with the link \n https://discord.gg/YVDBudA', bg='#24b1db')
    help_main.config(height=3, width=50)
    help_main.place(relx=.35, rely=.5)

global welcome_main
purgescreen()
mode = 7

welcome_main = tk.Label(master=back, text='Welcome to AGE \n This is a program which is used for encryption \n You can encrypt an unlimited ammount of text securely for free \n To start, you will need an encryption/decryption key for it to work \n Have fun!!', bg='#24b1db')
welcome_main.config(height=10, width=50)
welcome_main.place(relx=.35, rely=.35)

encryption_main = tk.Button(master=back, text='Encryption', command=encryption_button)
encryption_main.config(height=4, width=20)
encryption_main.place(relx=.095, rely=.07, anchor="c")

decryption_main = tk.Button(master=back, text='Decryption', command=decryption_button)
decryption_main.config(height=4, width=20)
decryption_main.place(relx=.095, rely=.21, anchor="c")

generator_main = tk.Button(master=back, text='Key Generator', command=keygen_button)
generator_main.config(height=4, width=20)
generator_main.place(relx=.095, rely=.35, anchor="c")

reader_main = tk.Button(master=back, text='Key reader', command=keyread_button)
reader_main.config(height=4, width=20)
reader_main.place(relx=.095, rely=.49, anchor="c")

information_main = tk.Button(master=back, text='Information', command=info_button)
information_main.config(height=4, width=20)
information_main.place(relx=.095, rely=.63, anchor="c")

help_main = tk.Button(master=back, text='Help', command=help_button)
help_main.config(height=4, width=20)
help_main.place(relx=.095, rely=.77, anchor="c")

quit_main = tk.Button(master=back, text='Quit', command=mw.destroy)
quit_main.config(height=4, width=20)
quit_main.place(relx=.095, rely=.91, anchor="c")

mw.mainloop()

  • 3
    If you want a code review better go to codereview.stackexchange.com – camp0 Nov 1 '19 at 11:44
  • 5
    A major part of your code is just user interface and has nothing to do with security at all. Apart from that this is primarily an undocumented code dump, i.e. it is not a question about a particular algorithm but about a specific implementation (off-topic). Anyway, the generic answer for own crypto is Why shouldn't we roll our own? and I recommend you to really understand why implementing your own encryption for any serious security (and this is what this site is about) is a bad idea. – Steffen Ullrich Nov 1 '19 at 11:50
  • 1
    val this is pretty good code for a 14 year old.good job.Apart from that if you are interested in writing encryption or anything crypto related you must pick up a book on cryptography before asking is this cryptographically secure ,But still super good for a 14 year old. – Vipul Nair Nov 1 '19 at 12:49
  • Welcome! I agree with camp0 - I think you'll get much more valuable feedback by taking this to codereview. Those guys are great at helping people learn coding. As for assessing the security of this, that's a bit off topic here. I think though that it's important to understand that what you have written is a substitution cipher. These can be interesting and are a great way to start learning (so fine choice to start with!), but are easily broken and shouldn't be used to encrypt important data. I imagine that isn't your plan, but I wanted to mention that. Great start, keep learning! – Conor Mancone Nov 1 '19 at 14:22
  • You do not explain what the goal of the program is and what kind of feedback you want. – schroeder Nov 1 '19 at 16:10
10

To asses your encryption method, you must assume that an adversary knows everything except the key. In your case, the adversary knows that every letter is substituted with one of two possible digraphs. In spite of the variance introduced, this still makes it a substitution cipher. Those can be attacked by simple statistics: Given a long enough crypto text, it is (depending on the language in the clear text) very likely that the most frequent letter is E (followed by N, R, I, S, T etc. with decreasing frequencies). Hence if the most frequent digraphs are ab and cd, it is very likely that these are the two encodings for E. Once the first few letters have been (probably) found this way, gaps are often quite easy to fill in from context or higher statistics.

7

Welcome to security.stackexchange!

First of all, I should start by quoting the Schneier's Law:

Anyone, from the most clueless amateur to the best cryptographer, can create an algorithm that he himself can't break. It's not even hard. What is hard is creating an algorithm that no one else can break, even after years of analysis.

This is valid for you, me, Bruce Schneier himself (a competent cryptographer), engineers designing real-world protocols, etc.

There is no harm however in designing and implementing toy encryption schemes for fun, as long as you are clearly aware that they are probably not actually secure.

In this case, here are a few things that I find could be improved in your code:

  • You are using a global variable current_key to hold the current key.

Generally, using variable objects to pass information between functions is discouraged. I would recommend directly passing the key as a parameter or, even better in this case, create an Encryption class which holds the key and functions encrypt, decrypt, readkey and genkey. You already have them all written at the beginning, as they are indeed a different block of code than the UI one.

  • Alphabet is repeated across the code.

Your chars list ('aabcdefghijklmnopqrstuvwxyz1234567890&²é~....) appears three different times in your code. One on readkey and twice on genkey (uselessly on all_chars variable). That should appear only once, probably as a constant, althoguh yu might also want to allow an Encryption instance to use a custom alphabet.

  • Your readkey function warns that key will only stay in the program as long as it is running but just having the inputkey is enough to recreate it. It's genkey() the one that creates a key from thin air

  • readkey is actually input_key[:545]

It is not clear the goal of the function readkey itself does. You are "shuffling" the input key, but actually you are converting a key of 779 characters into a key which simply consists of its first 545 characters in a convoluted way.

  • Key generation uses non-secure random number generators

genkey uses of shuffle() and randint() are using the default Mersenne Twister generator, which means your key security is actually that of the seed. See random.randint to generate cryptographically secure keys I would recommend using random.SystemRandom rng.

  • No need to replace ' ' with '^'

You are replacing ' ' with '^' on encryption and undoing it on decryption, but you could actually simply use a space on the alphabet instead. Note that if a text did use a circumflex (in the use of math, perhaps), your code would be converting it into a space.

  • Array new_key on encrypt

On encrypt you are using a list of three items: [original_character, replacement1, replacement2], and then for each letter you need to iterate all of the entries on new_key in order to find if the first entry is the current character. This would be more efficiently done if you had used a dictionary, in which case the lookup of the character would be immediate.

You might prefer to do it that way in order to ensure that you are using exactly the same code for key expansion on encrypt and decrypt. I would then use a single function to provide that, though.

  • Encryption method

Finally, your encryption method itself just works on substituting single letters into two options. This will fail immediately on frequency analysis when performed on pairs of letters. As each letter maps to a tuple, a few more crypted samples may be needed than otherwise, but recovery will be straightforward.

Note that per Kerckhoffs's principle we should design the system assuming that any attacker will know the inners of the system (except the key), in this case that each letter can map to a couple of glyphs (which would be easy to suspect, anyway).

Please remember that the goal of encryption is not that it is impossible to predict what is the encrypted outcome will be, but that given an encrypted text you can't recover the original one. If it was the former, simply a function like return str(randint(1000, 9999)) + plaintext would do that.

As further reading on different systems, I recommend you to read on the [Vigenère cipher](https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher], as well as trying to implement your own CipherSaber encryption.

And never be afraid of studying, experimenting and asking.

  • Thank you very much for all that you have added. I am sure that this will change many things in my program in the right way. I don't really know how to thank you as much. Valentino – Val198765 Nov 1 '19 at 14:50
  • I am glad to have been helpful, Valentino :) – Ángel Nov 1 '19 at 14:52

Not the answer you're looking for? Browse other questions tagged or ask your own question.