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.
Related
I am trying to send an encrypted file over TCP sockets in python, I don't want to have to encrypt the message, save it in %TEMP% and then send it (it could fill up hard drive space).
I am following this code I found online at: https://gist.github.com/giefko/2fa22e01ff98e72a5be2
Here is my server code:
from random import choice
import socket, os, threading, json
from cryptography.fernet import Fernet
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPWRSTUVWXYZ1234567890!##$%^&*()"
#read the key or generate
key = b""
if os.path.exists("client.key"):
with open("client.key", "rb") as f:
key = f.read()
else:
with open("client.key", "wb") as f:
key = Fernet.generate_key()
f.write(key)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
port = 34467
host = "0.0.0.0"
s.bind((host, port))
print(f"LISTENING ON {host}:{port}")
s.listen(100)
def new_salt():
salt = ""
for x in range(15):
salt += choice(chars)
return salt
def handle_client(conn, addr):
encryption = False
def send_raw(content_type, Bytes_, salt=new_salt()):
seperator = "<|SEPERATE|>"
to_send = content_type + seperator + Bytes_.decode() + seperator + salt
to_send = to_send.encode()
if encryption:
to_send = Fernet(key).encrypt(to_send)
conn.send(to_send)
def recv_raw(BufferSize):
seperator = "<|SEPERATE|>".encode()
data = b""
while True:
data = conn.recv(BufferSize)
if data: break
if encryption:
data = Fernet(key).decrypt(data)
splitted = data.decode().split(seperator.decode())
content_type = splitted[0]
Bytes_ = splitted[1].encode()
salt = splitted[2]
return {"content_type": content_type, "bytes": Bytes_}
print("NEW CLIENT AT IP: " + str(addr[0]))
print("EXTANGING KEY")
send_raw("KEY", key)
client_key = recv_raw(1024)["bytes"]
if key == client_key:
print("KEY EXTANGE VERIFIED")
else:
print("UNABLE TO VERIFY, CLIENT MAY EXPERIENCE ISSUES")
print(key)
print(client_key)
encryption = True
print("GRAPPING SYSTEM INFO...")
sys_info_request = recv_raw(1024)
print("RECIVED, DECODING...")
sys_info = json.loads(sys_info_request["bytes"].decode())
print("BASIC INFO:")
print("Platoform: " + sys_info["platform"])
print("Architecture: " + str(sys_info["architecture"]))
print("Username: " + sys_info["username"])
if os.path.exists("autorun.txt"):
with open("autorun.txt", "r") as f:
print("FOUND AUTORUN, EXECUTING COMMANDS")
for line in f.readlines():
print("> " + line)
send_raw("command", line.encode())
output = recv_raw(1024)
print(output["bytes"].decode())
current_dir = sys_info["current_dir"]
while True:
try:
cmd = input(current_dir + "> " + sys_info["username"] + " $ ")
if cmd == "abort":
send_raw("abort", "".encode())
conn.close()
print("SAFE")
break
if cmd == "send_file":
# CODE GOES HERE
send_raw("command", cmd.encode())
output = recv_raw(1024)["bytes"].decode()
print(output)
except:
print("UNEXCPECTED ERROR")
while True:
conn, addr = s.accept()
threading.Thread(target=handle_client, args=(conn,addr,)).start()
I haven't found anything online that will work in my senario.
Okay, so you want to open a file, encrypt it and send it and avoid writing a tempfile to the hard disc, right? This works (taken from the example server code you linked):
while True:
conn, addr = s.accept() # Establish connection with client.
print('Got connection from', addr)
data = conn.recv(1024)
print('Server received', repr(data))
from cryptography.fernet import Fernet
key = Fernet.generate_key()
ff = Fernet(key)
filename='crs.py' #In the same folder or path is this file running must the file you want to tranfser to be
f = open(filename,'rb')
l = f.read(1024)
while (l):
enc = ff.encrypt(l)
conn.send(enc)
print('Sent ',repr(enc))
l = f.read(1024)
f.close()
print('Done sending')
conn.send(b'Thank you for connecting')
conn.close()
So, I am just opening the file, reading it 1024 bytes a time, encrypting it and then sending it along .. Does that answer your question?
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
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
When I start the program to share files to client it received it but when i request for another file download it failed with this error.
Now i keep getting this error from the client
socket1.send(bytes('0', 'UTF-8'))
BrokenPipeError: [Errno 32] Broken pipe
line 46 client.py
I tried breaking out of the server's filedownload loop but still not working.
server
#! /usr/bin/env python3
import socket
import sys
import os
import hashlib
import time
HOST = 127.0.0.1
PORT = 5000
c = 0 #used to count cycles
bufsize = 4096
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
print('Server Created')
except OSError as e:
print('Failed to create socket. Error Code : ' + str(msg[0]) + ' Message ' + msg[1])
sys.exit()
try:
s.bind((HOST, PORT))
except OSError as e:
print('Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1])
sys.exit()
print('Socket bind complete')
s.listen(1)
print('Server now listening')
while 1:
conn, addr = s.accept()
print('Connected with ' + addr[0] + ':' + str(addr[1]))
reqCommand = conn.recv(1024).decode("utf-8", errors='ignore')
print('Client> %s' % reqCommand)
string = reqCommand.split(' ', 1)
if reqCommand == 'quit':
break
elif reqCommand == 'lls':
toSend = ""
path = os.getcwd()
dirs = os.listdir(path)
for f in dirs:
toSend = toSend + f + ' '
conn.send(toSend.encode('utf-8'))
# print path
else:
string = reqCommand.split(' ', 1) # in case of 'put' and 'get' method
if len(string) > 1:
reqFile = string[1]
if string[0] == 'FileDownload':
with open(reqFile, 'rb') as file_to_send1:
# get the entire filesize, which sets the read sector to EOF
file_size = len(file_to_send1.read())
# reset the read file sector to the start of the file
file_to_send1.seek(0)
# take filesize and write it to a temp file
with open('temp01',mode='w', encoding='UTF-8') as file_to_send2:
file_to_send2.write(str(file_size))
# pass the file size over to client in a small info chunk
with open('temp01', 'rb') as file_to_send3:
conn.send(file_to_send3.read(1024))
#send the total file size off the client
while (c*bufsize) < file_size:
send_data = file_to_send1.read(bufsize)
conn.send(send_data)
c += 1
# get bool (0 is bad | 1 is good) from client
chunk_write_flag = int(conn.recv(1024))
while chunk_write_flag != 1: #while whole data was not sent..retry until successful
conn.send(send_data)
#get status from client after a retry
chunk_write_flag = int(conn.recv(1024))
# used on the last chunk of the file xfer
# if the file.read() is less than buffer size do last tasks
if (file_size - (c*bufsize)) < bufsize:
send_data = file_to_send1.read(bufsize)
conn.send(send_data)
file_to_send1.close()
break
#for data in file_to_send:
#conn.sendall(data)
print('Send Successful')
conn.close()
s.close()
client
#! /usr/bin/env python3
import socket
import sys
import os
import hashlib
import time
HOST = 127.0.0.1
PORT = 5000
c = 0
bufsize = 4096
def get(commandName):
socket1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket1.connect((HOST, PORT))
socket1.send(commandName.encode("utf-8"))
string = commandName.split(' ', 1)
inputFile = string[1]
c = 0
# before starting to write new file, get file size
file_size = int(socket1.recv(1024)) # from file_to_send3
# print (file_size)
# set byte buffer size
bufsize = 4096
# start writing at the beginning and use following variable to track
write_sectors = 0
# this only opens the file, the while loop controls when to close
with open(inputFile, 'wb+') as file_to_write:
# while written bytes to out is less than file_size
while write_sectors < file_size:
# write the BUFSIZE while the write_sector is less than file_size
file_to_write.write(socket1.recv(bufsize))
c += 1
with open(inputFile, 'rb') as verify:
write_check = (len(verify.read()) / c)
verify.seek(0) # read cycle moves seek location, reset it
while write_check != bufsize:
# where the original write started, to send back to server
if c > 1: file_to_write.seek((c-1) * bufsize)
if c == 1: file_to_write.seek(0)
# send to server that the write was not successful
socket1.send(bytes('0', 'UTF-8'))
file_to_write.write(socket1.recv(bufsize))
write_check = int(len(verify.read()) /c )
# if last packet, smaller than bufsize
socket1.send(bytes('1', 'UTF-8')) #send SUCCESS back to server
if (file_size - (write_check * c)) < bufsize:
#file_to_write.write(socket1.recv(bufsize))
verify.close()
#file_to_write.close()
file_size = 0
write_sectors += bufsize # successful write, move 'while' check
# add the written sectors by the bufsize.
# example if filesize in bytes is 4096 you need to track how much
# was written to figure out where the EOF is
file_to_write.write(socket1.recv(bufsize)) # write the last chunk missed by while loop
#data = socket1.recv(4096).decode("utf-8", errors="ignore")
#if not data: break
#break
# print data
#file_to_write.write(bytes(data.encode()))
#file_to_write.close()
print('Download Successful')
socket1.close()
return
def serverList(commandName):
socket1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket1.connect((HOST, PORT))
socket1.send(commandName.encode('utf-8'))
fileStr = socket1.recv(1024)
fileList = fileStr.decode('utf-8').split(' ')
for f in fileList:
print(f)
socket1.close()
return
msg = input('Enter your name: ')
while 1:
print("\n")
print('"FileDownload [filename]" to download the file from the server ')
print('"lls" to list all files in the server')
sys.stdout.write('%s> ' % msg)
inputCommand = sys.stdin.readline().strip()
if inputCommand == 'lls':
serverList('lls')
else:
string = inputCommand.split(' ', 1)
if string[0] == 'FileDownload':
Please can anyone help me,i don't know to fix it. I'll appreciate any help.
Thanks
Server.py
class BufferedReceiver():
def __init__(self, sock):
self.sock = sock
self.buffer = ""
self.bufferPos = 0
def _fetch(self):
while self.bufferPos >= len(self.buffer):
self.buffer = self.sock.recv(1024)
# print(self.buffer)
self.bufferPos = 0
def take(self, amount):
result = bytearray()
while(len(result) < amount):
# Fetch new data if necessary
self._fetch()
result.append(self.buffer[self.bufferPos])
self.bufferPos += 1
return bytes(result)
def take_until(self, ch):
result = bytearray()
while True:
# Fetch new data if necessary
self._fetch()
nextByte = self.buffer[self.bufferPos]
self.bufferPos += 1
result.append(nextByte)
if bytes([nextByte]) == ch:
break
return bytes(result)
Then, I simplified your server send routine after the else::
string = reqCommand.split(' ', 1) # in case of 'put' and 'get' method
if len(string) > 1:
reqFile = string[1]
if string[0] == 'FileDownload':
with open(reqFile, 'rb') as file_to_send1:
# get the entire filesize, which sets the read sector to EOF
file_size = len(file_to_send1.read())
# reset the read file sector to the start of the file
file_to_send1.seek(0)
# pass the file size over to client in a small info chunk
print('Filesize:', file_size)
conn.send((str(file_size)+'\n').encode())
#send the total file size off the client
c = 0
while (c*bufsize) < file_size:
send_data = file_to_send1.read(bufsize)
conn.send(send_data)
c += 1
print('Send Successful')
Client.py
def get(commandName):
socket1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket1.connect((HOST, PORT))
socket1.send(commandName.encode("utf-8"))
receiver = BufferedReceiver(socket1)
string = commandName.split(' ', 1)
inputFile = string[1]
# before starting to write new file, get file size
file_size = int(receiver.take_until(b'\n').decode().strip()) # from file_to_send3
print ('Filesize:', file_size)
# set byte buffer size
bufsize = 4096
# this only opens the file, the while loop controls when to close
with open(inputFile, 'wb+') as file_to_write:
# while written bytes to out is less than file_size
c = 0
while True:
# Compute how much bytes we have left to receive
bytes_left = file_size - bufsize * c
# If we are almost done, do the final iteration
if bytes_left <= bufsize:
file_to_write.write(receiver.take(bytes_left))
break
# Otherwise, just continue receiving
file_to_write.write(receiver.take(bufsize))
c += 1
#TODO open file again, verify.
# Generate MD5 on server while sending. Then, send MD5 to client.
# Open finished file in client again and compare MD5s
print('Download Successful')
socket1.close()
return
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)