I been trying to create a Caesar cypher program with the message 'my secret' and key 6 - all letters are shifted 6 positions to the right in the cypher alphabet, with letters “wrapping around” when falling off the end. Using the cypher, the message “my secret” would be encoded as “gsumzxlzn”. However, I keep the wrong encoded and decoded results. It's comes out as:
Encoded: sdfykixkz
Decoded: abcdefghi
please help!
import sys
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 main(plaintext, key):
cypher = generate_cypher(key)
plaintext = sys.argv[1]
e_code = encode_message(plaintext, cypher)
mes s= decode_message(e_code, cypher)
def generate_cypher(key):
cipher = []
for i in range(len(ALPHABET)):
cipher.append(ALPHABET[i+key%27])
print(cipher)
return(cipher)
def encode_message(plaintext,cipher):
key = int(sys.argv[2])
en_code=''
for c in plaintext:
if c in cipher:
en_code+=cipher[(cipher.index(c)+key)%(len(cipher))]
print("Encoded: ", en_code)
return en_code
def decode_message(e_code,cipher):
key = int(sys.argv[2])
message = []
for i in range(len(e_code)):
message.append(cipher[i-key%27])
mess=''.join(message)
print("Decoded: ", mess)
return mess
Related
I am trying to implement a python program to encrypt a plain text using AES/ECB/PKCS5 padding. The output I am getting is slightly different from expected.
Python3 program:
import base64
from Crypto.Cipher import AES
def add_to_16(value):
while len(value) % 16 != 0:
value += '\0'
return str.encode (value) # returns bytes
# Encryption method
def encrypt(text):
# Secret key
key='92oifgGh893*cj%7'
# Text to be encrypted
# Initialize encryptor
aes = AES.new(key, AES.MODE_ECB)
# Aes encryption to be
encrypt_aes = aes.encrypt(add_to_16(text))
# Converted into a string with base64
encrypted_text = str(base64.encodebytes (encrypt_aes), encoding = 'utf-8')
print(encrypted_text)
return encrypted_text
if __name__ == '__main__':
text = '{ "Message": "hello this is a plain text" , "user":"john.doe", "Email":"john.doe#example.com}'
entrypted_text = encrypt(text)
The output for above program is:
oo8jwHQNQnBwVUsJ5piShFRM3PFFIfULwcoFOEQhPMTAvexSr6eE9aFLVQTpAKBFkGi8vNbtScvyexSxHBlwVapJ5Szz1JPR9q9cHHJYYMzGocln4TRPFQ6S3e8jjVud
where as when verified with 3rd party tools online, the results is:
oo8jwHQNQnBwVUsJ5piShFRM3PFFIfULwcoFOEQhPMTAvexSr6eE9aFLVQTpAKBFkGi8vNbtScvyexSxHBlwVapJ5Szz1JPR9q9cHHJYYMwnIIuNCUVn/IExpxebqXV1
Can someone please guide me where I am doing wrong?
I have framed the code with below for padding with PKCS5 and is working as expected.
block_size=16
pad = lambda s: s + (block_size - len(s) % block_size) * chr(block_size - len(s) % block_size)
and the encrypt method was re-written as below:
def encrypt(plainText,key):
aes = AES.new(key, AES.MODE_ECB)
encrypt_aes = aes.encrypt(pad(plainText))
encrypted_text = str(base64.encodebytes (encrypt_aes), encoding = 'utf-8')
return encrypted_text
Here is the complete code, in case if anyone is still looking.
tested against:
python3.6
python3.8
** used pycryptodome
encrypt_aes.py
import hashlib
from Crypto.Cipher import AES
import base64
class AES_pkcs5:
def __init__(self,key:str, mode:AES.MODE_ECB=AES.MODE_ECB,block_size:int=16):
self.key = self.setKey(key)
self.mode = mode
self.block_size = block_size
def pad(self,byte_array:bytearray):
"""
pkcs5 padding
"""
pad_len = self.block_size - len(byte_array) % self.block_size
return byte_array + (bytes([pad_len]) * pad_len)
# pkcs5 - unpadding
def unpad(self,byte_array:bytearray):
return byte_array[:-ord(byte_array[-1:])]
def setKey(self,key:str):
# convert to bytes
key = key.encode('utf-8')
# get the sha1 method - for hashing
sha1 = hashlib.sha1
# and use digest and take the last 16 bytes
key = sha1(key).digest()[:16]
# now zero pad - just incase
key = key.zfill(16)
return key
def encrypt(self,message:str)->str:
# convert to bytes
byte_array = message.encode("UTF-8")
# pad the message - with pkcs5 style
padded = self.pad(byte_array)
# new instance of AES with encoded key
cipher = AES.new(self.key, AES.MODE_ECB)
# now encrypt the padded bytes
encrypted = cipher.encrypt(padded)
# base64 encode and convert back to string
return base64.b64encode(encrypted).decode('utf-8')
def decrypt(self,message:str)->str:
# convert the message to bytes
byte_array = message.encode("utf-8")
# base64 decode
message = base64.b64decode(byte_array)
# AES instance with the - setKey()
cipher= AES.new(self.key, AES.MODE_ECB)
# decrypt and decode
decrypted = cipher.decrypt(message).decode('utf-8')
# unpad - with pkcs5 style and return
return self.unpad(decrypted)
if __name__ == '__main__':
# message to encrypt
message = 'hello world'
secret_key = "65715AC165715AC165715AC165715AC1"
AES_pkcs5_obj = AES_pkcs5(secret_key)
encrypted_message = AES_pkcs5_obj.encrypt(message)
print(encrypted_message)
decrypted_message = AES_pkcs5_obj.decrypt(encrypted_message)
print(decrypted_message)
Output:
>>> python encrypt_aes.py
>>> PDhIFEVqLrJiZQC90FPHiQ== # encrypted message
>>> hello world # and the decrypted one
I had tested many already available codes but none of them gave exact encryption as java ones. So, this is combined of all the found blogs and early written code compatible with python2
PKCS 5 (or 7) padding is not adding 0 bytes, but adding a c byteswith valuec(where1 <= c <= 16) if you're c` bytes short of a block length multiple.
So if you already have a multiple of 16, add a full 16 bytes of value 16, and if your last block is 'stop' (4 bytes), we add 12 bytes with value 0xc (12 in hex) to fill up the block. Etc.
This way the receiver (after decryption of the final block) can check the last byte c and check if the value is 1 <= c <= 16 (if not, reject the decryption) and then check that the last c bytes indeed are all that same value, and then remove them from the decryption. This way the receiver does not have to guess how many bytes of the last block were only padding or really part of the plain text. It's unambiguous doing it the PKCS way.
I'll leave the coding up to you.
You can use aes-pkcs5 package. I'm the author, it uses cryptography package instead of outdated pycrypto used in others answers and is compatible with Python 3.7+.
You can install via pip:
pip install aes-pkcs5
The same code that you posted using aes-pkcs5:
from aes_pkcs5.algorithms.aes_ecb_pkcs5_padding import AESECBPKCS5Padding
key = "92oifgGh893*cj%7"
cipher = AESECBPKCS5Padding(key, "b64")
text = '{ "Message": "hello this is a plain text" , "user":"john.doe", "Email":"john.doe#example.com}'
encrypted_text = cipher.encrypt(text)
You can use a random string separated by a null byte for the padding to add a bit of randomness sometimes.
import random
import string
from Crypto.Cipher import AES
NULL_BYTE = '\x00'
def random_string(size: int) -> str:
return ''.join([
random.choice(string.printable) for _ in range(size)
])
def encode_aes(value: str, key: str) -> bytes:
cipher = AES.new(key[:32], AES.MODE_ECB)
mod = len(value) % cipher.block_size
padding = (cipher.block_size - mod) % cipher.block_size
if padding > 0:
value += NULL_BYTE + random_string(padding - 1)
return cipher.encrypt(value)
def decode_aes(value: bytes, key: str) -> str:
cipher = AES.new(key[:32], AES.MODE_ECB)
decrypted = cipher.decrypt(value).decode('utf8')
return decrypted.rsplit(NULL_BYTE, 1)[0]
I have a Reverse cypher code in python and I want to reverse it so that it decodes reversed strings:
Code:
message = text.get()
translated = (" ")
i = len(message) - 1
while i >= 0:
translated = translated + message[i]
i = i - 1
print(translated)
EDIT:
message = text.get()
translated = (" ")
i = len(message) - 1
while i >= 0:
translated = translated + message[i]
i = i - 1
print(translated)
# Creating a string
s = message
# Encoding the string into bytes
b = s.encode("UTF-8")
# Base32 Encode the bytes
e = base64.b32encode(b)
# Decoding the Base32 bytes to string
s1 = e.decode("UTF-8")
# Printing Base32 encoded string
print(s1)
messagebox.showinfo("Encrypted", s1)
def decrypt():
base64.b32decode(s1)
translated[::-1]
Above is the whole code with the Encrypt and Decrypt
You can use python slices
translated[::-1] # reverses the "translated"
e.g if you input "hello" it becomes olleh and if u want to reverse it again (decode) all you have to do is use splicing "olleh"[::-1] which gives hello
message = input("enter msg: ")
translated = (" ")
i = len(message) - 1
while i >= 0:
translated = translated + message[i]
i = i - 1
print("Encoded: ", translated)
print("Decoded: ", translated[::-1]) # decode it back to normal by reversing it
Result:
Encoded: albalb
Decoded: blabla
EDIT (op posted the full code in comments):
I believe this is what you're looking for.
#Encryption GUI
from tkinter import *
from tkinter import messagebox
import base64
"""
You have two functions right? one is `encrypt` and the other is `decrypt`.
Now variable `e` which contains the encypted msg it only visible to the scope of `encrypt` function.
Meaning that `decrypt` does not know that it exists at all.
"""
# a global variable to store
# both encrypt and decrypt will be able to see this variable
message = ""
#Sub-Routine
def encrypt():
# Tell python to find the global variable `message`
global message
# get input and reverse it using splice
# "blabla"[::-1] => "albalb"
message = text.get()[::-1]
# Encoding the message into bytes
message = message.encode("UTF-8")
# Base32 Encode the bytes
message = base64.b32encode(message)
# temporarily decode and print encrpyted msg
# decoding is to make it human-readable (it's only in this function, won't affect anything else)
e = message.decode("UTF-8")
messagebox.showinfo("Encrypted", e)
def decrypt():
# again, tell python to find the global variable
# we need it! it contains our secret message
global message
# decode message
message = base64.b32decode(message)
# finally print it
print("Decrypted", message[::-1].decode("UTF-8"))
#Main
root=Tk()
root.geometry("500x425")
root.title("HORIZON Encryption")
root.resizable(True,True)
root.configure(bg='gray95')
#Frame Heading
frame_heading=Frame(root)
frame_heading.grid(row=0,column=0,columnspan=3,padx=30,pady=5)
frame_entry=Frame(root)
frame_entry.grid(row=1,column=0,columnspan=3,padx=25,pady=10)
#Labels
Label(frame_heading,text="HORIZON Encryption").grid(row=0,column=0,padx=0,pady=5)
Label(frame_entry,text="Text: ").grid(row=0,column=0,padx=10,pady=10)
text=Entry(frame_entry,width=15,bg='white')
text.grid(row=0,column=1,padx=5,pady=5)
#Buttons
encrypt_button=Button(root,text="Encrypt",width=7,command=encrypt)
encrypt_button.grid(row=2,column=1,padx=0,pady=5)
decrypt_button=Button(root,text="Decrypt",width=7,command=decrypt)
decrypt_button.grid(row=2,column=2,padx=0,pady=5)
root.mainloop()
Result:
msg: test
Encrypted ORZWK5A=
Decrypted test
A more compact approach could be:
def reverse(mssg):
return mssg[::-1]
print reverse("hello")
Output:
>> "olleh"
I'm trying to create encrypt & decrypt functions using pyDES module.
Problem:
if I print the cipher text on the screen then copy it (CTRL+C) then put it as input for the decrypt() function I get the following exception:
ValueError: Invalid data length, data must be a multiple of 8 bytes
my code:
key = "12345678"
charset = "utf-8"
def encrypt():
msg = input("Enter message: ")
data = des(key, CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
cipherText = data.encrypt(msg.encode(charset))
print(cipherText)
def decrypt():
cipherText = input("Enter cipher text: ")
data = des(key, CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
decrypted = data.decrypt(cipherText).decode(charset)
print(decrypted)
While passing the cipherText directly to decrypt message (not by copying it manually from the screen) it works perfectly! like this:
key = "12345678"
charset = "utf-8"
msg = input("Enter message: ")
data = des(key, CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
cipherText = data.encrypt(msg.encode(charset))
print(cipherText)
decrypted = data.decrypt(cipherText).decode(charset)
print(decrypted)
fix/explanation would be much appreciated.
I am struggling with converting this piece of code into a module in where I can use an outside program to set the variables in this piece of code. How would I go about setting variables in one program and set them in another(to be used as a module) and get the results from said program into the first program.
Here is the code, any advice/help would be greatly appreciated.
import Crypto.Random
from Crypto.Cipher import AES
import hashlib
SALT_SIZE = 16
iterations = 64000
salt = 'h5eE0b814M'
password = 'fortytwo'
text = 'What do you mean'
padded_text = ''
ciphertext = ''
key = ''
ciphertext_with_salt = ''
def key_generation(password, salt, iterations):
global key
assert iterations > 0
key = password + salt
for i in range(iterations):
key = hashlib.sha256(key).digest()
print '\nKey: ' + key #Debug Print
return key
def pad_text(text, SALT_SIZE):
print '\nUnpadded Text: ' + text #Debug Print
global padded_text
extra_bytes = len(text) % SALT_SIZE
pad_size = SALT_SIZE - extra_bytes
pad = chr(pad_size) * pad_size
padded_text = text + pad
print '\nPadded Text: ' + padded_text #Debug Print
return padded_text
def encryption(text, password):
global ciphertext
global key
salt1 = Crypto.Random.get_random_bytes(SALT_SIZE)
cipher = AES.new(key, AES.MODE_ECB)
padded_plaintext = pad_text(text, SALT_SIZE)
ciphertext = cipher.encrypt(padded_text)
ciphertext_with_salt = salt + ciphertext
#debug script
print '\nSalt: ' + salt #Debug Print
print '\nEncrypted Text: ' + ciphertext #Debug Print
print '\nEncrypted Text with Salt: ' + ciphertext_with_salt #Debug Print
return ciphertext_with_salt
def decryption(ciphertext, password):
salt = ciphertext[0:SALT_SIZE]
ciphertext_sans_salt = ciphertext[SALT_SIZE:]
key = key_generation(password, salt, iterations)
cipher = AES.new(key, AES.MODE_ECB)
padded_plaintext = cipher.decrypt(ciphertext_sans_salt)
print '\nUnencrypted Text: ' + text #Debug Print
return text
key_generation(password, salt, iterations)
encryption(text, password)
decryption(ciphertext, password)
Simply put
if __name__ == '__main__':
Before your last 3 lines. Then you can import it like any other module and call functions with e.g. yourmodulename.encryption(text, password).
I am currently having an issue of not being able to decrypt the text provided after encryption. It returns:
Key: ンƚ!*!゙ᆱø}Qd`Dᆱd!Þxͦ}ᄚミᄀ>'U
Unpadded Text: Hello World
Padded Text: Hello World
Salt: h5eE0b814M
Encrypted Text: WxCž~¼!Ò]Cú´=P+
Encrypted Text with Salt: h5eE0b814MWxCž~¼!Ò]Cú´=P+
Key: ンƚ!*!゙ᆱø}Qd`Dᆱd!Þxͦ}ᄚミᄀ>'U
Unencrypted Text:
Where
Unencrypted Text:
Should be "Unencypted Text: Hello World"
Two programs are used in this, one a module and a master. You must run the master to run the module. Any adivce or help would be greatly appricated as I have been stuck for a while. Thank you for your time.
Here is the code:
Master.py
import Encryption as encrypt
#Place Holder Variables
SALT_SIZE = 16
padded_text = ''
ciphertext = ''
key = ''
ciphertext_with_salt = ''
#Adjustable Variables
text = "Hello World"
iterations = 62705
salt = 'h5eE0b814M'
password = 'pause232'
encrypt.key_generation(password, salt, iterations)
encrypt.encryption(text, password, SALT_SIZE, salt, iterations)
encrypt.decryption(ciphertext_with_salt, password, SALT_SIZE, salt, iterations)
Encryption.py
import Crypto.Random
from Crypto.Cipher import AES
import hashlib
#Key Generation(Used in encyption to create cipher)
def key_generation(password, salt, iterations):
global key
assert iterations > 0
key = password + salt #Combines [password] and [salt] to create a [key]
for i in range(iterations): #Hashes the [key]
key = hashlib.sha256(key).digest() #Using Sha256 it hashes the [key] based on amount of [iterations]
print '\nKey: ' + key #Debug Print
return key
#Text padding function to set text to a incerment of SALT_SIZE
def pad_text(text, SALT_SIZE):
print '\nUnpadded Text: ' + text #Debug Print
global padded_text
extra_bytes = len(text) % SALT_SIZE #Using the length of [text] it counts how many more characters is required to make an incerment of [SALT_SIZE]
pad_size = SALT_SIZE - extra_bytes #Subtracts the needed bytes from the [SALT_SIZE] and sets [pad_size] as the length of pading needed.
pad = chr(pad_size) * pad_size #Creates padding for the [text]
padded_text = text + pad #Adds the [pad] to the [text]
print '\nPadded Text: ' + padded_text #Debug Print
#Primary Encryption Function(using text and password)
def encryption(text, password, SALT_SIZE, salt, iterations):
global padded_text
global ciphertext
cipher = AES.new(key, AES.MODE_ECB)
padded_plaintext = pad_text(text, SALT_SIZE)
ciphertext = cipher.encrypt(padded_text)
ciphertext_with_salt = salt + ciphertext
#debug script
print '\nSalt: ' + salt #Debug Print
print '\nEncrypted Text: ' + ciphertext #Debug Print
print '\nEncrypted Text with Salt: ' + ciphertext_with_salt #Debug Print
return ciphertext_with_salt
#Primary Decryption Function(using the encrypted text and password)
def decryption(ciphertext_with_salt, password, SALT_SIZE, salt, iterations):
ciphertext_with_salt = ciphertext[SALT_SIZE:]
key = key_generation(password, salt, iterations)
cipher = AES.new(key, AES.MODE_ECB)
unencrypted_text = cipher.decrypt(ciphertext_with_salt)
print '\nUnencrypted Text: ' + unencrypted_text #Debug Print
return unencrypted_text
#Code to allow to use as outside module
if __name__ == '__main__':
key_generation(password, salt, iterations)
encryption(text, password, SALT_SIZE, salt, iterations)
decryption(ciphertext_with_salt, password, SALT_SIZE, salt, iterations)
You are transferring your ciphertext and key as strings. You should make sure that the bytes that make up the ciphertext and keys stay intact. If you want to transport them using character strings, please use either hexadecimal encoding or base 64. Hexadecimals are easier to read and check for length, base 64 is more efficient.
Note that the ciphertext will contain bytes with any value, including ones that are ASCII control characters (< 0x20) which also contain termination characters such as 0x00.