Using caesar cipher to decrypt ciphertext - python

I am attempting to decrypt the ciphertext "htrgti" to plaintext using this code. I keep getting "wigvix" which is not the message I should be getting.
Given the plain text (which should be a common word or phrase) and key, for every spot that said ciphertext I replaced it with plaintext, and the same for every spot that says plaintext:
def caesar(ciphertext, shift):
alphabet=["a","b","c","d","e","f","g","h","i",
"j","k","l","m","n","o","p","q","r",
"s","t","u","v","w","x","y","z"]
plaintext = ""
for i in range(len(ciphertext)):
letter = ciphertext[i]
# Find the number position of the ith letter
num_in_alphabet = alphabet.index(letter)
# Find the number position of the cipher by adding the shift
plain_num = (num_in_alphabet + shift) % len(alphabet)
# Find the plain letter for the cipher number you computed
plain_letter = alphabet[plain_num]
# Add the cipher letter to the plaintext
plaintext = plaintext + plain_letter
return plaintext

Your function works if you call it correctly, as hinted by #Mr.Llama, with the right shift caesar("htrgti", 11) is secret. Your function itself runs correctly. Here is a better version of your code, but it still has the problem that each .index lookup is O(alphalen). So, as a bonus, I added the implementation of the suggestion by #Two-Bit Alchemist to use str.translate.
import string
alphabet = string.ascii_lowercase
alphalen = len(alphabet)
shift = 11
def caesar(ciphertext, shift):
plaintext = ""
for letter in ciphertext:
num_in_alphabet = alphabet.index(letter)
plain_num = (num_in_alphabet + shift) % alphalen
plain_letter = alphabet[plain_num]
plaintext = plaintext + plain_letter
return plaintext
print(caesar("htrgti", shift))
# secret
table = str.maketrans(alphabet, alphabet[shift:] + alphabet[:shift])
print("htrgti".translate(table))
# secret

Related

How do I increase the position of a letter in a list by the position of letter?

I have a program that takes the position of a letter and increases the position by the value of the shift and then gives me the new position of the letters, it's a caesar list function. However i need to be able to increase the position of the letter by the value of shift and also by the position of the letter, so if i have "hello" and shift is 15, h = 7 so 7 +15 +0 = 22 and e would be 4+15+1(position of e) = 20
However, I'm not sure how to edit my code so that I can increase the position of each letter by the value of their position. The code works fine, I just need help figuring out this step.
alphabet =['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
def caesar(plaintext,shift):
# initialize ciphertext as blank string
ciphertext = ""
# loop through the length of the plaintext
for i in range(len(plaintext)):
# get the ith letter from the plaintext
letter = plaintext[i]
# find the number position of the ith letter
num_in_alphabet = alphabet.index(letter)
print (num_in_alphabet)
# find the number position of the cipher by adding the shift
cipher_num = (num_in_alphabet + shift + 3) % len(alphabet)
# find the cipher letter for the cipher number you computed
cipher_letter = alphabet[cipher_num]
# add the cipher letter to the ciphertext
ciphertext = ciphertext + cipher_letter
# return the computed ciphertext
return ciphertext
def main():
plaintext = ("hello")
shift = 16
text = caesar(plaintext,shift)
print (text)
main()
cipher_num = (num_in_alphabet + shift + i) % len(alphabet)
Or much simpler
shift = 16
chiper = ''.join([chr(((ord(c)-ord('a')+shift+i)%26)+ord('a')) for i, c in enumerate("hellow")])
assert chiper == 'xvdeir'

Implementing the Ceaser Cipher function through input in Python

Im trying to create a Ceaser Cipher function in Python that shifts letters based off the input you put in.
plainText = input("Secret message: ")
shift = int(input("Shift: "))
def caesar(plainText, shift):
cipherText = ""
for ch in plainText:
if ch.isalpha():
stayInAlphabet = ord(ch) + shift
if stayInAlphabet > ord('z'):
stayInAlphabet -= 26
finalLetter = chr(stayInAlphabet)
cipherText += finalLetter
print(cipherText)
return cipherText
caesar(plainText, shift)
For example, if I put "THE IDES OF MARCH" as my message and put 1 as my shift, it outputs "UIFJEFTPGNBSDI" when it is meant to output "UIF JEFT PG NBSDI." It doesn't keep the spaces and also shifts things like exclamation marks back also when it should leave them as is. Letters should also wrap meaning if I put shift as 3, an X should go back to A.
To fix the spacing issue, you can add an else to if ch.isalpha() and just append the plain text character to the cipher text. This will also handle punctuation and other special, non-alpha characters.
To handle wrapping (e.g. X to A), you'll want to use the modulo operator %. Because A is the 65th ASCII character and not the 0th, you'll need to zero-base the alpha characters, then apply the mod, then add back the offset of 'A'. To shift with wrap-around, you can do something like: final_letter = chr((ord(ch) + shift - ord('A')) % 26 + ord('A')). Note the 26 comes from number of letters in the Latin alphabet.
With these in mind, here is a full example:
plain_text = input("Secret message: ")
shift = int(input("Shift: "))
def caesar(plain_text, shift):
cipher_text = ""
for ch in plain_text:
if ch.isalpha():
final_letter = chr((ord(ch) + shift - ord('A')) % 26 + ord('A'))
cipher_text += final_letter
else:
cipher_text += ch
print(cipher_text)
return cipher_text
caesar(plain_text, shift)
Sample input:
plain_text = "THE IDES OF MARCH"
shift = 1
cipher_text = caesar(plain_text, shift)
print(cipher_text)
# UIF JEFT PG NBSDI
The reason the cipher does not produce the expected result is your code does not account for the case where it is not a alpha non numerical letter. So, a potential fix is just adding handling for spaces.
Code
plainText = input("Secret message: ")
shift = int(input("Shift: "))
def caesar(plainText, shift):
cipherText = ""
for ch in plainText:
if ch.isalpha():
stayInAlphabet = ord(ch) + shift
if stayInAlphabet > ord('z'):
stayInAlphabet -= 26
finalLetter = chr(stayInAlphabet)
cipherText += finalLetter
elif ch is " ":
cipherText += " "
print(cipherText)
return cipherText
caesar(plainText, shift)
Example
Secret message: THE IDES OF MARCH
Shift: 1
UIF JEFT PG NBSDI

Python Vigenere Cipher with required functions

I am working on an online course that has us creating a caesar cipher and vigenere cipher, but we first created two functions; one to find the position of a letter in an alphabet variable, and one to rotate one given character a given amount of times (I have seen that ord() and chr() work better, but the assignment wants us to focus on simpler concepts for now, I guess).
I was able to get the caesar function working, but am unsure as how to go forward with the vigenere cipher. I have watched many videos and looked around this site, but have not found any that allow for the preservation of spaces and non alphabetical characters. Can anyone point me in the right direction of how to start the vigenere function?
#Create function alphabet_position(letter) to turn letter into number
#such as a=0 or e=4, using lowercase to make sure case doesnt matter.
def alphabet_position(letter):
alphabet ="abcdefghijklmnopqrstuvwxyz" #Lists alphabet for a key
lower_letter = letter.lower() #Makes any input lowercase.
return alphabet.index(lower_letter) #Returns the position of input as a number.
def rotate_character(char, rot):
alphabet = "abcdefghijklmnopqrstuvwxyz"
if char.isalpha():
a = alphabet_position(char)
a = (a + rot) % 26 #needs modulo
a = (alphabet[a])
if char.isupper():
a = a.title()
return a
else:
return char
def encrypt(text, rot):
list1 = ""
for char in text:
list1 += rotate_character(char, rot)
return list1
def main():
x = input("Type a message: ")
y = input("Rotate by: ")
#result = rotate_character(x, y) #Not needed once encrypt function works.
result = encrypt(x, y)
print (result)
if __name__ == '__main__':
main()
following my comments; using all printables as alphabet:
from string import ascii_letters, digits, punctuation, whitespace
ALPHABET = ascii_letters + digits
STATIC_ALPHABET = punctuation + whitespace
# minor speedup
ALPHA_INDEX = {a: i for i, a in enumerate(ALPHABET)}
STATIC_ALPHABET_SET = set(STATIC_ALPHABET)
MOD = len(ALPHABET)
def encrypt(char, key):
if char in STATIC_ALPHABET_SET:
return char
else:
return ALPHABET[(ALPHA_INDEX[char] + key) % MOD]
def decrypt(char, key):
if char in STATIC_ALPHABET_SET:
return char
else:
return ALPHABET[(ALPHA_INDEX[char] + MOD - key) % MOD]
key = 17
plain = 'Hello World!'
enc = ''.join(encrypt(char, key) for char in plain)
print(enc) # YvCCF dFICu!
dec = ''.join(decrypt(char, key) for char in enc)
print(dec) # Hello World!

Work out the difference between letters python

been given an assignment and it's nearly finished. Just struggling with the last bit. The program is given a caesar cipher text, it then works out what the most frequent letter is and prints this back to the terminal. (Where I am up to.)
It will then suggest a key shift based on the most frequent letter and the user can then manually input this key shift, or their own key shift and the text is the deciphered.
I need the program to take the most frequent letter in the caesar text and compare this to the letter 'E' which is the most frequent letter in the english language and then work out how many key shifts it is away...
e.g. if the most common caesar text letter is n then n-e = 9.
Code so far:
import sys
def decrypt(plain, key):
"returns a Caesar cipher text given plain text and a key"
cipher = ""
for index in range(len(plain)):
if plain[index].isalpha():
if plain[index].islower():
cipher = cipher + chr((ord(plain[index]) -101- key+26) % 26+ 101)
else:
cipher = cipher + chr((ord(plain[index]) -65- key+26) % 26+ 65)
else:
cipher = cipher + plain[index]
return cipher #do nothing here
#main program
key = int(sys.argv[4])
action = sys.argv[2]
try:
in_file = open(sys.argv[1], "r")
except:
sys.exit("There was an error opening the file: {}".format(sys.argv[1]))
try:
out_file = open(sys.argv[3], "w")
except:
sys.exit("There was an error opening the file: {}".format(sys.argv[3]))
line = in_file.readline()
freq_dict = { }#letter : 0 for letter in LETTERS }
while len(line) != 0:
for letter in line.replace(" ",""):
if letter in freq_dict:
freq_dict[letter] += 1
else:
freq_dict[letter] = 1
line = in_file.readline()
cipher = decrypt(line, key)
out_file.write(cipher)
in_file.close()
out_file.close()
for letter in freq_dict:
print(letter, "times", freq_dict[letter])
Thanks in advance.
So it seems your decrypt function essentially generates an output that is the input text string shifted by the key right now.
From what I understand, what you then want to do is find the most frequently occurring letter in this string.
You can use the collections module to do this
import collections
most_freq = collections.Counter(cipher).most_common(1)[0]
Now all you are left with is to find the shift between your most_freq letter and e.
Perhaps the simplest way is just to enumerate the alphabet in a list and then find the index differences between the two.
alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
shift = alphabet.index(most_freq) - alphabet.index('e')
Remember this shift gets you from e to your most_freq letter so when you apply the shift to your text you need to apply the opposite ( -1 * shift ) to get the right result.
Hope this helps.

how to find alphabetic value of a keyword

I am currently trying to produce a program that allows me to encrypt and decrypt a words using a keyword, I have been told to use alphabetic value to do add from another words alphabetic value I know that I need to use ord or chr but I am not very confident in using this as I'm a beginner at programming, however I have no idea how to do this and would much appreciate, if someone could explain this to me with some examples.
s = "foo!#bar"
enc_key = "key"
# get sum of ord's of letters in key modulo 256
sm_ords= sum(map(ord,enc_key)) % 256
# add sum of ord's in encryption letter in key to ord of each char in s and use chr to create a new char
enc = "".join(chr((sm_ords + ord(ch))) for ch in s)
# reverse the encryption using - ord
dec = "".join(chr((ord(ch) - sm_ords)) for ch in enc)
print(enc)
print(dec)
¯¸¸jl«ª»
foo!#bar
This code encrypts / decrypts a string by adding the value of each of the keyword letters to each character in the string to be encrypted.
def encryptfunction():
result = ""
addedup = 0
for letter in wordtoencrypt:
for letter2 in keyword:
addedup = addedup + ord(letter2)
result = result + chr(ord(letter) + addedup)
return result
def decryptfunction():
result = ""
addedup = 0
for letter in wordtoencrypt:
for letter2 in keyword:
addedup = addedup + ord(letter2)
result = result + chr(ord(letter) - addedup)
return result
wordtoencrypt = input("Enter the word to encrypt:")
keyword = input("Enter the keyword:")
encrypt = int(input("encrypt(1) or decrypt(0)"))
if encrypt == 1:
print(encryptfunction())
else:
print(decryptfunction())

Categories