I had this idea not to long ago on creating a secure chat for people who need to be not meddled with when talking (like whistleblowers, hackers, etc) talking to one of my friends about it he said I could use the One Time Pad Cipher, so I decided to write my own in Python.
If you don't know what the one time pad is, in a nutshell it's a cipher that generates a key for you that is as long as the string you pass to it, this key makes it theoretically impossible to crack the cipher without the key itself, due to their being so many possible combinations.
My cipher uses sqlite to store a database into memory to keep the keys unique, once the program is exited, the database is destroyed (theoretically). I would like someone to poke as many holes in this as possible, I would like to see if the string is possible to be cracked and would also like someone to break the database if possible. Basically I want to know how secure this is. Please keep in mind, this is not a finished product but just a fundamental understanding to a larger project. So critique away and have fun with it, thank you!
The code:
import random
import string
import sqlite3
PUNC = string.punctuation
ALPHABET = string.ascii_letters
def initialize():
"""
initialize the database into memory so that it can be wiped upon exit
"""
connection = sqlite3.connect(":memory:", isolation_level=None, check_same_thread=False)
cursor = connection.cursor()
cursor.execute(
"CREATE TABLE used_keys ("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"key TEXT"
")"
)
return cursor
def create_key(_string, db_cursor):
"""
create the key from a provided string
"""
retval = ""
set_string = ""
used_keys = db_cursor.execute("SELECT key FROM used_keys")
id_number = len(used_keys.fetchall()) + 1
for c in _string:
if c in PUNC:
c = ""
if c == " " or c.isspace():
c = ""
set_string += c
key_length = len(set_string)
acceptable_key_characters = string.ascii_letters
for _ in range(key_length):
retval += random.choice(acceptable_key_characters)
if retval not in used_keys:
db_cursor.execute("INSERT INTO used_keys(id, key) VALUES (?, ?)", (id_number, retval))
return retval, set_string
else:
create_key(_string, db_cursor)
def encode_cipher(_string, key):
"""
encode the string using a generated unique key
"""
retval = ""
for k, v in zip(_string, key):
c_index = ALPHABET.index(k)
key_index = ALPHABET.index(v)
cipher_index = c_index + key_index
try:
retval += ALPHABET[cipher_index]
except IndexError:
cipher_index -= 26
retval += ALPHABET[cipher_index]
return retval
def decode_cipher(encoded, key):
"""
decode the encoded string using the encoded string and the key used to cipher it
"""
retval = ""
for k, v in zip(encoded, key):
c_index = ALPHABET.index(k)
key_index = ALPHABET.index(v)
decode = c_index - key_index
try:
retval += ALPHABET[decode]
except IndexError:
decode += 26
retval += ALPHABET[decode]
return retval
def main():
"""
main messy function
"""
exited = False
choices = {"1": "show keys", "2": "create new key", "3": "decode a cipher", "4": "exit"}
cursor = initialize()
seperator = "-" * 35
print("database initialized, what would you like to do:")
try:
while not exited:
for item in sorted(choices.keys()):
print("[{}] {}".format(item, choices[item]))
choice = raw_input(">> ")
if choice == "1":
keys = cursor.execute("SELECT key FROM used_keys")
print(seperator)
for key in keys.fetchall():
print(key[0])
print(seperator)
elif choice == "2":
phrase = raw_input("Enter your secret phrase: ")
key, set_string = create_key(phrase, cursor)
encoded = encode_cipher(set_string, key)
print(seperator)
print("encoded message: '{}'".format(encoded))
print(seperator)
elif choice == "3":
encoded_cipher = raw_input("enter and encoded cipher: ")
encode_key = raw_input("enter the cipher key: ")
decoded = decode_cipher(encoded_cipher, encode_key)
print(seperator)
print("decoded message: '{}'".format(decoded))
print(seperator)
elif choice == "4":
print("database destroyed")
exited = True
except KeyboardInterrupt:
print("database has been destroyed")
if __name__ == "__main__":
main()