Vigenere Cipher: Having issues with - python-3.x

I was following a python Vigenere cipher tutorial (https://www.youtube.com/watch?v=sxFObRNriUg) and one of the issues I'm having is that that I consistently get key errors (which is understandable) but I don't understand why the youtube tutorial didn't go over that. Considering I followed the tutorial word for word (apart from the modifications made to fit with the class format), I don't understand why my code is having problems and not his. Any help?
class VigenereCipher(object):
def __init__(self, key, alphabet):
self.key = key
self.alphabet = alphabet
self.letter_to_index = dict(zip(self.alphabet, range(len(self.alphabet))))
self.index_to_letter = dict(zip(range(len(self.alphabet)),self.alphabet))
def encode(self, text):
encrypted = ''
split_message = [text[i:i+len(self.key)] for i in range(0, len(text), len(self.key))]
for each_split in split_message:
i = 0
for letter in each_split:
number = (self.letter_to_index[letter] + self.letter_to_index[self.key[i]])
encrypted += self.index_to_letter[number]
i += 1
print (encrypted)
return encrypted
def decode(self, text):
decrypted = ''
split_cipher = [text[i:i+len(self.key)] for i in range(0, len(text), len(self.key))]
for each_split in split_cipher:
index = 0
for letter in each_split:
number = (self.letter_to_index[letter] - self.letter_to_index[self.key[i]])
decrypted += self.index_to_letter[number]
i += 1
return decrypted

Related

White Spaces issue while converting to binary

I'm implementing A5/1 algorithm, I have the following function:
def to_binary(plain):
print(plain)
binary = str(''.join(format(ord(x), 'b') for x in plain))
j = len(binary)
binary_values = []
k = 0
while(k < j):
binary_values.insert(k,int(binary[k]))
k = k + 1
return(binary_values)
then I'm reading the input as the following:
plainText = input("Please enter your plaintext : ")
print ("You entered : "+ plainText)
plainText = to_binary(plainText)
After that I generate a keyStream and I store it in a list, then I obtain the ciphered text as the following:
while(i < len(plainText)):
cipherText = cipherText + str(plainText[i] ^ keyStream[i])
i = i + 1
Now I can decrypt the ciphered text using the following function:
def decrypt(cipher,keystream):
s = ""
binary = []
i = 0
while(i<len(cipher)):
binary.insert(i,int(cipher[i]))
s = s + str(binary[i]^keystream[i])
i = i +1
print(s)
return convert_binary_to_str(s)
and the convert_binary_to_str function is:
def convert_binary_to_str(bin_data):
str_data =' '
for i in range(0, len(bin_data), 7):
temp_data = bin_data[i:i + 7]
decimal_data = BinaryToDecimal(temp_data)
str_data = str_data + chr(decimal_data)
return str_data
Everything is working fine if the input was a sentence with no white spaces, but if the sentence was for example "Hello There", the decryption is corrupted because the white space representation in binary this way is taking "6 bits" while the other alphabetical characters are "7-bits" long, what can I do to solve this?? I need to store the plain text in a list to apply the algorithm.

convert between str of text and lists of numbers in which described in the Numerical Equivalents of Letters

dic is a lookup dic for letters to number and numdic is a lookup for num to letters
'k':'10','l':'11','m':'12','n':'13','o':'14','p':'15','q':'16','r':'17','s':"18",'t':'19','u':'20',
'v':'21','w':'22','x':'23','y':'24','z':'25'}
numdic = {'0':'a','1':'b','2':'c','3':'d','4':'e','5':'f','6':'g','7':'h','8':'i',
'9':'j','10':'k','11':'l','12':'m','13':'n','14':'o','15':'p','16':'q','17':'r','18':'s','19':'t','20':'u',
'21':'v','22':'w','23':'x','24':'y','25':'z'}
def encode(message):
cipher = ''
for letter in message:
# checks for space
if(letter != ' '):
#adds the corresponding letter from the lookup_table
cipher += dic[letter]
else:
# adds space
cipher += ' '
return cipher
def decode(nummessage):
ciphertext = ''
for letter in nummessage:
if (letter != ' '):
ciphertext += numdic[letter]
else:
ciphertext +=' '
return ciphertext
# Driver function to run the program
def main():
#encrypt the given message
print('Enter a message to encrypt:')
message = input()
print(encode(message))
print('Enter message to decrypt:')
nummessage = input()
#decrypt the given message
print(decode(nummessage))
if __name__ == '__main__':
main()
when i run the code, for decoding if i enter 18 for example it gives me bi instead of s, is there another way to do this?
Your issue is that you are interpreting 18 as '18'. Then, when you iterate over that you get '1' and '8'. Try:
def decode(nummessage):
ciphertext = ''
for letter in nummessage.split(','):
if (letter != ' '):
ciphertext += numdic[letter]
else:
ciphertext +=' '
return ciphertext
And you can use it like this:
>>> decode("18,1,2")
sbc

pycryptodome : MAC Check Failed (using decrypt_and_verify)

I am working on an encryption program with Pycryptodome in Python 3.6 I am trying to encrypt a file and then decrypt it and verify the MAC tag. When I get to verify it, an error is thrown
import os
from Crypto.Cipher import AES
bib Cryptodome imported
aad = b'any thing'
nonce = b'\xde\xe2G\xca\xe8Lq9\xeb\x8b\x84\xe7'
key = b'\xde\xe9\xad\xe9\x14_\x07\x1aq7C\\\xd7\x9c\xae\xfcJ\x1c%\xec\xe6C\xbe\xf0eO\xfaJ1\x08\x0c\xae'
I set the nonce and key as constant just to start things first. then i will use nonce = get_random_bytes(12) unique for every file.
def encrypt(filename):
chunksize = 64 * 1024
outputFile = "(encrypted)" + filename
filesize = str(os.path.getsize(filename))
cipher = AES.new(key, AES.MODE_GCM, nonce)
cipher.update(aad)
with open(filename, 'rb') as infile:
with open(outputFile, 'wb') as outfile:
outfile.write(filesize.encode('utf-8'))
while True:
chunk = infile.read(chunksize)
if len(chunk) == 0:
break
elif len(chunk) % 16 != 0:
chunk += ' '.encode('utf-8') * (16 - (len(chunk) % 16))
ciphertext,sender_tag = cipher.encrypt_and_digest(chunk)
print (sender_tag)
outfile.write(ciphertext)
the decryption part using decrypt_and_verify so no need to worry about which come first the decryption or verification
def decrypt(filename,received_tag):
chunksize = 64 * 1024
outputFile = "(clear)"+ filename
cipher = AES.new(key, AES.MODE_GCM, nonce)
cipher.update(aad)
with open(filename, 'rb') as infile:
with open(outputFile, 'wb') as outfile:
while True:
chunk = infile.read(chunksize)
if len(chunk) == 0:
break
clearmessage = cipher.decrypt_and_verify(chunk, b'received_tag')
outfile.write(clearmessage)
outfile.truncate()
def Main():
choice = input("Would you like to (E)ncrypt or (D)ecrypt?: ")
if choice == 'E':
filename = input("File to encrypt: ")
#password = input("Password: ")
encrypt(filename)
print ("Done.")
elif choice == 'D':
filename = input("File to decrypt: ")
#password = input("Password: ")
received_tag = input("enter received tag:")
decrypt(filename,received_tag)
print ("Done.")
else:
print ("No Option selected, closing...")
if __name__ == '__main__':
Main()
And this is the error:
raise ValueError("MAC check failed")
ValueError: MAC check failed
I don't know where i messed up . by the way i get a tag similar to b'\x1c\xd1\xd8\x1a6\x07\xf3G\x8c_s\x94"*(b'
Update :
i did correct a mistake in the code sender_tag,ciphertext = cipher.encrypt_and_digest(chunk) insted of ciphertext,sender_tag = cipher.encrypt_and_digest(chunk) but still the problem persists
Quite a few of things look dodgy:
You write the file size, but then you don't read it back. Actually, I don't think you should write it at all.
You pad the chunk to the 16 bytes boundary before encrypting it, but GCM does not require that.
None should not be fixed, but random per encryption.
Nonce and MAC tag are typically stored along with the ciphertext (which therefore becomes longer than the plaintext).
By writing chunks independently one from the other you are allowing an attacker to remove, duplicate and reorder chunks in transit.

how to define decryption of caeser cipher

Ok So I missed class and am trying to do the work they did in there. One of the problems was fixing a caeser cipher. I believe I have fixed all except for the last part which is of course the part I'm stuck on. This is what I have.
#Change to T to lowercase in plaintext
#add : to the end of if statement
def encrypt(plaintext, alphabet, key):
plaintext = plaintext.lower()
cipherText = ""
for ch in plaintext:
idx = alphabet.find(ch)
if idx >= 0 and idx <= 25:
cipherText = cipherText + key[idx]
else:
cipherText = cipherText + ch
#add return ciphertext
return cipherText
#add def to decrypt line
def decrypt(cipherText, alphabet, key):
plainText = ""
for ch in cipherText:
idx = key.find(ch)
#add and idx <= 25 to if statement
if idx >= 0 and idx <= 25:
plaintext = plaintext + alphabet[idx]
else:
plaintext = plaintext + ch
return plaintext
#got rid of def main
#have myCipher = encrypt
# define both myCipher and my plain to the encrypt and decrypt
alphabet = "abcdefghijklmnopqrstuvwxyz"
key = "nopqrstuvwxyzabcdefghijklm"
plaintext = input("Enter the text you want to encrypt: " )
myCipher = encrypt(plaintext, alphabet, key)
myPlain = decrypt(cipherText,alphabet, key)
print(myCipher)
print("Checking if decryption works: ")
print(myPlain)
When I run the code it says cipherText is not defined in
myPlain = decrypt(cipherText,alphabet, key)
I have tried a few different options but I seem to be going further from fixing it than what I have it as now. So is a way I can define cipherText in that line or do I have to redo that line and change it to something else?
This is the error I get when I tried to change cipherText as LalolDublin suggested
Traceback (most recent call last):
File "C:\Users\David\Downloads\caeser (2).py", line 32, in <module>
myPlain = decrypt(myCipher ,alphabet, key)
File "C:\Users\David\Downloads\caeser (2).py", line 21, in decrypt
plaintext = plaintext + alphabet[idx]
UnboundLocalError: local variable 'plaintext' referenced before assignment
you can't use cipherText it's a local variable only within that function...
myCipher = encrypt(plaintext, alphabet, key)
myPlain = decrypt(myCipher ,alphabet, key)
Ok as LalolnDublin stated I needed to put myCipher instead of cipherText, he was right but I also needed to change the position of where I entered the code so that it could work properly. This is the finished product if anyone has a similar problem as I did here.
key = "nopqrstuvwxyzabcdefghijklm"
plainText = input("Enter the text you want to encrypt: " )
alphabet = "abcdefghijklmnopqrstuvwxyz"
def encrypt(plainText, key, alphabet):
plainText = plainText.lower()
cipherText = ""
for ch in plainText:
idx = alphabet.find(ch)
if idx >= 0 and idx <= 25:
cipherText = cipherText + key[idx]
else:
cipherText = cipherText + ch
return cipherText
myCipher = encrypt(plainText, key, alphabet)
def decrypt(myCipher, plainText, alphabet, key):
plainText = ""
for ch in myCipher:
idx = key.find(ch)
if idx >= 0 and idx <=25:
plainText = plainText + alphabet[idx]
else:
plainText = plainText + ch
return plainText
myPlain = decrypt(myCipher, plainText, alphabet, key)
print(myCipher)
print("Checking if decryption works: ")
print(myPlain)

Python 3.3 cypher script

So i have this code here in python 3.3, it cyphers text with the ceaser cypher.
What i need to know is how do i make a script that will convert it back from the original so that the person i send it too can read it.
message = input("Input: ")
key = 11
coded_message = ""
for ch in message:
code_val = ord(ch) + key
if ch.isalpha():
if code_val > ord('z'):
code_val -= ord('z') - ord('a')
coded_message = coded_message + chr(code_val)
else:
coded_message = coded_message + ch
# print ("Input: " + message)
print ("Output: " + coded_message)
One more thing, I plan to be putting this is a tkinter message box, with the two entry fields used for the input and output. one field should be used to type what i want to convert and the other should be used to show what the text looks like after it has been crypted. The button should start the encryption. here is the code:
import sys
from tkinter import *
def mHello():
mLabel = Label(mGui,text = input("Hello World"))
mLabel.grid(row=3, column=0,)
mGui = Tk()
ment = StringVar()
mGui.geometry("450x450+250+250")
mGui.title("My TKinter")
# input label
mLabel = Label(mGui,text = "Input",)
mLabel.grid(row=1,column=0,)
# output label
mLabeltwo = Label(mGui,text = "Input",)
mLabeltwo.grid(row=2,column=0,)
# convert button
mButton = Button(text = "Convert",command = mHello)
mButton.grid(row=3,column=0)
# input entry
mEntry = Entry(mGui,textvariable=ment)
mEntry.grid(row=1,column=1)
# output entry
mEntryTwo = Entry(mGui,textvariable=ment)
mEntryTwo.grid(row=2,column=1)
mGui.mainloop()
By the way i am only 15 and this is my 2nd day learning python.
Some credit goes to sources on this forum that have provided me with some code snippets
Thank-you in advance guys!
Before i say anything else you should be aware that minds much greater the mine have advised against writing your own cypher script for anything other then learning
If you want them to be able to decode your code then provide them with a key. so in your case:
s maps to h
t maps to i
f maps to t
I hope this code illustrates my suggestion:
In [1]: from cyro import your_cyrptic_function
In [2]: key = {'s':'h', 't':'i', 'f':'t'}
In [3]: secret_word = your_cyrptic_function('hit')
In [4]: decyrpted_secret_word = ''
In [5]: for letter in secret_word:
decyrpted_secret_word += key[letter]
...:
In [6]: print(decyrpted_secret_word)
hit
For the code above i turned your original code into a function:
def your_cyrptic_function(secret):
message = secret
key = 11
coded_message = ""
for ch in message:
code_val = ord(ch) + key
if ch.isalpha():
if code_val > ord('z'):
code_val -= ord('z') - ord('a')
coded_message = coded_message + chr(code_val)
else:
coded_message = coded_message + ch
# print ("Input: " + message)
return coded_message
there are several great ways to do this in python. If your interested in cyptopgraphy then check out Udacities class cs387 applied cryptography

Resources