Python Control Server – File Transfer and Encryption (4 of 8)
What’s up guys?
In this part we’ll be implementing file transfer and encryption.
I use these programs on my own system and you absolutely have to be able to download and upload files in order to get anything done.
Now some of you might remember in part three I mentioned that our encrypted channel wasn’t stable enough to handle several megabytes of data without any mishaps.
Because of that, I had to implement file encryption and decryption in the client as well, since we’re already working with pyAesCrypt anyway.
This allows us to, at the very least, encrypt files locally before sending them over a standard tcp tunnel – or keep them encrypted on the system.
Like much of the functionality we’re going through here, these functions could be copied and used in other code without much hassle.
I’ve already made some posts regarding file encryption using pyAesCrypt in the blog, most notably: recursive file encryption in Python 3.
I recommend to check that one out if you haven’t seen it yet.
In any case, file encryption with pyAesCrypt is pretty straightforward. We are basically working with the following methods:
pyAesCrypt.encryptFile(“file.txt”, “file.txt.aes”, password, bufferSize)
pyAesCrypt.decryptFile(“file.txt.aes”, “file.txt”, password, bufferSize)
The passwords have to match of course and the files in and out need to be in the correct order, so plain file in for encryption first; while for decryption, we have the encrypted file in first.
Dive Into The Code
Let’s take a look at the functions being used for encryption:
# Encrypt file def encryptFile(password, file): if len(file) < 1 or len(password) < 1 or not os.path.isfile(file): return '> Enter correct file/password.\n' newfile = file + '.aes' bufferSize = 64 * 1024 try: pyAesCrypt.encryptFile(file, newfile, password, bufferSize) return '> Encrypted: ' + newfile + '\n' except: return '> Error while encrypting, try again.\n'
As you can see most of the code is checking for errors from the user – things like typos in the filename and incorrect password. Once we’ve checked it all, we go ahead and run the encryptFile method.
# Decrypt file def decryptFile(password, file): if len(file) < 1 or len(password) < 1 or not os.path.isfile(file): return '> Enter correct file/password.\n' try: newfile = os.path.splitext(file) except: newfile = 'decrypted.' + file bufferSize = 64 * 1024 try: pyAesCrypt.decryptFile(file, newfile, password, bufferSize) return '> Decrypted: ' + newfile + '\n' except: return '> Error while decrypting, try again.\n'
The function for decryption is quite similar, we do attempt to check if there is an encryption extension to remove using splitext on the file.
Both arguments are the same: password and file. Again, if we have any errors we’ll return that message back to the user.
I was contemplating adding a os.remove(file) line in there to remove the file leftover, but since we have terminal access, we can just do that after.
# Send file def sendFile(sock, file): try: with open(file, 'rb') as f: fileData = f.read() # Begin sending file sock.sendall(fileData) time.sleep(4) sock.send('EOFX'.encode()) f.close() return '> Download: ' + file + ' complete.\n' except: return '> Error downloading file: ' + file + '.\n'
This is the code we’re using to transfer the files over. We open the desired file as a binary (read-only) and go through its content.
Then send it all through to the other side, pause for a few seconds and send the end of file delimiter so the server knows we are done transferring.
Now to receive the file on the server side:
g = open(os.path.basename(decrypted[7:]), 'wb') s.settimeout(60) while True: l = s.recv(1024) try: if l.decode().endswith('EOFX') == True: break except: pass g.write(l) g.close()
We open the file with write mode on and set a 60 second timeout – in case we have any issues, we’ll get a response back in a minute.
Then we’re simply receiving the data and writing it to file until we receive the end of file delimiter characters.
All of this code can be adapted into different scripts with minor tweaks.
For further understanding, download and peep it below:
Just make sure to change the IP address on the client and that’s it.
Little by little we’re moving on with the functionality, but that’s gonna do it for today. We’ll be back for more in a few days! 😉