Convert string with accent into numbers (RSA encryption) - python

My math teacher asked us to program the RSA encryption/decryption process in python. So I've created the following function:
lettre_chiffre(T) which convert each character in the string into a number with the ord() function
chiffre_lettre(T) which does the opposite with chr()
And as these functions create 4 numbers blocks I need to encrypted in RSA with 5 numbers block to prevent frequency analysis.
The problem is the ord function doesn't works well with french accents "é" "à"...
Therefore, I was interested by using the bytearray method, but I have no idea how to use it.
How can I make this program works with accents. The encryption and decryption in byte with bytearray is not working with "é" and "à" for example.
python
def lettre_chiffre(T):
Message_chiffre = str('')
for lettre in T:
if ord(lettre) < 10000:
nombre = str(ord(lettre))
while len(nombre) != 4:
nombre = str('0') + nombre
Message_chiffre += nombre
else:
print("erreur lettre : ",lettre)
while len(Message_chiffre)%4 != 0:
Message_chiffre = str('0') + Message_chiffre
return str(Message_chiffre)
def chiffre_lettre(T):
Message_lettre = str('')
A =T
for i in range(int(len(str(A))/4)):
nombre = str(A)[4*i:4*i+4]
if int(nombre) < 10000:
Message_lettre += str(chr(int(nombre)))
return Message_lettre

Refer this post: https://stackoverflow.com/a/2788599
What you need is
>>> '\xc3\xa9'.decode('utf8')
u'\xe9'
>>> u = '\xc3\xa9'.decode('utf8')
>>> u
u'\xe9'
>>> ucd.name(u)
'LATIN SMALL LETTER E WITH ACUTE'

Related

Adapting Python function easyCrypto() to use a dictionary instead of a multiway if function

There is an exercise that I was able to complete where I was tasked with implementing a function easyCrypto() which took a string for input and returned its encryption as follows:
Every character at an odd position i in the alphabet was encrypted with the character at position i + 1, and every character at an even position in the alphabet was encrypted with the character at position i - 1. ('a' becomes 'b', 'b' becomes 'a', 'c' becomes 'd', etc.) Lowercase remained lowercase and uppercase remained uppercase. This is what I wrote:
from string import ascii_letters
def easyCrypto(string):
encrypted = ''
for char in string:
if char in ascii_letters:
ascii_code = ord(char)
if ascii_code % 2 == 1:
encrypted += chr(ascii_code + 1)
else:
encrypted += chr(ascii_code - 1)
else:
encrypted += char
print(encrypted)
>>> easyCrypto('abc')
bad
>>> easyCrypto('ZOO')
YPP
There is a follow-up exercise that instructs me to redo this problem using a dictionary instead of a multiway if statement. I have not succeeded in various attempts, although I have been fairly close at times. I would like to learn where I am going wrong. Here is the last bit I came up with:
from itertools import chain
def easyCrypto(string):
asciiDict = dict()
asciiNum = chain(range(65,91), range(97,123))
for i in asciiNum:
asciiDict[str(i)] = chr(i)
for j in range(0, len(string)):
encrypted = ''
for string[j] in asciiDict.keys():
val = asciiDict[string[j]]
while val % 2 == 1:
encrypted += asciiDict[string[j]+1]
else:
encrypted += asciiDict[string[j]-1]
return encrypted
t = {i: i-(-1)**i
for a in [65, 97]
for i in range(a, a+26)}
def easyCrypto(string):
print(string.translate(t))
easyCrypto('abc')
easyCrypto('ZOO')
You need to build the dictionary first, after that loop over the string
from itertools import chain
def easyCrypto(string):
asciiDict = dict()
asciiNum = chain(range(65,91), range(97,123))
for i in asciiNum:
asciiDict[i] = chr(i)
encrypted = ''
for cha in string:
val = ord(cha)
if val % 2 == 1:
encrypted += asciiDict[val+1]
else:
encrypted += asciiDict[val-1]
return encrypted

python string.split() and loops

disclaimer im new to python
i need to split a string input send if to a function that substitutes a character in the string with a different character (like a substitution cipher) but i just dont know how to go about this
print('Welcome to the encryption protocol for top secret governemt cover ups')
string=input('whats your message?')
def encrypt(string):
alpha = "abcdefghijklmnopqrstuvwyz"
sub_alpha = "pokmenliuytrwqazxcvsdfgbhn"
index=0
while index < len(string):
letter=string[index]
im not really sure what im doing im really bad at python, this has had me stumped for 3 days now ive reviewed my course material and tried videos on youtube im probably just really really dumb
I think the key piece of knowledge you're missing is that strings are iterable. So you can do things like:
for c in "FOO":
print(c)
# prints "F\nO\nO\n"
And you can find the index of a character within a string with str.index. So you can build up your cyphertext like this:
alpha = "abcdefghijklmnopqrstuvwyz "
cypher = "pokmenliuytrw qazxcvsdfgbhn"
plaintext = "some string"
cyphertext = ""
for c in plaintext:
char_index = alpha.index(c)
cyphertext += cypher[char_index]
You can also iterate over things inline - this is called a comprehension. So to transform your string you can do this instead of using the for loop:
cyphertext = "".join(cypher[alpha.index(c)] for c in plaintext)
The example above uses the str.join function to concatenate each character of cyphertext.
Here is a solution that asks the question and then iterates through each letter, finding the index in the alpha key, and replacing it with the sub_alpha key equivalent.
Note this example also checks if it should be lowercase or uppercase.
EDIT: if the input character does not have a valid cipher, it doesn't get altered.
EDIT 2: expanded answer to convert both forwards and backwards.
alpha = "abcdefghijklmnopqrstuvwyz"
sub_alpha = "pokmenliuytrwqazxcvsdfgbhn"
def encrypt(in_char):
is_lower_case = in_char.islower()
index = alpha.find(in_char.lower())
if index < 0:
return in_char
elif is_lower_case:
return sub_alpha[index]
else:
return sub_alpha[index].upper()
def decrypt(in_char):
is_lower_case = in_char.islower()
index = sub_alpha.find(in_char.lower())
if index < 0:
return in_char
elif is_lower_case:
return alpha[index]
else:
return alpha[index].upper()
print('Welcome to the encryption protocol for top secret governemt cover ups')
input_str=input('whats your message? ')
output_str=""
for letter in input_str:
output_str += encrypt(letter)
print("Encrypted: ")
print(output_str)
input_str=""
for letter in output_str:
input_str+= decrypt(letter)
print("Decrypted: ")
print(input_str)

Going back to begining of a string

I am coding a Caesar cipher. The key is an integer from 1 to 25. This cipher rotates the letters of the alphabet (A to Z). The encoding replaces each letter
with the 1st to 25th next letter in the alphabet (wrapping Z to A). So key 2 encrypts “HI” to “JK”, but key 20 encrypts “HI” to “BC”.
But If I put in
"I am super" it will output "k kc oouwrgt" when it should be "k co uwrgt" with a key of 2. It will also not go back to the beginning of the alphabet e.g 'x' will not go to 'a' with a key of 2. I use python 3.4.1
encode = []
a = "abcdefghijklmnopqrstuvwyxz"
a = list(a)
print(a)
e = input("encode or decode --->")
text = input("Sentence -->").lower()
text = list(text)
print(text)
Key = int(input("Key -->"))
if Key > 25:
print("Too high")
else:
print(Key)
if e == "encode":
for i, item in enumerate(text):
if item == " ":
encode.append(letter)
else:
num = a.index(item)
num = num + int(Key)
letter = a[num]
encode.append(letter)
for i in range(len(encode)):
print(encode[i])
When you encounter a space, you append the last letter again, instead of item:
if item == " ":
encode.append(letter)
This causes k and o to appear twice when the key is 2; you re-appended the encoded i -> k and m -> o results.
You need to use the % modulo operator to make your index 'wrap round':
num = (num + Key) % 26
I removed the int() call, you already turned Key to an integer earlier.
Other tips:
You don't need to turn a into a list; strings are sequences too and support indexing and the .index()method directly. The same applies to text; just loop over the string itself.
You are not using i in the for i, item in enumerate(text): loop; drop enumerate altogether: for item in text:.
You could just print your encoded characters directly in that loop, no need to use an encode list and a separate loop.
The str.join() method would let you print your encoded text all on one line: print(''.join(encode)) instead of your last for loop.
The absolute fastest method of encoding a string is to use a translation table, a dictionary mapping input characters to output characters, and the str.translate() method. You can use the str.maketrans() function to make that table:
import string
a = string.ascii_lowercase # why type yourself when the stdlib has these?
text = input("Sentence -->").lower()
Key = int(input("Key -->"))
mapping = str.maketrans(a, a[Key:] + a[:Key]) # letters to rotated letters
print(text.translate(mapping))
The trick lies in creating the second string for str.maketrans(); using slicing it is easy to create a rotated string, by taking everything from position Key onwards, and the first Key characters at the end:
>>> a[Key:] + a[:Key]
'cdefghijklmnopqrstuvwyxzab'
One obvious solution would be to use modulo for the alphabet index:
The % (modulo) operator yields the remainder from the division of the
first argument by the second.
>>> 12 % 26
12
>>> 26 % 26
0
>>> 28 % 26
2
As a bonus, you wouldn't need to check the key is lower than 25, and you'll never get an IndexError: list index out of range.
encode = []
a = "abcdefghijklmnopqrstuvwyxz"
e = input("encode or decode --->")
text = input("Sentence -->").lower()
key = int(input("Key -->"))
if e == "encode":
for i, item in enumerate(text):
if item == " ":
encode.append(item)
else:
num = a.index(item)
num = num + int(key)
letter = a[num % 26]
encode.append(letter)
for letter in encode:
print(letter)
A few notes:
a string is already an iterable of characters. No need to convert it to a list
letter wasn't defined in if item == " "
to iterate over a list, you don't need the length or the index.
to decode the message, just change the sign of the key. It should work just like encode, thanks to modulo : -2 % 26 # => 24
As an example:
encode or decode --->encode
Sentence -->i am super
Key -->2
k
c
o
u
w
r
g
t
and
encode or decode --->encode
Sentence -->k co uwrgt
Key -->-2
i
a
m
s
u
p
e
r

Selecting specific int values from list and changing them

I have been playing with Python and came across a task from MIT, which is to create coded message (Julius Cesar code where for example you change ABCD letters in message to CDEF). This is what I came up with:
Phrase = input('Type message to encrypt: ')
shiftValue = int(input('Enter shift value: '))
listPhrase = list(Phrase)
listLenght = len(listPhrase)
ascii = []
for ch in listPhrase:
ascii.append(ord(ch))
print (ascii)
asciiCoded = []
for i in ascii:
asciiCoded.append(i+shiftValue)
print (asciiCoded)
phraseCoded = []
for i in asciiCoded:
phraseCoded.append(chr(i))
print (phraseCoded)
stringCoded = ''.join(phraseCoded)
print (stringCoded)
The code works but I have to implement not shifting the ascii value of spaces and special signs in message.
So my idea is to select values in list in range of range(65,90) and range(97,122) and change them while I do not change any others. But how do I do that?
If you want to use that gigantic code :) to do something as simple as that, then you keep a check like so:
asciiCoded = []
for i in ascii:
if 65 <= i <= 90 or 97 <= i <= 122: # only letters get changed
asciiCoded.append(i+shiftValue)
else:
asciiCoded.append(i)
But you know what, python can do the whole of that in a single line, using list comprehension. Watch this:
Phrase = input('Type message to encrypt: ')
shiftValue = int(input('Enter shift value: '))
# encoding to cypher, in single line
stringCoded = ''.join(chr(ord(c)+shiftValue) if c.isalpha() else c for c in Phrase)
print(stringCoded)
A little explanation: the list comprehension boils down to this for loop, which is easier to comprehend. Caught something? :)
temp_list = []
for c in Phrase:
if c.isalpha():
# shift if the c is alphabet
temp_list.append(chr(ord(c)+shiftValue))
else:
# no shift if c is no alphabet
temp_list.append(c)
# join the list to form a string
stringCoded = ''.join(temp_list)
Much easier it is to use the maketrans method from the string module:
>>import string
>>
>>caesar = string.maketrans('ABCD', 'CDEF')
>>
>>s = 'CAD BA'
>>
>>print s
>>print s.translate(caesar)
CAD BA
ECF DC
EDIT: This was for Python 2.7
With 3.5 just do
caesar = str.maketrans('ABCD', 'CDEF')
And an easy function to return a mapping.
>>> def encrypt(shift):
... alphabet = string.ascii_uppercase
... move = (len(alphabet) + shift) % len(alphabet)
... map_to = alphabet[move:] + alphabet[:move]
... return str.maketrans(alphabet, map_to)
>>> "ABC".translate(encrypt(4))
'EFG'
This function uses modulo addition to construct the encrypted caesar string.
asciiCoded = []
final_ascii = ""
for i in ascii:
final_ascii = i+shiftValue #add shiftValue to ascii value of character
if final_ascii in range(65,91) or final_ascii in range(97,123): #Condition to skip the special characters
asciiCoded.append(final_ascii)
else:
asciiCoded.append(i)
print (asciiCoded)

Anyway to shorten this Python Caesar Cipher code into fewer lines?

def encrypt(text, key, direction):
if direction == 1: #The direction is either -1, or 1. If it is 1, it goes right. Otherwise, it will go left.
emptys=''
for x in text:
b = ord(x) #b is the individual characters after the ord() function
b+=key
if b<=122:
n = chr(b) #n is the converted letter of the encrypted ASCII number
emptys+=n
else:
o=b-90
q=chr(o)
emptys+=q
return emptys
else:
emptys=''
for x in text:
b = ord(x) #b is the individual characters after the ord() function
b=b-key
if b>=32:
n = chr(b) #n is the converted letter of the encrypted ASCII number
emptys+=n
else:
o=b+90
q=chr(o)
emptys+=q
return emptys
Your code as written blithely translates alphabetic characters to non-alphabetic and vice versa (e.g. encrypt('abc', 25, 1) gets 'z!"'). So it's wrong by most definitions of the traditional Caesar cipher, which should only modify alphabetic characters, and should rotate them within the alphabet.
That said, getting it right is easier than you're making it. The best approach is to avoiding rolling your own rotation code. Python already provides a really nice way to do one-to-one character mappings, str.translate. For example:
from string import ascii_letters, ascii_uppercase, ascii_lowercase
def encrypt(text, key, direction):
# direction == -1 is trivially converted to direction == 1 case
if direction == -1:
key = 26 - key
# On Py2, you'd use the string module's string.maketrans instead of
# str.maketrans
trans = str.maketrans(ascii_letters, ascii_lowercase[key:] + ascii_lowercase[:key] + ascii_uppercase[key:] + ascii_uppercase[:key])
return text.translate(trans)

Categories

Resources