Caesar Cypher Python using RAD software - python

So currently I am working on a Caesar cypher app, my code looks like this (coded by RAD software https://anvil.works/)
The problem is that I don't get any output when I try to run the program and I think that it could be self.text_area_2 = cipher_encrypt(plain_text, key). I'm not sure if I'm using the correct statement to display the output correctly.
What statement should I use instead? Am I doing the right thing?
from ._anvil_designer import Form2Template
from anvil import *
class Form2(Form2Template):
def __init__(self, **properties):
# Set Form properties and Data Bindings.
self.init_components(**properties)
def button_1_click(self, **event_args):
def cipher_encrypt(plain_text, key):
plain_text = self.text_area_1.text
key = self.text_box_1.text
encrypted = ""
for c in plain_text:
if c.isupper(): #check if it's an uppercase character
c_index = ord(c) - ord('A')
# shift the current character by key positions
c_shifted = (c_index + key) % 26 + ord('A')
c_new = chr(c_shifted)
encrypted += c_new
elif c.islower(): #check if its a lowecase character
# subtract the unicode of 'a' to get index in [0-25) range
c_index = ord(c) - ord('a')
c_shifted = (c_index + key) % 26 + ord('a')
c_new = chr(c_shifted)
encrypted += c_new
elif c.isdigit():
# if it's a number,shift its actual value
c_new = (int(c) + key) % 10
encrypted += str(c_new)
else:
# if its neither alphabetical nor a number, just leave it like that
encrypted += c
return encrypted
self.text_area_2 = cipher_encrypt(plain_text, key)

Related

How to avoid backspace/delete/null when print cipher text?

I am testing a substitution cipher. I'm using the 256 standard ASCII. Here's my code:
def Encrypt(psw, key):
res = ""
for i in psw:
new_letter = chr((ord(i)+key)%255)
if new_letter == '\n':
new_letter = '。'
res += new_letter
return res
def Decrypt(psw, key):
res = ""
for i in psw:
if i == '。':
i = '\n'
old_letter = chr((ord(i)-key)%255)
res += old_letter
return res
if __name__ == "__main__":
try:
while True:
i = input("1 for encryption, 2 for decryption")
s = "";k = 0
if i == '1':
s = input("Input Plaintext:")
k = (int)(input("Input Key:"))
print("Ciphertext is:"+Encrypt(s, k))
elif i == '2':
s = input("Input Ciphertext:")
k = (int)(input("Input Key:"))
print("Plaintext is:"+Decrypt(s, k))
else:
break
except:
print("Error")
When I test some keys, such as 6012, the ciphertext is ãøôøø³ø³ûº³ú
I used this result to restore the plaintext, but failed, and it became Peasee me wh's wrong
I think this is due to special operators such as Delete, Backspace, and Null in the encryption process. It caused me to be unable to recover. Is there any way to solve this problem?
Most of the time, you should not print binary data (ciphertext) in a human-text channel (stdout) because it will interpret the non-printable data instead of displaying it.
If what you want is just to be able to copy-paste, you should escape the non-printable bits. One simple way to do it is to use urllib.parse.quote and unquote :
import urllib.parse
[...]
print("Ciphertext is: "+urllib.parse.quote(Encrypt(s, k)))
[...]
s = urllib.parse.unquote(input("Input Ciphertext:"))
Example :
1 for encryption, 2 for decryption
1
Input Plaintext:hello
Input Key:6012
Ciphertext is:%C3%BB%C3%B8%00%00%03
1 for encryption, 2 for decryption
2
Input Ciphertext:%C3%BB%C3%B8%00%00%03
Input Key:6012
Plaintext is:hello

Why does this code print the constructor?

class CipherTest:
def __init__(self):
self.shift = 0
self.direction = 'r'
self.text = "Testing"
# Shift to right function
def shift_to_right(self, text, shift):
encrypted_text = ""
for i in range(len(self.text)):
c = self.text[i]
# Encrypt upper case
if (c == ' '):
encrypted_text += ' '
elif (c.isupper()):
encrypted_text += chr((ord(c) + self.shift - 65) % 26 + 65)
# Encrypt lower case
else:
encrypted_text += chr((ord(c) + self.shift - 97) % 26 + 97)
return encrypted_text
# Shift to left function
def shift_to_left(self, text, shift):
encrypted_text = ""
for i in range(len(self.text)):
c = self.text[i]
# Encrypt upper case
if (c == ' '):
encrypted_text += ' '
elif (c.isupper()):
encrypted_text += chr((ord(c) - self.shift - 65) % 26 + 65)
# Encrypt lower case
else:
encrypted_text += chr((ord(c) - self.shift - 97) % 26 + 97)
return encrypted_text
if __name__ == "__main__":
user_text = str(input())
user_shift = int(input())
user_direction = str(input().lower()) # user inputs
Cipher_Message = CipherTest() # create an instance of the class
if user_direction == 'l': # picking left or right
print(CipherTest.shift_to_left(Cipher_Message, user_text, user_shift))
if user_direction == 'r':
print(CipherTest.shift_to_right(Cipher_Message, user_text, user_shift))
Am I calling the functions within my class incorrectly? Currently no matter the input, it prints "Testing". I'm new to classes but I believe that in the last couple lines, I am calling the new instance, telling it which method to perform, then feeding it the variables it needs to successfully run. From there it should be printing the 'encrypted_text' that is returned using my methods.
The issue is that CipherTest have attributes direction, shift and text but you also have local variables that you pass as parameter which you don't use
So your method keep using Testing and 0, that returns Testing so
The easiest, is to remove the attributs, so the class instance can do both direction, and in fact the method can be static (meaning no instance needed, only the class)
class CipherTest:
#staticmethod
def shift_to_right(text, shift):
encrypted_text = ""
for c in text:
if c == ' ':
encrypted_text += ' '
elif c.isupper():
encrypted_text += chr((ord(c) + shift - 65) % 26 + 65)
else:
encrypted_text += chr((ord(c) + shift - 97) % 26 + 97)
return encrypted_text
if __name__ == "__main__":
user_text = "hey how are you"
user_shift = 2
user_direction = "l"
if user_direction == 'l':
enc = CipherTest.shift_to_left(user_text, user_shift)
print(enc) # encrypted
print(CipherTest.shift_to_right(enc, user_shift)) # back to plain
elif user_direction == 'r':
enc = CipherTest.shift_to_right(user_text, user_shift)
print(enc) # encrypted
print(CipherTest.shift_to_left(enc, user_shift)) # back to plain
Another example, so you understand better, is to put the shift as class attribut, in order to use ise, we need to save in the class with self.shift = shift then we can use one cipher instance, with it's shift, to do both operation (also see how we really call a instance method)
class CipherTest:
def __init__(self, shift: int):
self.shift = shift
def shift_to_right(self, text):
encrypted_text = ""
for c in text:
if c == ' ':
encrypted_text += ' '
elif c.isupper():
encrypted_text += chr((ord(c) + self.shift - 65) % 26 + 65)
else:
encrypted_text += chr((ord(c) + self.shift - 97) % 26 + 97)
return encrypted_text
if __name__ == "__main__":
user_text = "hey how are you"
user_shift = 2
user_direction = "l"
cipher = CipherTest(user_shift)
if user_direction == 'l':
enc = cipher.shift_to_left(user_text)
print(enc) # encrypted
print(cipher.shift_to_right(enc)) # back to plain
elif user_direction == 'r':
enc = cipher.shift_to_right(user_text)
print(enc) # encrypted
print(cipher.shift_to_left(enc)) # back to plain
You're passing the class in as a parameter to your function.
CipherTest.shift_to_left(Cipher_Message, user_text, user_shift)
When you define a class method in python, you include self as a parameter but don't actually pass it when calling the function. It's interpreting Cipher_Message (the instance) as what you intended to put in as user_text.
Fix this by simply removing Cipher_Message from your parameters:
CipherTest.shift_to_left(user_text, user_shift)
You're not done yet. You're attempting to call a non-static method on the Class, instead of the instance. This means you're telling the 'blueprint' to shift your encryption as opposed to your actual test class. Fix this by changing the class to the instance:
Cipher_Message.shift_to_left(user_text, user_shift)
A nonbreaking bug you also have is that your functions seem to be taking parameters that you aren't using.
def shift_to_right(self, text, shift): takes two parameters - text & shift, yet you use the class's fields instead of those.
Simply removing them from the definitions and calls will remedy this.
def shift_to_right(self):
.shift_to_right()
Within your class methods, you are accepting parameters of text and shift, but the code of the methods never references those parameters.
The methods only reference the instance variables self.text and self.shift, which are attributes of the instance Cipher_Message, assigned during the execution of __init__ when the new instance was created
Two options:
Update the methods to use the parameters instead of the instance attributes.
Update __init__ to take text and shift as parameters, and assign the instance attributes based on the parameters that were passed in.
Ignoring how the user input is handled, this can be greatly simplified.
class CipherTest:
#staticmethod
def shift_to_left(text, shift):
return CipherTest.shift(text, -shift)
#staticmethod
def shift_to_right(text, shift):
return CipherTest.shift(text, shift)
#staticmethod
def shift(text, shift):
result = ''
for c in text:
if c.isupper():
c = chr((ord(c) + shift - 65) % 26 + 65)
elif c.islower():
c = chr((ord(c) + shift - 97) % 26 + 97)
# note that whitespace is neither upper nor lower so just append unchanged
result += c
return result
print(CipherTest.shift_to_left(CipherTest.shift_to_right('Hello world', 3), 3))
...which keeps the interface similar. Alternatively:
print(CipherTest.shift(CipherTest.shift('Hello world', 3), -3))
Output:
Hello world

Make Vigenere Decipher case-insensitive in Python

I am currently working on a school project where I need to build a decrypter for the Vigenere Cipher. The deciphering is working out just fine, but I have a problem which is that every letter is lowercase. I know the reason for this is that my used the casefold() method for my initial string. I did it so I can compare it to the alphabet a-z. Now here is my question: How can I modify the code in so that it will return the corresponding letter in uppercase?
def decipher(key):
original = "Rpoe, Xknf cne Rosvuhcl"
string = original
Alphabet ="abcdefghijklmnopqrstuvwxyz"
dec_message = ""
key = key.lower()
string = string.casefold()
textlength = len(string)
exp_key = key
exp_key_length = len(exp_key)
while exp_key_length < textlength:
exp_key = exp_key + key
exp_key_length = len(exp_key)
key_position = 0
for letter in string:
if letter in Alphabet:
position = Alphabet.find(letter)
key_char = exp_key[key_position]
key_char_position = Alphabet.find(key_char)
key_position += 1
new_position = position - key_char_position
if new_position > 26:
new_position = new_position + 26
new_character = Alphabet[new_position]
dec_message = dec_message + new_character
else:
dec_message = dec_message + letter
print(dec_message)
print(original)
return(dec_message)
decipher("ABC")
I tried to use a for loop so I can look at each letter in the encrypted string and then .upper the letter at the corresponding position in the dec_message string, however, that didn´t work.
The encrypted text is: Rome, Wine and Portugal

Encoding a password with special characters

I am in an into to Programming class and the assignment is in part to shift the letters of a valid password by +1 if it is a letter or number and -1 if it is a !##$ special character. I have most of it working with my below code but I always get the wrong output for the special characters. If I use to the code of anything high like 128 then I get the wrong symbol.
I am using the code from an encryption program from the other week and slowly changing things but I feel like this is too involved for something simple
If I enter the password UMA#augusta2020 I need to get the output VNB?bvhvtub3131 but I either end up with a space, b, or wrong symbol when I change the code input between 26,64,96,128, etc.
I have updated the code to fix small errors
def main():
print("This program validates and encrypts a password")
print()
main()
# The Encryption Function
def cipher_encrypt(plain_text):
encrypted = ""
for c in plain_text:
if c.isupper(): #check if it's an uppercase character
c_index = ord(c) - ord('A')
# shift the current character by key positions
c_shifted = (c_index + 1) % 26 + ord('A')
c_new = chr(c_shifted)
encrypted += c_new
elif c.islower(): #check if its a lowecase character
c_index = ord(c) - ord('a')
c_shifted = (c_index + 1) % 26 + ord('a')
c_new = chr(c_shifted)
encrypted += c_new
elif c.isdigit():
# if it's a number,shift its value
c_new = (int(c) + 1) % 10
encrypted += str(c_new)
else:
# if its neither alphabetical nor a number, -1
c_shifted = (c_index - 1) % 128 + ord('a')
c_new = chr(c_shifted)
encrypted += c_new
return encrypted
plain_text =input("Enter your Password: ")
print()
ciphertext = cipher_encrypt(plain_text)
print()
print("Your Password: ", plain_text)
print()
print("Your password is valid and encrypted it is: ", ciphertext)
print()
Here is a much cleaner approach:
def cipher_encrypt(plain_text):
alpha = 'abcdefghijklmnopqrstuvwxyz'
digits = '0123456789'
puncs = '!"#$%&\'()*+,-./:;<=>?#[\\]^_`{|}~'
encrypted_text = ''
for c in plain_text:
if c.lower() in alpha:
c_index = alpha.index(c.lower())
e_index = (c_index + 1)%len(alpha)
if c == c.lower():
encrypted_text += alpha[e_index]
else:
encrypted_text += alpha[e_index].upper()
elif c in digits:
c_index = digits.index(c)
e_index = (c_index + 1)%len(digits)
encrypted_text += digits[e_index]
else:
c_index = puncs.index(c)
e_index = (c_index +len(puncs) - 1)%len(puncs)
encrypted_text += puncs[e_index]
return encrypted_text
In this approach I deal with each caharcter in plain text by:
Determining idf the char is part of alpha by making use of the c.lower() function to isolate alpha chars and then find an index modulo the len of alpha. Then I determine if I need an uppercase char or lower case in the encrypted text.
I use the same modulo approach for digits, but don't have to worry about upper and lower, finally
I find the index for the punctuations found in the plain_text

Python Vigenere Cipher Encrypt method not encrypting properly

The encrypt method in my program is not encrypting correctly. I thought I figured out why using debug mode; it's because it reads the spaces between words as something it has to encrypt. So I tried typing a message without spaces but it still didn't come out correctly.
I figure the issue is the if statement with the key. I tried commenting lines out, changing statements, changing the if statement to a for loop, but it still isn't correct.
def main():
vig_square = create_vig_square()
message = input("Enter a multi-word message with punctuation: ")
input_key = input("Enter a single word key with no punctuation: ")
msg = message.lower()
key = input_key.lower()
coded_msg = encrypt(msg, key, vig_square)
print("The encoded message is: ",coded_msg)
print("The decoded message is: ", msg)
def encrypt(msg,key,vig_square):
coded_msg = ""
key_inc = 0
for i in range(len(msg)):
msg_char = msg[i]
if key_inc == len(key)-1:
key_inc = 0
key_char = key[key_inc]
if msg_char.isalpha() and key_char.isalpha():
row_index = get_row_index(key_char,vig_square)
col_index = get_col_index(msg_char,vig_square)
coded_msg = coded_msg+vig_square[row_index][col_index]
else:
coded_msg = coded_msg + " "
key_inc = key_inc+1
return coded_msg
def get_col_index(msg_char, vig_square):
column_index = ord(msg_char) - 97
return column_index
def get_row_index(key_char, vig_square):
row_index = ord(key_char) - 97
return row_index
def create_vig_square():
vig_square = list()
for row in range(26):
next_row = list()
chr_code = ord('a') + row
for col in range(26):
letter = chr(chr_code)
next_row.append(letter)
chr_code = chr_code + 1
if chr_code > 122:
chr_code = ord('a')
vig_square.append(next_row)
return vig_square
main()
This example was given to us:
Enter a multi-word message with punctuation: The eagle has landed.
Enter a single word key with no punctuation: LINKED
The encoded message is: epr oejwm ukw olvqoh.
The decoded message is: the eagle has landed.
But my encoded message comes out as:
epr iloyo sif plvqoh
You have two errors:
First, you don't use all characters in the key. Change the following line:
if key_inc == len(key)-1:
key_inc = 0
to
if key_inc == len(key):
key_inc = 0
Second, you move the key pointer even if you process a non-alpha character in the message (e.g. spaces). Do it only if you encode a character, i.e. make the following change:
if msg_char.isalpha() and key_char.isalpha():
...
key_inc = key_inc+1 # Move this line here
else:
...

Categories