XOR cryptographic algorithm not working for > 54 chars - python

I recently began to play around with cryptography after playing with Project Euler Problem 59, and I made a basic XOR cryptography system. In this case the concatentation of your output and a random key are made and saved to a text file (only as a test, I will make it better once I've fixed this bug), but I've noticed that certain messages do not encrypt or decrypt correctly. I've narrowed this down to messages of length > 54. My code is as follows:
#encrypt.py
import random
msg = raw_input("Enter your message: ")
out = ""
key = ""
for i in xrange(len(msg)):
key += chr(random.randint(0,255))
k = 0
for char in msg:
out += chr(ord(msg[k]) ^ ord(key[k]))
k += 1
print "\nYour output is:", out
print "Your key is:", key
raw_input()
with open("output.txt","r+") as f:
f.truncate()
f.write(out+key)
And decryption:
#decrypt.py
import sys
if not len(sys.argv) > 1: exit()
with open(sys.argv[1],"r+") as f:
content = f.read()
msg, key = content[:len(content)/2], content[len(content)/2:]
out = ""
k = 0
for char in msg:
out += chr(ord(char) ^ ord(key[k]))
k += 1
print out
raw_input()
For longer messages (than 54 chars), when they are decrypted they will give a string of random characters. Does anyone have an idea as to why this happens?

Since making characters out of random bits is likely to produce characters that look ugly on the screen, you can try hex-encoding the output before printing it.
#encrypt.py
import random
msg = raw_input("Enter your message: ")
out = ""
key = ""
for i in xrange(len(msg)):
key += chr(random.randint(0,255))
k = 0
for char in msg:
out += chr(ord(msg[k]) ^ ord(key[k]))
k += 1
out = ":".join("{:02x}".format(ord(c)) for c in out)
key = ":".join("{:02x}".format(ord(c)) for c in key)
print "\nYour output is:", out
print "Your key is:", key
raw_input()
with open("output.txt","w+") as f:
f.truncate()
f.write(out+key)
Then for decryption, you have to remove the colons and hex-decode before you can continue with regular decryption.
#decrypt.py
import sys
if not len(sys.argv) > 1: exit()
with open(sys.argv[1],"r+") as f:
content = f.read()
content = content.replace(':', '')
msg, key = content[:len(content)/2], content[len(content)/2:]
msg = msg.decode('hex')
key = key.decode('hex')
out = ""
k = 0
for char in msg:
out += chr(ord(char) ^ ord(key[k]))
k += 1
print out
raw_input()
At the console, the results look like this:
$ python encrypt.py
Enter your message: onetwothreefourfivesixseveneightnineteneleventwelvethirteen
Your output is: 7f:09:d0:8c:2e:1a:e0:a0:84:e7:bf:3b:e8:cc:f3:4e:35:e4:4f:20:c8:00:72:9d:f0:bc:de:54:88:30:a6:3d:93:3f:c1:6d:46:4a:68:ca:96:2e:16:50:43:0f:30:fa:27:f3:f2:8d:35:4b:6a:11:cc:02:04
Your key is: 10:67:b5:f8:59:75:94:c8:f6:82:da:5d:87:b9:81:28:5c:92:2a:53:a1:78:01:f8:86:d9:b0:31:e1:57:ce:49:fd:56:af:08:32:2f:06:af:fa:4b:60:35:2d:7b:47:9f:4b:85:97:f9:5d:22:18:65:a9:67:6a
$ cat output.txt
7f:09:d0:8c:2e:1a:e0:a0:84:e7:bf:3b:e8:cc:f3:4e:35:e4:4f:20:c8:00:72:9d:f0:bc:de:54:88:30:a6:3d:93:3f:c1:6d:46:4a:68:ca:96:2e:16:50:43:0f:30:fa:27:f3:f2:8d:35:4b:6a:11:cc:02:0410:67:b5:f8:59:75:94:c8:f6:82:da:5d:87:b9:81:28:5c:92:2a:53:a1:78:01:f8:86:d9:b0:31:e1:57:ce:49:fd:56:af:08:32:2f:06:af:fa:4b:60:35:2d:7b:47:9f:4b:85:97:f9:5d:22:18:65:a9:67:6a
$ python decrypt.py output.txt
onetwothreefourfivesixseveneightnineteneleventwelvethirteen

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

Need help fixing a ValueError of and 'i' index

So I'm making this code that uses strings to cipher a given phrase with a given key (I can't use the preset functions in python to do it). I believe I've got the idea of how to do it but I;m experiencing this error that I can't figure out how to fix. My code is the following.
def inputForChipher():
input1 = False
input2 = False
while input1 == False:
string = input('Enter the message: ')
input1 = verifyString(string)
while input2 == False:
key = input('Enter the key you want to use: ')
input2 = verifyString(key)
print(cipherWithKey(string, key))
def cipherWithKey(string, key):
string = string.lower()
key = key.lower()
letters = 'abcdefghijklmnopqrstuvwxyz'
count = 0
newCode = ''
for i in string:
if i == '':
count = 0
newCode += i
else:
if count > (len(key)-1):
count = 0
value1 = letters.index(i) + 1
value2 = letters.index(key[count]) + 1
num = value1 + value2
if num > 26:
num -= 26
newCode += letters[num-1]
count += 1
return newCode
And I'm getting the following error:
File "C:\Users\xxxxx\Desktop\funciones.py", line 29, in cipherWithKey
value1 = letters.index(i) + 1
ValueError: substring not found
I know what causes this error, but I'm not sure of why I'm getting it in this case.
well its clear , in your input 'tarea de' you are passing space in your input ( string varible) which is not in letters variable and it fails in that line.
you can add the possible characters to your letters variable like :
letters = 'abcdefghijklmnopqrstuvwxyz '
alternatively you can use string module to provide the full list of whitespaces
import string as st
letters = st.ascii_lowercase + st.whitespace

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:
...

Interactive rot13 cipher

I have a code and I'm having trouble making it interactive.
Here's the problem:
"""Write a function called rot13 that uses the Caesar cipher to encrypt a message. The Caesar cipher works like a substitution cipher but each character is replaced by the character 13 characters to “its right” in the alphabet. So for example the letter “a” becomes the letter “n”. If a letter is past the middle of the alphabet then the counting wraps around to the letter “a” again, so “n” becomes “a”, “o” becomes “b” and so on. Hint: Whenever you talk about things wrapping around its a good idea to think of modulo arithmetic (using the remainder operator)."""
Here's the code to this problem:
def rot13(mess):
alphabet = 'abcdefghijklmnopqrstuvwxyz'
encrypted = ''
for char in mess:
if char == ' ':
encrypted = encrypted + ' '
else:
rotated_index = alphabet.index(char) + 13
if rotated_index < 26:
encrypted = encrypted + alphabet[rotated_index]
else:
encrypted = encrypted + alphabet[rotated_index % 26]
return encrypted
def main():
print(rot13('abcde'))
print(rot13('nopqr'))
print(rot13(rot13('since rot thirteen is symmetric you should see this message')))
if __name__ == "__main__":
main()
I want to make it interactive where you can input any message and you can rotate the letters however many times as you want. Here is my attempt. I understand you'd need two parameters to pass, but I'm clueless as to how to replace a few items.
Here's my attempt:
def rot13(mess, char):
alphabet = 'abcdefghijklmnopqrstuvwxyz'
encrypted = ''
for char in mess:
if char == ' ':
encrypted = encrypted + ' '
else:
rotated_index = alphabet.index(char) + mess
if rotated_index < 26:
encrypted = encrypted + alphabet[rotated_index]
else:
encrypted = encrypted + alphabet[rotated_index % 26]
return encrypted
def main():
messy_shit = input("Rotate by: ")
the_message = input("Type a message")
print(rot13(the_message, messy_shit))
if __name__ == "__main__":
main()
I don't know where my input should be taking place in the function. I have a feeling it could be encrypted?
This is probably what you're looking for. It rotates the message by the messy_shit input.
def rot13(mess, rotate_by):
alphabet = 'abcdefghijklmnopqrstuvwxyz'
encrypted = ''
for char in mess:
if char == ' ':
encrypted = encrypted + ' '
else:
rotated_index = alphabet.index(char) + int(rotate_by)
if rotated_index < 26:
encrypted = encrypted + alphabet[rotated_index]
else:
encrypted = encrypted + alphabet[rotated_index % 26]
return encrypted
def main():
messy_shit = input("Rotate by: ")
the_message = input("Type a message")
print(rot13(the_message, messy_shit))
def rot(message, rotate_by):
'''
Creates a string as the result of rotating the given string
by the given number of characters to rotate by
Args:
message: a string to be rotated by rotate_by characters
rotate_by: a non-negative integer that represents the number
of characters to rotate message by
Returns:
A string representing the given string (message) rotated by
(rotate_by) characters. For example:
rot('hello', 13) returns 'uryyb'
'''
assert isinstance(rotate_by, int) == True
assert (rotate_by >= 0) == True
alphabet = 'abcdefghijklmnopqrstuvwxyz'
rotated_message = []
for char in message:
if char == ' ':
rotated_message.append(char)
else:
rotated_index = alphabet.index(char) + rotate_by
if rotated_index < 26:
rotated_message.append(alphabet[rotated_index])
else:
rotated_message.append(alphabet[rotated_index % 26])
return ''.join(rotated_message)
if __name__ == '__main__':
while True:
# Get user input necessary for executing the rot function
message = input("Enter message here: ")
rotate_by = input("Enter your rotation number: ")
# Ensure the user's input is valid
if not rotate_by.isdigit():
print("Invalid! Expected a non-negative integer to rotate by")
continue
rotated_message = rot(message, int(rotate_by))
print("rot-ified message:", rotated_message)
# Allow the user to decide if they want to continue
run_again = input("Continue? [y/n]: ").lower()
while run_again != 'y' and run_again != 'n':
print("Invalid! Expected 'y' or 'n'")
run_again = input("Continue? [y/n]: ")
if run_again == 'n':
break
Note: It's more efficient to create a list of characters then join them to produce a string instead of using string = string + char. See Method 6 here and the Python docs here. Also, be aware that our rot function only works for lowercase letters of the alphabet. It'll break if you try to rot a message with uppercase characters or any character that isn't in alphabet.

Brute force decryption python

Hello I am trying to brute force decrypt a word 58 times but my code keeps adding more characters for every loop it does. Has anyone got any idea what I am doing wrong I just learnt python 3
Here is my attempt to decrypt
word = input("Please enter the encrypted word: ")
message = ""
times = 0
for i in range(58):
for ch in word:
val=ord(ch)
times += 1
val = (val-times)
if val > ord('z'):
val = ord('a') + (val - ord('z')-1)
message +=chr(val)
print("Here is your original message: ", message)
Is this what you're looking for?
word = input("Please enter the encrypted word: ")
message = ""
times = 0
for i in range(58):
message = ""
for ch in word:
val=ord(ch)
val = (val-times)
if val > ord('z'):
val = ord('a') + (val - ord('z')-1)
message +=chr(val)
print("Here is your encrypted message: ", message)
times += 1
Knowing what kind of encryption was used would make this a much easier problem to solve.

Categories