vigenere encryption probleme with 'spaces' on python - python

i can t pinpoint the reason why the encryption goes wrong after 'spaces'
here is the code :
def chiffre_vigenere(message,key):
message = message.lower()
key = key.lower()
encrypted = []
d = dict(a=0,b=1,c=2,d=3,e=4,f=5,g=6,h=7,i=8,j=9,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)
long_key = key
while len(message) > len(long_key) :
long_key = long_key + key
i=0
while i < len(message) :
decalage = d.get(long_key[i])
if message[i].isalpha() :
c = ord(message[i]) + decalage
if c > 122 :
c = c - 26
encrypted.append(chr(c))
else :
encrypted.append(message[i])
i = i+1
print(listToString(encrypted))
for example when i do : chiffre_vigenere('stack overflow','apple')
it gives : sipno dkpvfadh
the first word is encrypted right but after the space the encryption is wrong
any help is appreciated thanks in advance

The problem is that you're using the same counter variable i to mark your place in two different strings: message and long_key. Whenever you encounter a non-alphabet character in message, you're stepping to the next character, but you're also stepping to the next character in long_key, which is not what you want to do.
If you just use i to count characters in long_key then the problem goes away. For example:
def chiffre_vigenere(message,key):
message = message.lower()
key = key.lower()
encrypted = []
d = dict(a=0,b=1,c=2,d=3,e=4,f=5,g=6,h=7,i=8,j=9,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)
long_key = key
while len(message) > len(long_key):
long_key = long_key + key
i=0
for ch in message:
decalage = d.get(long_key[i])
if ch.isalpha() :
c = ord(ch) + decalage
if c > 122 :
c = c - 26
encrypted.append(chr(c))
i = i+1
else :
encrypted.append(ch)
print(listToString(encrypted))
You might also consider simplifying your code a little. You can use the ord function to convert ASCII values to integers, and a modulus operator to cycle through the values of key without having to expand it to the size of the input message.
def chiffre_vigenere(message,key):
key = key.lower()
encrypted = ''
i = 0
for ch in message.lower():
if 'a' <= ch <= 'z':
a = ord(ch) + ord(key[i]) - ord('a')
if a > ord('z'):
a -= 26
encrypted += chr(a)
i = (i + 1) % len(key)
else:
encrypted += ch
print(encrypted)

Related

Improving Encryption Algorithm

Recently I had started this assignment just meant for school purposes but I have recently decided that I would want to continue this as a new project and wanted suggestions on how I can improve my algorithm. I had an idea where I wanted the encryption key to change per character to make my encryption more secure but I have been having difficulty with this as It wouldn't work out and I couldnt decrypt my final encrypted text
Here is the encrypter:
text = input('Enter A Word : ') ##This asks a user for an input of text integers etc
encrypt = '' ##Empty Value used to store the encrypted value
temp = '' ##Empty temp value replaced at every iteration of the encryption process
temp2 =0 ##Empty temp value replaced at every iteration of the encryption process
temp_val=0
temp_char=''
rtext= text[::-1]
key=int(input('Enter your key (Your Encrypted Sentence Will Further be Encrypted Later) : '))##key used to shift the letters
for a in range (0,len(rtext)):
if len(rtext) % 2==0:
hlength=len(rtext)/2
else:
hlength=(len(rtext)+1)/2
print(hlength)
for i in range(int(hlength),len(rtext)):
##Rearranges text in a caps switch
if str.islower(rtext[i])==True:
temp=temp+str.upper(rtext[i])
elif str.isupper(rtext[i])==True:
temp=temp+str.lower(rtext[i])
else:
temp=temp+rtext[i]
for b in range(0,int(hlength)):
##Rearranges text in a caps switch
if str.islower(rtext[b])==True:
temp=temp+str.upper(rtext[b])
elif str.isupper(rtext[b])==True:
temp=temp+str.lower(rtext[b])
else:
temp=temp+rtext[b]
for j in range(0,len(temp)):
temp_val=0
temp2=0
temp_val=ord(temp[j])
temp2=temp2+temp_val+int(key)
temp_char=temp_char+chr(temp2)
encrypt=temp_char
print(encrypt)
print(temp)
print(temp2)
The Decrypter:
text = input('Enter A Word : ') ##This asks a user for an input of text integers etc
decrypt = '' ##Empty Value used to store the encrypted value
order=0
characters=''
temp=''
rtext=text[::-1]
key=int(input('Enter your key (decryption) : '))##key used to shift the letters
for i in range (0,len(rtext)):
order=0
order=order+ord(rtext[i])-int(key)
characters=characters+chr(order)
for a in range (0,len(rtext)):
if len(rtext) % 2==0:
hlength=len(rtext)/2
else:
hlength=(len(rtext)+1)/2
for j in range (int(hlength),len(characters)):
if str.islower(characters[j])==True:
temp=temp+str.upper(characters[j])
elif str.isupper(characters[j])==True:
temp=temp+str.lower(characters[j])
else:
temp=temp+characters[j]
for b in range (0,int(hlength)):
if str.islower(characters[b])==True:
temp=temp+str.upper(characters[b])
elif str.isupper(characters[b])==True:
temp=temp+str.lower(characters[b])
else:
temp=temp+characters[b]
print(temp)
I specifically want to change the variable key.
ord() - Turns characters into its Ascii equivalent
chr() - Turns Ascii numbers into its character equivalent
rtext - gets the inverse of the users input
If we simplify the code in the encryptor a little, we get:
def encrypt_text(text: str, key: int):
print("TEXT:", text, "KEY:", key)
temp = ''
temp2 = 0
temp_val = 0
temp_char = ''
rtext = text[::-1]
print("RTEXT:", rtext)
hlength = len(rtext) // 2 + len(rtext) % 2 # half, round up
print("HLENGTH:", hlength)
for i in range(hlength, len(rtext)):
# Rearrange text in a caps switch
if rtext[i].islower():
temp += rtext[i].upper()
elif rtext[i].isupper():
temp += rtext[i].lower()
else:
temp += rtext[i]
print("TEMP:", temp)
for b in range(0, int(hlength)):
# Rearrange text in a caps switch
if rtext[b].islower():
temp += rtext[b].upper()
elif rtext[b].isupper():
temp += rtext[b].lower()
else:
temp += rtext[b]
for j in range(len(temp)):
temp_val = 0
temp2 = 0
temp_val = ord(temp[j])
temp2 = temp2 + temp_val + int(key)
temp_char = temp_char + chr(temp2)
encrypt = temp_char
print("ENCRYPT:", encrypt)
print("TEMP:", temp)
print("TEMP2:", temp2)
return encrypt
text = "hello world"
key = 42
print("ENCRYPTED:", encrypt_text(text, key))
I've put it inside a function (and added some print statements), so it becomes easier to work with while developing. The code is essentially the same as yours, except
for a in range (0,len(rtext)):
if len(rtext) % 2==0:
hlength=len(rtext)/2
else:
hlength=(len(rtext)+1)/2
is replaced by
hlength = len(rtext) // 2 + len(rtext) % 2 # half, round up
which gives the same result (except hlength is an integer).
Your first two for loops do the same operation (switches case on a string). We can write a function for that:
def swap_case(str):
res = ''
for ch in str:
if ch.islower():
res += ch.upper()
elif ch.isupper():
res += ch.lower()
else:
res += ch
return res
and now we can replace the first two for loops with calls to our function:
temp += swap_case(rtext[hlength:len(rtext)]) # or shorter rtext[hlength:]
temp += swap_case(rtext[0:hlength]) # or shorter rtext[:hlength]
it just happend that .swapcase() is already a string method, so we didn't really need our swap_case function, and could just write:
temp += rtext[hlength:].swapcase()
temp += rtext[:hlength].swapcase()
Your third for-loop:
for j in range(len(temp)):
temp_val = 0 # this value is not used (it's overwritten 2 lines down)
temp2 = 0
temp_val = ord(temp[j])
temp2 = temp2 + temp_val + int(key) # temp2 is always zero at this point
temp_char = temp_char + chr(temp2)
encrypt = temp_char
can be simplified to (the initial value of temp_char is set to the empty string above):
for j in range(len(temp)): # for each index position (j)
temp_val = ord(temp[j]) # use the character at from temp at index j
temp2 = temp_val + int(key) # key is already an int from your: key=int(input('Enter your key (decryption) : '))
temp_char += chr(temp2)
encrypt = temp_char # hmm... just overwriting encrypt on every iteration
the comments mean that it could be even simpler:
encrypt = ''
for character in temp:
temp_val = ord(character)
temp2 = temp_val + key
encrypt += chr(temp2)
This leaves us with (the comments enumerate the steps taken):
def encrypt_text(text: str, key: int):
temp = ''
rtext = text[::-1] # (1) reverse the string
hlength = len(rtext) // 2 + len(rtext) % 2 # (2) split the string on hlength
second_part = rtext[hlength:].swapcase() # .. and swap case on the parts
first_part = rtext[:hlength].swapcase()
temp += second_part # (3) and put the second part..
temp += first_part # .. before the first part
encrypt = ''
for character in temp:
temp_val = ord(character)
temp2 = temp_val + key # (4) add key to every character
encrypt += chr(temp2)
return encrypt
to decrypt a string encrypted with this function, we need to do the operations "backwards and opposite":
def decrypt_text(encrypted, key):
temp = ''
for ch in encrypted:
temp += chr(ord(ch) - key) # subtract key from every character (4)
hlength = len(encrypted) // 2 + len(encrypted) % 2
half = len(encrypted) - hlength # the split point is a mirror image of what it is in encrypt_text (3)
rtext = ''
rtext += temp[half:].swapcase() # re-assemble the string and swap case (2)
rtext += temp[:half].swapcase()
text = rtext[::-1] # finally reverse (1)
return text
The standard way of using longer keys (similar to your one-key-per-character), is to use the xor function, which in Python is written as ^ (pronounced either 'hat' or 'xor'), as in:
a ^ b # true if either a, or b are true, but not both
Here is some background on how it works, although you don't really need to understand this to use it...
This operator work on bits. To see what is happening, lets define a
function to print the bit representation of an integer (you don't need
to understand this):
def bits(n):
return bin(n)[2:].zfill(4)
then we have we can show the bit patterns of integers 5 and 9, and the
operation 5 ^ 9:
bits(5) => 0101
bits(9) => 1001
--------------------
bits(5 ^ 9) => 1100
====================
if you look at the bit patterns, there is a 1 in the result where
there is exactly one 1 in the column above, so from left to right (0 ^
1 = 1, 1 ^ 0 = 1, 0 ^ 0 = 0, and 1 ^ 1 = 0).
Knowing the above, you can verify that for any number k ^ k == 0,
and n ^ 0 == n, and therefore n ^ k ^ k == n.
The useful thing about xor is that for any number n:
n ^ key ^ key == n
ie. xor-ing the number with key, twice, gives you back the number.
Let's use this to encrypt (zip(text, key) returns one character from text and key at a time, in lock-step, until one of them is "used up"):
def encrypt_xor(text: str, key: str):
if len(key) < len(text):
# key must be longer because of how zip works..
raise ValueError("Key must be at least as long as text")
res = ''
for ch, k in zip(text, key):
res += chr(ord(ch) ^ ord(k))
return res
if you try to print(encrypt_text('hello', 'world')) you'll get gibberish printed to your screen (since the value you get by xor-ing two characters isn't necessarily printable). The cool thing about xor is that the decrypt function is exactly the same as the encrypt function, so encrypting twice gives you the original value:
text = 'hello'
key = 'world'
cipher = encrypt_xor(text, key) # encrypted text is often called cipher
print(encrypt_xor(cipher, key)) # prints 'hello'
You can use a similar structure for shift-type encryption (but without the convenience that the decrypt function is the same as the encrypt), e.g.:
def encrypt_shift(text: str, key: str):
res = ''
for ch, k in zip(text, key):
res += chr(ord(ch) + ord(k)) # add the char from the key
return res
def decrypt_shift(text: str, key: str):
res = ''
for ch, k in zip(text, key):
res += chr(ord(ch) - ord(k)) # subtract the char from the key
return res
text = 'hello'
key = 'world'
cipher = encrypt_shift(text, key)
print(decrypt_shift(cipher, key)) # prints 'hello
to avoid the unpleasantness of needing a key that is longer than the text, we can start using the key from the beginning again if there is more text left. The itertools.cycle(..) function does this for us:
import itertools
def encrypt_shift(text: str, key: str):
res = ''
for ch, k in zip(text, itertools.cycle(key)):
res += chr(ord(ch) + ord(k))
return res
def decrypt_shift(text: str, key: str):
res = ''
for ch, k in zip(text, itertools.cycle(key)):
res += chr(ord(ch) - ord(k))
return res
now
text = 'hello world'
key = 'world'
cipher = encrypt_shift(text, key)
print(decrypt_shift(cipher, key)) # prints 'hello world' (not just 'hello' -- the first len(key) characters)
This can be plugged into the encrypt_text and decrypt_text functions from the other answer:
def encrypt_text(text: str, key: str): # key is now a string
temp = ''
rtext = text[::-1] # (1) reverse the string
hlength = len(rtext) // 2 + len(rtext) % 2 # (2) split the string on hlength
second_part = rtext[hlength:].swapcase() # .. and swap case on the parts
first_part = rtext[:hlength].swapcase()
temp += second_part # (3) and put the second part..
temp += first_part # .. before the first part
encrypt = encrypt_shift(temp, key) # (4) shift each char using key
return encrypt
and
def decrypt_text(encrypted, key):
temp = decrypt_shift(encrypted, key) # unshift each char using key
hlength = len(encrypted) // 2 + len(encrypted) % 2
half = len(encrypted) - hlength # the split point is a mirror image of what it is in encrypt_text (3)
rtext = ''
rtext += temp[half:].swapcase() # re-assemble the string and swap case (2)
rtext += temp[:half].swapcase()
text = rtext[::-1] # finally reverse (1)
return text

How can I fix the IndexError?

When I run this program (It is supposed to encode and decode things in and out of the Caesar cipher) and opt for the decode option, I get the error saying that the string index is out of range. Can anyone tell me how to fix this and tell me why it is happening? The text I entered for it to decode was ibmmp and the key was 1.Thanks.
alphabet = "abcdefghijklmnopqrstuvwxyz"
encdec = input("Would you like to encode or decode a message? ")
if encdec == "decode":
keyyn = input("Do you know the key to your encoded text? (Y/N) ")
if keyyn == "Y":
plaintext = input("Please type in your text ")
text = plaintext
key = int(input("What is the key? "))
for i in range(len(plaintext)):
letter = plaintext[i]
alphletter = alphabet.find(letter)
alphletter = alphletter - key
if alphletter < 0 or alphletter == 0:
alphletter = alphletter + 26
letter = alphabet[alphletter]
plaintext = plaintext + letter
else:
letter = alphabet[alphletter]
plaintext = plaintext + letter
print(plaintext.strip(text))
else:
print("This program is unable to decode a message without the key")
Problem: ibmmp and key of 1
i works, b gives you an error. Here is why:
alphletter = alphabet.find(letter) # ==> 1
alphletter = alphletter - key # ==> 0
if alphletter < 0 or alphletter == 0: # ==> True
alphletter = alphletter + 26 # ==> 26
letter = alphabet[alphletter] # only has indexes from 0 to 25
plaintext = plaintext + letter # ~~~~ crash ~~~~
# (also: indentation error for the last 2 lines)
You can use the modulo-operator % to fix over/underflow:
alphletter = (alphletter - key) % 26 # for -1 : 25
You could also use if alphletter < 0: - this will not handle keys thats wrap around multiple times (f.e. 210) or negative keys -22
Some optimizations
# create a mapping dictionary so we do not need index()
alph = "abcdefghijklmnopqrstuvwxyz"
len_alph = len(alph)
d = {c:i for i,c in enumerate(alph)} # mapping char to index
d.update( {v:k for k,v in d.items()} ) # mapping index to char
d.update( {c:i for i,c in enumerate(alph.upper())} ) # mapping CHAR to index
def encode(text,key):
indexes = [d.get(c,"?") for c in text] # only mapped things, others get ?
# if ? use ? else lookup the correct replacement using % to make the index
# wrap around if above/below the index into alph
return ''.join(d.get((i+key)%len_alph if i != "?" else "?","?") for i in indexes)
def decode(text,key):
return encode(text,-key)
print(encode("tataaaa",5))
Output:
yfyffff

Encryption code in python, call upon a function, python returns nothing. No error messages show

Okay, so I've written the following series of functions in Python 3.6.0:
def code_char(c, key):
result = ord(c) + key
if c.isupper():
while result > ord("Z"):
result -= 26
while result < ord("A"):
result += 26
return chr(result)
else:
while result > ord("z"):
result -= 26
while result < ord("a"):
result += 26
result = chr(result)
return result
def isletter(char):
if 65 <= ord(char) <= 90 or 97<= ord(char) <= 122:
return True
else:
return False
def encrypt(string, key):
result = ""
length = len(string)
key = key * (length // len(key)) + key[0:(length % len(key))]
for i in range(0,length):
if (isletter for i in string):
c = string[i]
num = int("".join("".join(i) for i in key))
result += code_char(c, num)
else:
c = string[i]
result += i
return result
Then I try to call on the functions with:
encrypt("This is a secret message!!", "12345678")
When python runs the program absolutely nothing happens. Nothing gets returned, and in the shell python forces me onto a blank line without indents, or >>>. i don't know what is right or wrong with the code as no error messages appear, and no results appear. Any kind of advice would be appreciated.
Thank you.
Looking at your code, I don't think this is an infinite loop. I think your loop will not be infinite but will run for a very long time since the value of key is very big, and so, subtracting 26 at a time, until it gets to an English letter ascii value, will just take forever (but not really forever)
>>> key = '12345678'
>>> length = len("This is a secret message!!")
>>> key * (length // len(key)) + key[0:(length % len(key))]
'12345678123456781234567812'
It might be a problem in the your logic, maybe in the logic generating the key, but if this is indeed the logic you want, how about using modulus rather than iterating:
def code_char(c, key):
result = ord(c) + key
if c.isupper():
if result > ord("Z"):
result = ord("Z") + result % 26 - 26
if result < ord("A"):
result = ord("A") - result % 26 + 26
return chr(result)
else:
if result > ord("z"):
result = ord("z") + result % 26 - 26
if result < ord("a"):
result = ord("a") - result % 26 + 26
return chr(result)
def isletter(char):
if 65 <= ord(char) <= 90 or 97<= ord(char) <= 122:
return True
else:
return False
def encrypt(string, key):
result = ""
length = len(string)
key = key * (length // len(key)) + key[0:(length % len(key))]
for i in range(0,length):
if (isletter for i in string):
c = string[i]
num = int("".join("".join(i) for i in key))
result += code_char(c, num)
else:
c = string[i]
result += i
return result
>>> encrypt("This is a secret message!!", "12345678")
'Rlmwrmwrerwigvixrqiwwekiss'
Should you be having while loop here , or are you intening if loop? I don't see any exit for while loop. That may be where your code is hanging.
if c.isupper():
while result > ord("Z"):
result -= 26
while result < ord("A"):
result += 26
return chr(result)
else:
while result > ord("z"):
result -= 26
while result < ord("a"):
result += 26
Also, if I replace while with if above, it's giving me overflow error.
OverflowError: Python int too large to convert to C long
EDIT
After looking at #polo's comment and taking a second look at code, I believe #polo is correct. I put while loop back and added print statements. I have commented them, but you can uncomment at your end.
I've also reduced key's complexity to just key = key and reduced key from 12345678 to just 1234 to see if the code works and if it completes in reasonable time.. You can make it as complex as you want once code runs smoothly.
Here is result I got after:
>>>
key =1234
coding char = T
coding char = h
coding char = i
coding char = s
coding char =
coding char = i
coding char = s
coding char =
coding char = a
coding char =
coding char = s
coding char = e
coding char = c
coding char = r
coding char = e
coding char = t
coding char =
coding char = m
coding char = e
coding char = s
coding char = s
coding char = a
coding char = g
coding char = e
coding char = !
coding char = !
encrypted_message = Ftuezuezmzeqodqfzyqeemsqaa
Modified code below:
def code_char(c, key):
result = ord(c) + key
if c.isupper():
while result > ord("Z"):
#print("result1 = {}",format(result))
result -= 26
while result < ord("A"):
#print("result2 = {}",format(result))
result += 26
return chr(result)
else:
while result > ord("z"):
#print("result3 = {}",format(result))
result -= 26
while result < ord("a"):
#print("result4 = {}",format(result))
result += 26
result = chr(result)
return result
def isletter(char):
if 65 <= ord(char) <= 90 or 97<= ord(char) <= 122:
return True
else:
return False
def encrypt(string, key):
result = ""
length = len(string)
#key = key * (length // len(key)) + key[0:(length % len(key))]
key = key
print "key ={}".format(key)
for i in range(0,length):
if (isletter for i in string):
c = string[i]
num = int("".join("".join(i) for i in key))
print("coding char = {}".format(c))
result += code_char(c, num)
else:
c = string[i]
result += i
return result
#encrypt("This is a secret message!!", "12345678")
encrypted_message = encrypt("This is a secret message!!", "1234")
print("encrypted_message = {}".format(encrypted_message))

Vigenere Cipher Python 2.0

Im having trouble with encoding / decoding programming for a vigenere cipher. Im only supposed to use lists, dictionaries and loops.
EDIT: I added in the decrypt i have. GetCharList() just gets a list containing the alphabet. I dont know what is wrong that its making the output of the decrpyt not the original message.
def encryptVig(msg, keyword):
alphabet = getCharList() #Get char list is another function which creates a list containing a - z
key = keyword.upper()
keyIndex = 0
dicList = []
for symbol in msg:
num = alphabet.find(key[keyIndex])
if num != -1:
num += alphabet.find(key[keyIndex])
alphabet.find(key[keyIndex])
num%= len(alphabet)
if symbol.isupper():
dicList.append(alphabet[num])
elif symbol.islower():
dicList. append(alphabet[num].lower())
keyIndex += 1
if keyIndex == len(key):
keyIndex = 0
else:
dicList.append(symbol)
return " " .join(dicList)
def decryptVig(msg, keyword):
getCharList()
key = keyword.upper()
keyIndex = 0
dicList = []
for symbol in msg:
num = alphabet.find(key[keyIndex])
if num != -1:
num -= alphabet.find(key[keyIndex])
alphabet.find(key[keyIndex])
num%= len(alphabet)
if symbol.isupper():
dicList.append(alphabet[num])
elif symbol.islower():
dicList. append(alphabet[num].lower())
keyIndex -= 1
if keyIndex == len(key):
keyIndex = 0
else:
dicList.append(symbol)
return " " .join(dicList)
Rather than hacking through the alphabet yourself, another approach would be to use ord and chr to remove some of the complexity of working with letters. At the very least consider using itertools.cycle and itertools.izip to construct a list of the encryption/decryption pairs. Here's how I would solve it:
def letters_to_numbers(str):
return (ord(c) - ord('A') for c in str)
def numbers_to_letters(num_list):
return (chr(x + ord('A')) for x in num_list)
def gen_pairs(msg, keyword):
msg = msg.upper().strip().replace(' ', '')
msg_sequence = letters_to_numbers(msg)
keyword_sequence = itertools.cycle(letters_to_numbers(keyword))
return itertools.izip(msg_sequence, keyword_sequence)
def encrypt_vig(msg, keyword):
out = []
for letter_num, shift_num in gen_pairs(msg, keyword):
shifted = (letter_num + shift_num) % 26
out.append(shifted)
return ' '.join(numbers_to_letters(out))
def decrypt_vig(msg, keyword):
out = []
for letter_num, shift_num in gen_pairs(msg, keyword):
shifted = (letter_num - shift_num) % 26
out.append(shifted)
return ' '.join(numbers_to_letters(out))
msg = 'ATTACK AT DAWN'
keyword = 'LEMON'
print(encrypt_vig(msg, keyword))
print(decrypt_vig(encrypt_vig(msg, keyword), keyword))
>>> L X F O P V E F R N H R
A T T A C K A T D A W N
I don't know how Vigenere is supposed to work. However I am quite sure that after
num = alphabet.find(key[keyIndex])
if num != -1:
num -= alphabet.find(key[keyIndex])
num is zero.

Caesar Cipher Function in Python

I'm trying to create a simple Caesar Cipher function in Python that shifts letters based on input from the user and creates a final, new string at the end. The only problem is that the final cipher text shows only the last shifted character, not an entire string with all the shifted characters.
Here's my code:
plainText = raw_input("What is your plaintext? ")
shift = int(raw_input("What is your shift? "))
def caesar(plainText, shift):
for ch in plainText:
if ch.isalpha():
stayInAlphabet = ord(ch) + shift
if stayInAlphabet > ord('z'):
stayInAlphabet -= 26
finalLetter = chr(stayInAlphabet)
cipherText = ""
cipherText += finalLetter
print "Your ciphertext is: ", cipherText
return cipherText
caesar(plainText, shift)
I realize that this answer doesn't really answer your question, but I think it's helpful anyway. Here's an alternative way to implementing the caesar cipher with string methods:
def caesar(plaintext, shift):
alphabet = string.ascii_lowercase
shifted_alphabet = alphabet[shift:] + alphabet[:shift]
table = string.maketrans(alphabet, shifted_alphabet)
return plaintext.translate(table)
In fact, since string methods are implemented in C, we will see an increase in performance with this version. This is what I would consider the 'pythonic' way of doing this.
You need to move cipherText = "" before the start of the for loop. You're resetting it each time through the loop.
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 "Your ciphertext is: ", cipherText
return cipherText
This is an improved version of the code in the answer of #amillerrhodes that works with different alphabets, not just lowercase:
def caesar(text, step, alphabets):
def shift(alphabet):
return alphabet[step:] + alphabet[:step]
shifted_alphabets = tuple(map(shift, alphabets))
joined_aphabets = ''.join(alphabets)
joined_shifted_alphabets = ''.join(shifted_alphabets)
table = str.maketrans(joined_aphabets, joined_shifted_alphabets)
return text.translate(table)
Example of usage:
>>> import string
>>> alphabets = (string.ascii_lowercase, string.ascii_uppercase, string.digits)
>>> caesar('Abc-xyZ.012:789?жñç', step=4, alphabets=alphabets)
'Efg-bcD.456:123?жñç'
References:
Docs on str.maketrans.
Docs on str.translate.
Docs on the string library
Using some ascii number tricks:
# See http://ascii.cl/
upper = {ascii:chr(ascii) for ascii in range(65,91)}
lower = {ascii:chr(ascii) for ascii in range(97,123)}
digit = {ascii:chr(ascii) for ascii in range(48,58)}
def ceasar(s, k):
for c in s:
o = ord(c)
# Do not change symbols and digits
if (o not in upper and o not in lower) or o in digit:
yield o
else:
# If it's in the upper case and
# that the rotation is within the uppercase
if o in upper and o + k % 26 in upper:
yield o + k % 26
# If it's in the lower case and
# that the rotation is within the lowercase
elif o in lower and o + k % 26 in lower:
yield o + k % 26
# Otherwise move back 26 spaces after rotation.
else: # alphabet.
yield o + k % 26 -26
x = (''.join(map(chr, ceasar(s, k))))
print (x)
Batteries included
while 1:
phrase = raw_input("Could you please give me a phrase to encrypt?\n")
if phrase == "" : break
print "Here it is your phrase, encrypted:"
print phrase.encode("rot_13")
print "Have a nice afternoon!"
https://docs.python.org/2/library/codecs.html#python-specific-encodings
Python 3 update
The fine docs say
[Now the rot_13] codec provides a text transform: a str to str mapping. It is not supported by str.encode() (which only produces bytes output).
Or, in other words, you have to import encode from the codecs module and use it with the string to be encoded as its first argument
from codecs import decode
...
print(encode(phrase, 'rot13'))
The problem is that you set cipherText to empty string at every cycle iteration, the line
cipherText = ""
must be moved before the loop.
As pointed by others, you were resetting the cipherText in the iteration of the for loop. Placing cipherText before the start of the for loop will solve your problem.
Additionally, there is an alternate approach to solving this problem using Python's Standard library. The Python Standard Library defines a function maketrans() and a method translate that operates on strings.
The function maketrans() creates translation tables that can be used with the translate method to change one set of characters to another more efficiently. (Quoted from The Python Standard Library by Example).
import string
def caesar(plaintext, shift):
shift %= 26 # Values greater than 26 will wrap around
alphabet_lower = string.ascii_lowercase
alphabet_upper = string.ascii_uppercase
shifted_alphabet_lower = alphabet_lower[shift:] + alphabet_lower[:shift]
shifted_alphabet_upper = alphabet_upper[shift:] + alphabet_upper[:shift]
alphabet = alphabet_lower + alphabet_upper
shifted_alphabet = shifted_alphabet_lower + shifted_alphabet_upper
table = string.maketrans(alphabet, shifted_alphabet)
return plaintext.translate(table)
Here, a more functional way:
(if you use shift i to encode, then use -i to decode)
def ceasar(story, shift):
return ''.join([ # concentrate list to string
(lambda c, is_upper: c.upper() if is_upper else c) # if original char is upper case than convert result to upper case too
(
("abcdefghijklmnopqrstuvwxyz"*2)[ord(char.lower()) - ord('a') + shift % 26], # rotate char, this is extra easy since Python accepts list indexs below 0
char.isupper()
)
if char.isalpha() else char # if not in alphabet then don't change it
for char in story
])
plainText = raw_input("What is your plaintext? ")
shift = int(raw_input("What is your shift? "))
def caesar(plainText, shift):
for ch in plainText:
if ch.isalpha():
stayInAlphabet = ord(ch) + shift
if stayInAlphabet > ord('z'):
stayInAlphabet -= 26
finalLetter = chr(stayInAlphabet)
#####HERE YOU RESET CIPHERTEXT IN EACH ITERATION#####
cipherText = ""
cipherText += finalLetter
print "Your ciphertext is: ", cipherText
return cipherText
caesar(plainText, shift)
As an else to if ch.isalpha() you can put finalLetter=ch.
You should remove the line: cipherText = ""
Cheers.
As #I82much said, you need to take cipherText = "" outside of your for loop. Place it at the beginning of the function. Also, your program has a bug which will cause it to generate encryption errors when you get capital letters as input. Try:
if ch.isalpha():
finalLetter = chr((ord(ch.lower()) - 97 + shift) % 26 + 97)
>>> def rotate(txt, key):
... def cipher(i, low=range(97,123), upper=range(65,91)):
... if i in low or i in upper:
... s = 65 if i in upper else 97
... i = (i - s + key) % 26 + s
... return chr(i)
... return ''.join([cipher(ord(s)) for s in txt])
# test
>>> rotate('abc', 2)
'cde'
>>> rotate('xyz', 2)
'zab'
>>> rotate('ab', 26)
'ab'
>>> rotate('Hello, World!', 7)
'Olssv, Dvysk!'
I have a hard time remember the char to int conversions so this could be optimized
def decryptCaesar(encrypted, shift):
minRange = ord('a')
decrypted = ""
for char in encrypted:
decrypted += chr(((ord(char) - minRange + shift) % 26) + minRange)
return decrypted
def encrypt():
plainText = input("What is your plaintext? ")
shift = int(input("What is your 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 ("Your ciphertext is: ", cipherText,"with a shift of",shift)
def decrypte():
encryption=input("enter in your encrypted code")
encryption_shift=int(input("enter in your encryption shift"))
cipherText1 = ""
for c in encryption:
if c.isalpha():
stayInAlphabet1 = ord(c) - encryption_shift
if stayInAlphabet1 > ord('z'):
stayInAlphabet1 += 26
finalLetter1 = chr(stayInAlphabet1)
cipherText1 += finalLetter1
print ("Your ciphertext is: ", cipherText1,"with negative shift of",encryption_shift)
from tkinter import *
menu=Tk()
menu.title("menu")
menu.geometry("300x300")
button1= Button(menu,text="encrypt",command=encrypt)
button1.pack()
button2= Button(menu,text="decrypt",command=decrypte)
button2.pack()
button3= Button(menu,text="exit",command=exit)
button3.pack()
menu.mainloop()
message = 'The quick brown fox jumped over the lazy dog. 1234567890 !##$%^&*()_+-'
encrypted = ''.join(chr(ord(char)+3) for char in message)
decrypted = ''.join(chr(ord(char)-3) for char in encrypted)
print(encrypted)
print(decrypted)
# Wkh#txlfn#eurzq#ir{#mxpshg#ryhu#wkh#od}|#grj1#456789:;<3#$C&'(a)-+,b.0
# The quick brown fox jumped over the lazy dog. 1234567890 !##$%^&*()_+-
def encrypt(text,shift):
'''
INPUT: text as a string and an integer for the shift value.
OUTPUT: The shifted text after being run through the Caeser cipher.
'''
# Create a placeholder list
encrypted_text = list(range(len(text)))
alphabet = string.ascii_lowercase
# Create shifted alphabet
first_half = alphabet[:shift]
second_half = alphabet[shift:]
shifted_alphabet = second_half+first_half
for i,letter in enumerate(text.lower()):
# Check for spaces or punctuation
if letter in alphabet:
# Find the original index position
original_index = alphabet.index(letter)
# Shifted letter
new_letter = shifted_alphabet[original_index]
encrypted_text[i] = new_letter
# Punctuation or space
else:
encrypted_text[i] = letter
return ''.join(encrypted_text)
For example, decod string:
"uo jxuhu! jxyi yi qd unqcfbu ev q squiqh syfxuh. muhu oek qrbu je tusetu yj? y xefu ie! iudt cu q cuiiqwu rqsa myjx jxu iqcu evviuj!".
This message has an offset of 10.
Code below:
import string
alphabet = list(string.ascii_lowercase)
print(alphabet, len(alphabet))
messege = "xuo jxuhu! jxyi yi qd unqcfbu ev q squiqh syfxuh. muhu oek qrbu je tusetu yj? y xefu ie! iudt cu q cuiiqwu rqsa myjx jxu iqcu evviuj!"
messege_split = messege.split()
print(messege_split)
encrypted_messege = ""
position = 0
for i in messege_split:
for j in i:
if ord(j) < 65:
encrypted_messege += j
else:
for k in alphabet:
if j == k:
position = alphabet.index(k)
if (position + 10) >= len(alphabet):
encrypted_messege += alphabet[abs((position + 10) - len(alphabet))]
else:
encrypted_messege += alphabet[position + 10]
encrypted_messege += " "
print(encrypted_messege)
Decoded string:
"hey there! this is an example of a caesar cipher. were you able to decode it? i hope so! send me a message back with the same offset!"
TRY IT!
Using cyclic generator:
import string
from itertools import cycle
def caesarCipherEncryptor(s, key):
def generate_letters():
yield from cycle(string.ascii_lowercase)
def find_next(v, g, c):
# Eat up characters until we arrive at the plaintext character
while True:
if v == next(g):
break
# Increment the plaintext character by the count using the generator
try:
for _ in range(c):
item = next(g)
return item
except UnboundLocalError:
return v
return "".join([find_next(i, generate_letters(), key) for i in s])
# Outputs
>>> caesarCipherEncryptor("xyz", 3)
>>> 'abc'
from string import ascii_lowercase as alphabet
class CaesarCypher:
alpha_len = len(alphabet)
min_guess_rate = 0.2
Encryption and decryption is a same stuff. when you want to decrypt for example with shift 10 that means that you can encrypt it with shift 26 - 10. In this case cycle will repeat at if you going to shift whole alphabet it will be the same. Also here i've proceed upper case and non chars
def __call__(self, text, offset, encrypt=True):
if not encrypt:
offset = self.alpha_len - offset
result = []
for letter in text:
if not letter.isalpha():
result.append(letter)
continue
letter_to_process = letter.lower()
processed_letter = self._encrypt_letter(letter_to_process, offset)
if letter.isupper():
processed_letter = processed_letter.upper()
result.append(processed_letter)
return ''.join(result)
all encryption goes here at most.
def _encrypt_letter(self, letter, offset=0):
position = (alphabet.find(letter) + offset) % self.alpha_len
return alphabet[position]
this part is for broot force and guess throug dictionary frequency.
#staticmethod
def __how_many_do_i_know(text):
clean_words = filter(lambda x: x.isalpha(), text.split())
clean_words = ['\'{}\''.format(x) for x in clean_words]
cursor = conn.cursor()
query = 'SELECT COUNT(*) FROM mydictionary WHERE word IN ({})'.format(",".join(clean_words))
cursor.execute(query)
response = cursor.fetchone()[0]
return response / len(clean_words)
def guess_encode(self, text):
options = [self(text, offset, encrypt=False) for offset in range(self.alpha_len)]
best_option = [self.__how_many_do_i_know(option) for option in options]
best_key, guess_rate = max(enumerate(best_option), key=lambda x: x[-1])
guess_text = options[best_key]
return best_key, guess_rate, guess_text
import string
wrd=raw_input("Enter word").lower()
fwrd=""
for let in wrd:
fwrd+=string.ascii_lowercase[(string.ascii_lowercase).index(let)+3]
print"Original word",wrd
print"New word",fwrd
according to me this answer is useful for you:
def casear(a,key):
str=""
if key>26:
key%=26
for i in range(0,len(a)):
if a[i].isalpha():
b=ord(a[i])
b+=key
#if b>90: #if upper case letter ppear in your string
# c=b-90 #if upper case letter ppear in your string
# str+=chr(64+c) #if upper case letter ppear in your string
if b>122:
c=b-122
str+=chr(96+c)
else:
str+=chr(b)
else:
str+=a[i]
print str
a=raw_input()
key=int(input())
casear(a,key)
This function shifts all letter to right according to given key.
Why not use the function reverse on the shift input, and and join the plain_text with the shift, and input it as the cipher text:
Plain = int(input("enter a number "))
Rev = plain[::-1]
Cipher = " ".join(for cipher_text in Rev)
The code is very large, but easy to understand. I think it fits your situation.
alphabet = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
class CaesarCipher(object):
def __init__(self, shift):
self.shift = shift
def encode(self, str):
encode = ''
str = str.lower()
for i in str:
if i in alphabet:
encode += alphabet[alphabet.index(i) + self.shift]
else:
encode += i
return encode.upper()
def decode(self, str):
decode = ''
str = str.lower()
for i in str:
if i in alphabet:
decode += alphabet[alphabet.index(i) - self.shift]
else:
decode += i
return decode.upper()
Using map:
def caesar(text, key):
return ''.join(map(lambda c:
chr((ord(c.lower()) - ord('a') + key) % 26 + ord('a')) if c.isalpha() else ''
, text))
This solution is more intuitively without the use of ord function:
def caesar_cipher(raw_text, key):
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
shifted_alphabet = alphabet[26-key:]+alphabet[0:(26-key)]
cipher_text = ""
for i in range(len(raw_text)):
char = raw_text[i]
idx = alphabet.find(char.upper())
if idx == -1:
cipher_text = cipher_text + char
elif char.islower():
cipher_text = cipher_text + shifted_alphabet[idx].lower()
else:
cipher_text = cipher_text + shifted_alphabet[idx]
return(cipher_text)
And an example:
plain_text = "The quick brown fox jumps over the lazy dog!"
caesar_cipher(plain_text,3)
And we get:
'Qeb nrfzh yoltk clu grjmp lsbo qeb ixwv ald!'
If we want to decrypt it:
caesar_cipher(caesar_cipher(plain_text,3),26-3)
and we get:
'The quick brown fox jumps over the lazy dog!'
More details here:https://predictivehacks.com/caesar-cipher-in-python/
caesar-cipher
message = str(input("Enter you message:"))
shift = int(input("Enter a number:"))
# encode
stringValue = [ord(message) - 96 for message in message]
print(stringValue)
encode_msg_val = []
[encode_msg_val.append(int(stringValue[i])+shift) for i in
range(len(stringValue))]
encode_msg_array = []
for i in range(len(encode_msg_val)):
encode_val = encode_msg_val[i] + 96
encode_msg_array.append(chr(encode_val))
print(encode_msg_array)
encode_msg = ''.join(encode_msg_array)
# dedcode
[deocde_msg_val = [ord(encode_msg) - 96 for encode_msg in encode_msg]
decode_val = []
[decode_val.append(deocde_msg_val[i] - shift) for i in
range(len(deocde_msg_val))]
decode_msg_array = []
[decode_msg_array.append(decode_val[i] + 96) for i in range(len(decode_val))]
decode_msg_list = []
[decode_msg_list.append(chr(decode_msg_array[i])) for i in
range(len(decode_msg_array))]
decode_msg = ''.join(decode_msg_list)
print(decode_msg)
alph = 'abcdefghijklmnopqrstuvwxyz'
# shift = int(input("Please enter the number of places to shift:"))
shift = 15
text = "python is fun!"
alph_len = len(alph)
if shift >=0 and shift <= alph_len:
# text = input("Please enter a sentence:")
shifted_alph = alph[shift:] + alph[:shift] # rotate
text = text.lower()
crypted_text = ""
for letter in text:
if letter in alph:
ind = alph.index(letter)
crypted_letter = shifted_alph[ind]
else:
crypted_letter = letter
crypted_text += crypted_letter
print(crypted_text)
else:
print(f"You need to enter a number between 0 and {alph_len}!")
# eniwdc xh ujc! # output
key = 3
def wub():
def choice():
choice = input("Do you wish to Encrypt of Decrypt?")
choice = choice.lower()
if choice == "e" or "encrypt":
return choice
elif choice == "d" or "decrypt":
return choice
else:
print("Invalid response, please try again.")
choice()
def message():
user = input("Enter your message: ")
return user
def waffle(choice, message, key):
translated = ""
if choice == "e" or "encrypt":
for character in message:
num = ord(character)
num += key
translated += chr(num)
derek = open('Encrypted.txt', 'w')
derek.write(translated)
derek.close()
return translated
else:
for character in message:
num = ord(character)
num -= key
translated += chr(num)
return translated
choice = choice() #Runs function for encrypt/decrypt selection. Saves choice made.
message = message() #Run function for user to enter message. Saves message.
final = waffle(choice, message, key) #Runs function to translate message, using the choice, message and key variables)
print("\n Operation complete!")
print(final)
wub()

Categories

Resources