So im writing a caeser cipher in python, and i have a brute force option to see if it can decode a word with a random offset. For some reason i get the error:
Traceback (most recent call last):
File "C:\Users\nameredacted\Desktop\Python\CipherV2.py", line 60, in <module>
print(getTranslatedMessage(mode, message, key))
File "C:\Users\nameredacted\Desktop\Python\CipherV2.py", line 47, in getTranslatedMessage
ciphertext += alpha2[ (alpha1[i] + brutekey)]
KeyError: 26
my code is :
from PyDictionary import PyDictionary
import enchant
MAX_KEY_SIZE = 26
dictionary = PyDictionary()
d = enchant.Dict("en_US")
alpha1 = dict(zip("ABCDEFGHIJKLMNOPQRSTUVWXYZ",range(26)))
alpha2 = dict(zip(range(26),"ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
#gets if the user wants to encrypt or decrypt
def getMode():
while True:
print('Do you wish to encrypt, decrypt or brute force a message')
mode = input().lower()
if mode in 'encrypt e decrypt d bruteforce bf'.split():
return mode
else:
print('Enter either "encrypt" or "e" or "decrypt" or "d" or "bruteforce" or "bf".')
#gets offset value if needed
def getKey(mode):
key = 0
if mode[0]=='b':
pass
else:
while True:
key = int(input('Enter the offset number (1-%s)' % (MAX_KEY_SIZE)))
if (key >= 1 and key <= MAX_KEY_SIZE):
return key
#translates the message
def getTranslatedMessage(mode, message, key):
ciphertext=''
if mode[0] == 'd':
key = -key
for c in message.upper():
if c.isalpha():
ciphertext += alpha2[ (alpha1[c] + key)]
else: ciphertext += c
elif mode[0] =='e':
for x in message.upper():
if x.isalpha():
ciphertext += alpha2[ (alpha1[x] + key) ]
else:
ciphertext += x
else:
while True:
for i in message.upper():
for brutekey in range (26):
ciphertext += alpha2[ (alpha1[i] + brutekey)]
print(ciphertext)
if d.check(ciphertext):
break
return ciphertext
mode = getMode()
message = input("please input your message")
key = getKey(mode)
print('Your translated text is:')
print(getTranslatedMessage(mode, message, key))
Thanks for reading, also id appreciate if you could comment on any improvements you could see to make.
As mentioned in the comment by #TemporalWolf, alpha1[i] + brutekey will be greater than 25 at some point. Suppose the message is "XYZ" and the broutekey, which starts from 0, would be 2. Then alpha1["X"] + brutekey = 25, which is ok. But alpha2[ alpha1["Y"] + brutekey ] will raise a KeyError. To fix this you could use the modulo operator. It allows you to calculate like one does with analog clocks: 8 + 6 = 2 (mod 12). In python the modulo operator is represented by a %. Your code would be:
else:
while True:
for i in message.upper():
for brutekey in range (26):
ciphertext += alpha2[ (alpha1[i] + brutekey) % 26]
print(ciphertext)
Also I think you want to change the order of those two for-loops. This way you fix a letter of the message and run through each brutekey for that letter. That is just the alphabet.
else:
for brutekey in range (26):
for i in message.upper():
ciphertext += alpha2[ (alpha1[i] + brutekey) % 26]
print(ciphertext)
if d.check(ciphertext):
break
So i consildated all of your guys' help and kinda reworked the program. It is slightly messy but it works. Code:
from PyDictionary import PyDictionary
import enchant
MAX_KEY_SIZE = 26
Go='Yes'
dictionary = PyDictionary()
d = enchant.Dict("en_US")
alpha1 = dict(zip("ABCDEFGHIJKLMNOPQRSTUVWXYZ",range(26)))
alpha2 = dict(zip(range(26),"ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
#gets if the user wants to encrypt or decrypt
def getMode():
while True:
print('Do you wish to encrypt, decrypt or brute force a message')
mode = input().lower()
if mode in 'encrypt e decrypt d bruteforce bf'.split():
return mode
else:
print('Enter either "encrypt" or "e" or "decrypt" or "d" or "bruteforce" or "bf".')
#gets offset value
def getKey(mode):
key = 0
if mode[0]=='b':
pass
else:
while True:
key = int(input('Enter the offset number (1-%s)' % (MAX_KEY_SIZE)))
if (key >= 1 and key <= MAX_KEY_SIZE):
return key
#translates the message
def getTranslatedMessage(mode, message, key):
ciphertext=''
if mode[0] == 'd':
key = -key
for c in message.upper():
if c.isalpha():
ciphertext += alpha2[ (alpha1[c] + key)]
else: ciphertext += c
elif mode[0] =='e':
for x in message.upper():
if x.isalpha():
ciphertext += alpha2[ (alpha1[x] + key)% (MAX_KEY_SIZE) ]
else:
ciphertext += x
else:
brutekey=0
while True:
for i in message.upper():
ciphertext += alpha2[ (alpha1[i] + brutekey)% (MAX_KEY_SIZE)]
print(ciphertext)
if d.check(ciphertext):
break
else:
ciphertext=''
brutekey=brutekey+1
return ciphertext
while Go=='yes' or 'Yes' or 'YES' or 'YEs' or 'yeS' :
mode = getMode()
message = input("please input your message")
key = getKey(mode)
print('Your translated text is:')
print(getTranslatedMessage(mode, message, key))
Go=input('Would you like to use the cipher again?')
if Go in 'yes Yes YES YEs yeS':
pass
else:
print("thank you for using the program")
break
Related
I'm having an issue with Vigenere Cipher Decryption, When an encrypted message is decrypted, the decrypted message is not printed, but the encrypted is?
I cant seem to see why this dose not work. But its probably a simple issue.
I think the issue is in the main decrypt function.
Help would be much appreciated
Encryption works fine
def encrypt_key(message, key):
i = 0
empty_key = '' # empty key to append to
# turn characters into index
for characters in message:
if characters.isalpha(): # checks if character is in the alphabet
empty_key = empty_key + key[i % len(key)] # append characters to empty key
i = i + 1 # increase integer value by 1
else:
empty_key = empty_key + ' ' # if character is a space or punctuation then add empty space
return empty_key
def encrypt_decrypt(message_char, key_char, choice='encrypt'):
if message_char.isalpha():
first_alphabet_letter = 'a' # assume character is lowercase
if message_char.isupper():
first_alphabet_letter = 'A' # assume character is upper, then replace with A
original_char_position = ord(message_char) - ord(first_alphabet_letter) # difference results in position of char in alphabet
key_char_position = ord(key_char.lower()) - ord('a')
if choice == 'encrypt':
new_char_position = (original_char_position + key_char_position) % 26 # encrypts & loops back around with % 26
else: # if choice == 'decrypt':
new_char_position = (original_char_position - key_char_position + 26) % 26 # decrypts & loops back around
return chr(new_char_position + ord(first_alphabet_letter))
return message_char
def encrypt(message, key):
cipher = ''
empty_key = encrypt_key(message, key)
for message_char, key_char in zip(message, empty_key):
cipher = cipher + encrypt_decrypt(message_char, key_char)
return cipher
def decrypt(cipher, key):
message = ''
empty_key = encrypt_key(cipher, key)
for cipher_char, key_char in zip(cipher, empty_key):
message = message + encrypt_decrypt(cipher_char, key_char, 'decrypt')
return message
message = input('Enter your message to encrypt here: ')
key = input('Enter your key: ')
cipher = encrypt(message, key) # inputs message and key to encrypt function
decrypt_message = decrypt(cipher, key)# inputs message and key to decrypt function
print(f'Cipher: {cipher}')
print(f'Decrypted: {decrypt_message}')
def choice():
user_choice = int(input('''
Enter your choice (1 or 2):
1. Encrypt
2. Decrypt
> '''))
if user_choice == 1:
print(f'Cipher: {cipher}')
print('')
elif user_choice == 2:
print('')
print(f'Decrypted: {decrypt_message}')
choice()
I have it set to ask the user a word to encrpyt which works fine using my own alphabet.
My issue is trying to also get it to return the deciphered text.
So far I have it either returning the encrypted message twice or sending back a different version of the encrypted message.
I have tried using - instead of + in my for char, and it gives me a error which I thought was the correct way to do it.
alphabet = "abcdefghijklmnopqrstuvwxyz"
key = "zjrekydnqoluaxmicvpgtfbhws"
def decryptMessage(ciphertext, key):
plaintext = ""
for char in ciphertext:
if alphabet.find(char) < +1:
plaintext += key[alphabet.find(char)]
else:
plaintext += char
return plaintext
def encryptMessage(plaintext, key):
ciphertext = ""
for char in plaintext:
if alphabet.find(char) > -1:
ciphertext += key[alphabet.find(char)]
else:
ciphertext += char
return ciphertext
message = input("Type a message to encrypt: ")
encrypted = encryptMessage(message, key)
decrypted = decryptMessage(encrypted, key)
print("Plaintext message: " + message)
print("Encrypted message: " + encrypted)
print("Decrypted message: " + decrypted)
you should use the builtin str.translate
message = "hello world"
alphabet = b"abcdefghijklmnopqrstuvwxyz"
key = b"zjrekydnqoluaxmicvpgtfbhws"
encrypted = message.translate(dict(zip(alphabet,key)))
print("E:",encrypted)
decrypted = encrypted.translate(dict(zip(key,alphabet)))
print("D:",decrypted)
If you want to keep with the theme of your original code:
You need to modify as follows:
alphabet = "abcdefghijklmnopqrstuvwxyz"
key = "zjrekydnqoluaxmicvpgtfbhws"
def decryptMessage(ciphertext, key):
plaintext = ""
for char in ciphertext:
if key.find(char) > -1:
plaintext += alphabet[key.find(char)]
else:
plaintext += char
return plaintext
def encryptMessage(plaintext, key):
ciphertext = ""
for char in plaintext:
if alphabet.find(char) > -1:
ciphertext += key[alphabet.find(char)]
else:
ciphertext += char
return ciphertext
message = input("Type a message to encrypt: ")
encrypted = encryptMessage(message, key)
decrypted = decryptMessage(encrypted, key)
print("Plaintext message: " + message)
print("Encrypted message: " + encrypted)
print("Decrypted message: " + decrypted)
So, I had 2 scripts, a Vigenere cipher and a Caesar cipher, however, when I decided to merge them into a "mainproject" file by using "import" to import the script after the wanted answer from the user is sent on the Terminal page, when I've done the code and decided to execute the mainproject, I've got the question whether to choose to use Vigenere or Caesar, once I typed caesar (1) it played the first 2-4 lines and stopped the code once I've encountered the "def" line on both of scripts, if thats the problem, I can't use imports with "def", how can I merge them both into one file that asks which script I would like to use?
Caesar:
import time
import sys
print("Welcome to Caesar Cipher")
time.sleep(3)
print("Choose the corresponding number to Encrypt or Decrypt in Caesar Cipher")
def encryption():
print("Encryption")
print("You have chose ENCRYPTION")
msg = input("Enter message: ")
key = int(input("Enter key(0-25): "))
encrypted_text = ""
for i in range(len(msg)):
if ord(msg[i]) == 32:
encrypted_text += chr(ord(msg[i]))
elif ord(msg[i]) + key > 122:
temp = (ord(msg[i]) + key) - 122
encrypted_text += chr(96+temp)
elif (ord(msg[i]) + key > 90) and (ord(msg[i]) <= 96):
temp = (ord(msg[i]) + key) - 90
encrypted_text += chr(64+temp)
else:
encrypted_text += chr(ord(msg[i]) + key)
print("Your Encrypted Message: " + encrypted_text)
def decryption():
print("Decryption")
print("You have chose DECRYPTION")
encrp_msg = input("Enter encrypted Text: ")
decrp_key = int(input("Enter key(0-25): "))
decrypted_text = ""
for i in range(len(encrp_msg)):
if ord(encrp_msg[i]) == 32:
decrypted_text += chr(ord(encrp_msg[i]))
elif ((ord(encrp_msg[i]) - decrp_key) < 97) and ((ord(encrp_msg[i]) - decrp_key) > 90):
temp = (ord(encrp_msg[i]) - decrp_key) + 26
decrypted_text += chr(temp)
elif (ord(encrp_msg[i]) - decrp_key) < 65:
temp = (ord(encrp_msg[i]) - decrp_key) + 26
decrypted_text += chr(temp)
else:
decrypted_text += chr(ord(encrp_msg[i]) - decrp_key)
print("Text has been Decrypted: " + decrypted_text)
choice = int(input("1. Encryption\n2. Decryption\nChoose(1,2): "))
if choice == 1:
encryption()
elif choice == 2:
decryption()
else:
print("Wrong Choice")
Vigenere:
import time
print("Welcome to Vigenere Cipher")
time.sleep(2)
print("Choose the corresponding number to Encrypt or Decrypt in Vigenere Cipher")
time.sleep(2.5)
def msg_and_key():
msg = input("Enter message: ").upper()
key = input("Enter key: ").upper()
key_map = ""
j=0
for i in range(len(msg)):
if ord(msg[i]) == 32:
key_map += " "
else:
if j < len(key):
key_map += key[j]
j += 1
else:
j = 0
key_map += key[j]
j += 1
return msg, key_map
def create_vigenere_table():
table = []
for i in range(26):
table.append([])
for row in range(26):
for column in range(26):
if (row + 65) + column > 90:
table[row].append(chr((row+65) + column - 26))
else:
table[row].append(chr((row+65)+column))
return table
def cipher_encryption(message, mapped_key):
table = create_vigenere_table()
encrypted_text = ""
for i in range(len(message)):
if message[i] == chr(32):
encrypted_text += " "
else:
row = ord(message[i])-65
column = ord(mapped_key[i]) - 65
encrypted_text += table[row][column]
print("Encrypted Message: {}".format(encrypted_text))
def itr_count(mapped_key, message):
counter = 0
result = ""
for i in range(26):
if mapped_key + i > 90:
result += chr(mapped_key+(i-26))
else:
result += chr(mapped_key+i)
for i in range(len(result)):
if result[i] == chr(message):
break
else:
counter += 1
return counter
def cipher_decryption(message, mapped_key):
table = create_vigenere_table()
decrypted_text = ""
for i in range(len(message)):
if message[i] == chr(32):
decrypted_text += " "
else:
decrypted_text += chr(65 + itr_count(ord(mapped_key[i]), ord(message[i])))
print("Decrypted Message: {}".format(decrypted_text))
print("Key and Message can only be alphabetic")
time.sleep(1.5)
choice = int(input("1. Encryption\n2. Decryption\nChoose(1,2): "))
if choice == 1:
print("You have chose ENCRYPTION")
message, mapped_key = msg_and_key()
cipher_encryption(message, mapped_key)
elif choice == 2:
print("You have chose DECRYPTION")
message, mapped_key = msg_and_key()
cipher_decryption(message, mapped_key)
else:
print("Wrong choice")
Any help would be appreciated!
def only defines a function. To actually execute it you need to call it.
It seems the following part should be outside of decryption function body i.e. indented to the left. It:
call be executed directly on the module level
can be a separate function e.g. main that you can call
As main:
def main():
choice = int(input("1. Encryption\n2. Decryption\nChoose(1,2): "))
if choice == 1:
encryption()
elif choice == 2:
decryption()
else:
print("Wrong Choice")
And now you can call the main function:
main()
Welcome to Stackoverflow. This answer ended up more as general advice than a specific point solution to your problem, but I hope it's helpful.
One obvious remark is that it would be nice not to have to import the code for the cypher you don't intend to use.
Imports are executable statements, so this is quite practical.
Your code is far from optimally organised. Much of the code on the two files is the same or very similar. This is not unusual for new programmers, as it takes a while to learn how to break problems down and extract the common elements. The real problem is that while it defines lots of functions, none of them actually get called (unless there's more code you haven't included).
I would recommend that you modify your code so that there's a top-level program that collects the key and data and performs the required operations, along with your two
encryption/decryption modules. The encryption and decryption routines shouldn't do any input or output at all, just deal with the data.
Let's assume you have a variable mtype that holds the type of encryption you want to use. The top-level logic could look something like this:
if mtype == "caesar":
from caesar import encrypt, decrypt
elif mtype == "vigniere":
from vigniere import encrypt, decrypt
else:
sys.exit("Unrecognised message type")
If this code succeeds you would then have an encrypt and a decrypt function from the correct module. This means that they have to have the same interface, since your logic must now be written to accommodate either.
The remainder of your logic would look something like this (untested):
operation = input("E(ncrypt) or D(ecrypt)? ")
if operation.upper().startswith("E"):
function = encrypt
elif operation.upper().startswith("D"):
function = decrypt
else:
sys.exit("Unknown operation")
message = input(...)
key = input(...)
output = function(message, key)
This will hopefully make your code clearer by separating out the I/O responsibility
from the encryption and decryption tasks.
I would greatly appreciate your feedback on my first ever Python project! :D
Basically I am coding a Caesar Cipher and I think its pretty terribly 'optimised / efficient' if you know what I mean, this is because I copied and pasted the encrypt() method for the decrypt() method and the only thing I changes was instead of rotating the numbers more, I rotated them less. This is what I'm talking about:
newPosition = (abc.find(letter) - key) % 26
^^ Instead of having a + (plus) I made it a - (minus) ^^
Is there a way I can sort of call the encrypt() method at just the newPosition line? Or what I did was correct and it doesn't need fixing (which I highly doubt)
** Please do take in mind that I do not have much knowledge in Python (if any at all) since I just started today so don't blow my brain up with some super complex code. THANK YOU!!! **
abc = 'abcdefghijklmnopqrstuvwxyz'
def main():
message = input("Would you like to encrypt or decrypt a word?")
if message.lower() == "encrypt":
encrypt()
elif message.lower() == "decrypt":
decrypt()
else:
print("You must enter either 'encrypt' or 'decrypt'.")
main()
def encrypt():
message = input("Enter a message to encrypt: ")
message = message.lower()
key = int(input("What number would you like for your key value?"))
cipherText = ""
for letter in message:
if letter in abc:
newPosition = (abc.find(letter) + key) % 26
cipherText += abc[newPosition]
else:
cipherText += letter
print(cipherText)
return cipherText
def decrypt():
message = input("Enter a message to decrypt: ")
message = message.lower()
key = int(input("What number would you like for your key value?"))
cipherText = ""
for letter in message:
if letter in abc:
newPosition = (abc.find(letter) - key) % 26
cipherText += abc[newPosition]
else:
cipherText += letter
print(cipherText)
return cipherText
main()
In general, str.find is bad performance-wise. It's O(n) complexity, which isn't awful, but you rarely actually need it. In this case you can use ord to convert each letter to its ordinal, then subtract ord('a') to get 0-25 instead of 97-122.
This is particularly useful, because you can then use chr to convert back without needing a lookup.
for letter in message:
if letter in string.ascii_lowercase: # same as "abcdef..z"
new_position = ((ord(letter) - ord('a') + key) % 26) + ord('a')
new_ch = chr(new_position)
ciphertext += new_ch
Note also that concatenating strings with += isn't as fast as something like str.join.
new_letters = [chr(((ord(letter) - ord('a') + key) % 26) + ord('a')) if letter in ascii_lowercase else letter for letter in message]
ciphertext = "".join(new_letters)
And since that chr(((ord(letter) - ord('a') + key) % 26) + ord('a')) is so ugly, I'd refactor that into a function.
def rotate(letter, key=0):
c_pos = ord(letter) - ord('a')
rotated = c_pos + key
modded = rotated % 26
final_pos = modded + ord('a')
return chr(final_pos)
new_letters = [rotate(c, key) if c in string.ascii_lowercase else c for c in letters]
ciphertext = "".join(new_letters)
A point of maintainability: it's easier to write testably good code if you separate your inputs from your results. Right now you'd have to do some monkey patching of stdin to write unit tests for any of your functions, but if you move your requests for user input into main and out of their respective function, that gets much easier.
def main():
message = input("What's the message to encrypt/decrypt? ")
key = int(input("What number would you like for your key value? "))
choice = input("Choose: encrypt or decrypt. ")
if choice == "encrypt":
result = encrypt(message, key)
elif choice == "decrypt":
result = decrypt(message, key)
else:
# something here about a bad user input.
In fact, when you consider the Caesar Cipher is reversible by flipping the sign of the key, you can simply do:
if choice == "encrypt":
result = encrypt(message, key)
elif choice == "decrypt":
result = encrypt(message, key * (-1))
and not write a decrypt function at all!
I have been creating a cipher and I have been getting an error message:
TypeError: 'str' object is not callable
my code currently is:
alphabet = "abcdefghijklmnopqrstuvwxyz"
key = 5
cipher = ' '
choice = input('Do you wish to encrypt or decrypt? E/D')
if not choice == 'D' and not choice == 'E':
raise Exception('Must enter E or D for Encrypt or Decrypt')
user_input = input('Please enter your word')
cipher2 = cipher (user_input, alphabet, choice, key)
print('your encrypted mesaage 2 is: ' + cipher2)
#Method can encrypt or decrypt the entered word
def cipher(plain_text, alphabet, choice, key):
cipher = ''
for c in plain_text:
if c in alphabet:
if choice == 'E':
val1 = alphabet.index(c)
val2 = key
cipher += alphabet[ (val1 + val2) % (len(alphabet))]
elif choice == 'D':
cipher = cipher + alphabet[ (alphabet.index(c)-key) % (len(alphabet))]
return cipher
the error is on line nine :
cipher2 = cipher (user_input, alphabet, choice, key)
Appreciate the help if anyone can
Your string cipher(defiend in line 3) have same name as your function cipher :
print (type(cipher)) # class <'str'>
cipher2 = cipher (user_input, alphabet, choice, key) # cipher is string here not function
when you call this check cipher type it's string so change your string name or function name.