I'm trying to write an encryption/decryption program called P-Cypher in python (python-Cypher, rhymes with decypher). It uses the PyCrypto libraries to encode a file (using AES). Although I know Python, I do not know cryptography - I'm doing this because I thought it would be fun, so don't critique me on security.
This is how the program is supposed to work.
Asks for input file.
Asks whether you want it to encrypt or decrypt. (sets mode)
Asks for output file. Verifies it exists- if it does not, asks if you want it to create one.
Encrypts input file and tells you the key/Prompts you for the key, and decrypts the file with the key (Depending on mode)
Writes to output file.
Everything works except for number 4. (I know step 5 works as step 5 remains pretty much unchanged from the last stable version, v0.03d). On step 4 encoding, one of two things happen depending on which way I code it:
The thing successfully- YAY! encodes the file. However, the key it prints out is in the form of b'U\xxx\xxx\xxx\xxx\xxx' like that. When I enter it in step 4 decoding mode, with or without the b and 's, it doesn't work. So the program cannot decrypt the file, rendering half of my program useless.
I can use .decode(encoding) to turn it into a string. This is the method you see on the code below. However, here is this way's problem- no matter what encoding I use (ascii, ISO, windows-125x, EUR, Big5, utf-8, 16, and 32, etc...) there is always one or more bytes that the encoding cannot encode. And without encoding, there's no decoding, rendering the WHOLE program useless.
So I ask you for help. If you could figure out how to fix problem #1 or #2 (or maybe even both), I would be grateful.
CODE -- Updated
# P-Cypher-Dev
# Made in 2015 by Mateo Guynn
# v0.04d
# Using AES 16/32/64-bit encryption (Google standard)
# DEV VERSION: Possibly unstable, contains better code.
# Changelog:
"""
v0.02d
- Improved Caesar Cipher
- Added binary Cipher converter (fail)
-------------FILE BROKEN------------
"""
"""
v0.03d
- Added ability to create new output files
- Fixed code not quitting on abort
- DEL : binary Cipher converter
---------------STABLE---------------
"""
"""
v0.04d
- DEL : Caesar Cypher
- Added 16/32/64-byte AES encryption
- Binary and text now handled in same manner
-------------FILE BROKEN------------
(encryption works, decryption does not)
"""
"""
v0.05d
- Changed AES encryption to Google's way
- Fixed Key entry
"""
import os
import sys
from Crypto.Cipher import AES
from Crypto import Random
from Crypto.Util import randpool
import base64
import codecs
MAX_KEY_SIZE = 26 # Shows the number of available characters (26 in the alphabet)
#NOTES: Binary mode only works if the file is named binary.dat.
def getMode():
while True:
eOrD = input('\nDo you wish to encrypt or decrypt a message? ')
mode = eOrD.lower()
if mode in 'encrypt e decrypt d'.split():
return mode
else:
sys.exit('\nEnter either "encrypt" or "e" or "decrypt" or "d". Capital letters are allowed.\n')
def getMessage():
inputFile = open(input('\nPlease enter the name of the file you want to encrypt/decrypt. You may use relative or full paths. \nPlease, remember the file extension(s)! ')).read()
try:
print ('\nThe contents of the file are: \n%s\n' % inputFile)
return inputFile
except IOError as e:
sys.exit('Unable to open file (the file does not exist or P-Cypher does not have permission to view it).\n Aborting.')
except FileNotFoundError as e:
sys.exit('Unable to open file (the file does not exist or P-Cypher does not have permission to view it).\n Aborting.')
def getCipher(mode, message):
block_size = 16 # For AES, this is the only working value
key_size = 32 # Size of crypto key (possibly changes in getKey())
aesmode = AES.MODE_CBC # More secure mode
if mode[0] == 'e':
key_bytes = randpool.RandomPool(512).get_bytes(key_size)
open('decryption.key', 'wb+').write(key_bytes)
print('\nYour keyfile is: decryption.key\n')
pad = block_size - len(message) % block_size
data = message + pad * chr(pad)
iv_bytes = randpool.RandomPool(512).get_bytes(block_size)
encrypted_bytes = iv_bytes + AES.new(key_bytes,aesmode,iv_bytes).encrypt(data)
encrypted = base64.urlsafe_b64encode(encrypted_bytes)
return encrypted
else:
decryptb = base64.urlsafe_b64decode(message)
decrypted_ivbytes = decryptb[:block_size]
decrypt = decryptb[block_size:]
print('\nAuto-searching for decryption.key...')
try:
key_bytes = base64.urlsafe_b64decode(open('decryption.key', 'rb').read())
except IOError as io:
key_bytes = base64.urlsafe_b64decode(open(input('decryption.key not found. If you have an alternate keyfile, please enter its name now. ')), 'rb').read
except FileNotFoundError as fnf:
key_bytes = base64.urlsafe_b64decode(open(input('decryption.key not found. If you have an alternate keyfile, please enter its name now. '), 'rb').read())
decrypted = AES.new(key_bytes, aesmode, decrypted_ivbytes).decrypt(decryptb)
pad = ord(decrypted[-1])
decrypted = decrypted[:-pad]
return decrypted
def getOutput():
outputFile = input('\nPlease specify an output file. \nDon\'t forget the file extension! ')
outputCheck = input('\nYour message will be encrypted/decrypted into the following output file: %s\n\nIs this okay? (y/n) ' % outputFile).lower()
if outputCheck in 'y yes yeah ok'.split():
try:
return outputFile
except IOError as ioerror:
createNewFile = input('The file you specified does not exist. Shall I create one? (y/n) ')
if createNewFile in 'y_yes_yeah_yes please_ok'.split('_'):
oF = open(outputFile, 'w+')
oF.close()
return outputFile
else:
sys.exit('Aborting...')
elif outputCheck in 'n no'.split():
sys.exit('\nAborting...\n')
else:
sys.exit('\nAborting.\n')
print("\nP-Cypher Alpha starting up...\n\nv0.05 dev\nMateo Guynn\n2015\n")
mode = getMode()
message = getMessage()
try:
open(getOutput(), 'wb+').write(getCipher(mode,message))
except IOError:
sys.exit('Oh noes! Something has gone terribly wrong!')
except FileNotFoundError:
sys.exit('Your input file was not found.')
print('\nDone.')
one solution is to encode it as hex ... this is guaranteed to be ascii characters
import codecs
my_key = "U\x22\x54\x33"
print ("Your Key:", codecs.encode(my_key,"hex"))
...
my_decode_key = codecs.decode(input("enter key:"),"hex")
print( repr(my_decode_key))
print( my_decode_key == my_key )
Related
I am trying to do a P2MS script.
For my script, I am saving the keys into a text file with DER format instead of the usual PEM file. Both key and signatures are saved in a text file and hexlify. Below is my code for the P2MS execution.
from Crypto.PublicKey import DSA
from Crypto.Hash import SHA256
from Crypto.Signature import DSS
from binascii import hexlify, unhexlify
import binascii
message = b"helpsmepls"
# Read scriptPubKey and scriptSig from files
with open('scriptPubKey.txt', 'r') as f:
readscriptPubKey = f.read().strip()
with open('scriptSig.txt', 'r') as f:
scriptSig = f.read().strip()
print(type(readscriptPubKey))
tempholder = readscriptPubKey.split()
# Removing the first character and last character
removeend = tempholder[1:-1]
scriptPubKey = []
# Removing front extra headings
for count, x in enumerate(removeend):
w = bytes(removeend[count][1:-1], encoding = 'utf-8')
#print(w)
scriptPubKey.append(w)
# Splitting the Signatures
signatures = scriptSig.split()
hash_obj = SHA256.new(message)
# Going through the pubkeys based on the number of signatures generated
for o, sig in enumerate(signatures):
pub_key = DSA.import_key(bytes.fromhex(scriptPubKey[o].decode("utf-8")))
hash_obj = SHA256.new(message)
verifier = DSS.new(pub_key, 'fips-183-3')
# Verifying if the Public key and signatures match, loop will break if False is encountered
if verifier.verify(hash_obj, sig):
d = True
else:
d = False
break
break
if d == True:
print("The message is authentic.")
else: print("The message is not authentic.")
Unfortunately before my code can reach the verification, it encountered an error.
Full traceback
It seems my DSA key format has an error, but I am not too sure why is it giving me that error.
I have also tried unhexlifying my input from the public key text file, but it also did not work. I have tried to hex decode the input to get the DER format of the input, but my type is still just bytes. I am not so sure how to properly import the key with the appropriate DSA key format from a txt file. I am able to do that with a PEM file but would just like to find out how to execute it with a txt file.
My expected outcome is the DSA key is imported properly and i am able to verify the public key with the signatures.
I'm attempting to read text from a file and decrypt it using the Fernet cryptography library in Python. So i'm running a For loop which prints all of the text, while it does that I attempt to make the loop decrypt.
from cryptography.fernet import Fernet
from inspect import currentframe
key = "kdQGjocgILOLXj6k_mkkOJOxHxXJji7kdRUTtrGZBTo="
f = Fernet(key)
def get_linenumber():
cf = currentframe()
return cf.f_back.f_lineno
def Main():
choice = input("1. Write Raw Data To File For Encryption\n2. Read Data From File For Decryption\n\nEnter Option Here: ")
if choice == "1":
print("Init Main Successfull On Line ", get_linenumber())
File = open(r"D:\Visual Studio Projects\Python Proj\Secure Note Storage Project\File.txt",mode="a")
FileToEncrypt = bytes(input("Input data to encrypt, Note it will be stored as a string, then heavily encrypted with SHA-256.\n"),'utf-8')
print("\nSuccesfully printed File To Encrypt data on line ",get_linenumber,"\nData From FileToEncrypt Var: ",FileToEncrypt)
FileEncrypted = f.encrypt(FileToEncrypt)
print("\n\n\Here is the final product: ",FileEncrypted)
EncryptionDescription = input("What Is The Data Entered. (Explain For Future Reference!!!)\n\nEnter Here: ")
File.write(f"{EncryptionDescription}\n" + str(FileEncrypted))
File.close()
elif choice == "2":
print("\n\nYou Have Chosen Decryption Method!\n")
File = open(r"D:\Visual Studio Projects\Python Proj\Secure Note Storage Project\File.txt",mode="r")
for line in File:
name = line.strip()
num = File.readline()
num = Fernet.decrypt(f,num)
print (num)
else:
print("Sorry, We Do Not Recognise What You Have Entered. Please look at the options and think...")
exit(0)
###Debug Shit
#print(Fernet.generate_key()) # so i can find one key and keep it static:)
# print(File.read())
# print("File Print Successfull On Line ", get_linenumber())
# File.write("\nRawrar")
if __name__ == "__main__":
Main()
I tried printing the data from the file, then when that worked. I attempted to convert the Num Variable to a decrypted version of the encrypted text. When that didn't work I messed with the parameters a bit. But I got no where, not to sure what Im doing.
The first problem in this case seems to be the fact that you correctly convert FileToEncrypt into bytes for encryption, but when you save it you simply cast it as a string using str(). What you want to do instead is use .decode()
Furthemore you'd probably want to add another linebreak when you write the data to the file. Otherwise you will face issues if you append multiple times to the same file
File.write(f"{EncryptionDescription}\n" + FileEncrypted + "\n") You'd also want to make sure that when loading this data that you convert it to bytes again using bytes(str, 'utf-8').
Now that your data is properly saved into the File.txt file, you are now ready to decode the data. However you will still face an error as you do not pass a timestamp in the decrypt function call, as per the documentation. Essentially I found two ways to do this. One would simply be to call the function with a very high number as the ttl paramater like this: print(Fernet.decrypt(f,bytes(num, "utf-8"), 1000000))
The proper way to do this is to use the function extract_timestamp() as per the documentation. I implemented it like this encryptionTimeStamp = Fernet.extract_timestamp(f, bytes(num, 'utf-8')) with success.
Doing this will get you the unix timestamp at the time of encryption. The ttl parameter is the number of seconds since encryption, you'd want to take the "current unix timestamp - unix timestamp at encryption" and pass that as the ttlparameter.
from cryptography.fernet import Fernet
from inspect import currentframe
import time
key = "kdQGjocgILOLXj6k_mkkOJOxHxXJji7kdRUTtrGZBTo="
f = Fernet(key)
def get_linenumber():
cf = currentframe()
return cf.f_back.f_lineno
def Main():
choice = input("1. Write Raw Data To File For Encryption\n2. Read Data From File For Decryption\n\nEnter Option Here: ")
if choice == "1":
print("Init Main Successfull On Line ", get_linenumber())
File = open(r"File.txt",mode="a")
FileToEncrypt = bytes(input("Input data to encrypt, Note it will be stored as a string, then heavily encrypted with SHA-256.\n"),'utf-8')
print("\nSuccesfully printed File To Encrypt data on line ",get_linenumber,"\nData From FileToEncrypt Var: ",FileToEncrypt)
FileEncrypted = f.encrypt(FileToEncrypt)
FileEncrypted = FileEncrypted.decode()
print("\n\n\Here is the final product: ",FileEncrypted)
EncryptionDescription = input("What Is The Data Entered. (Explain For Future Reference!!!)\n\nEnter Here: ")
File.write(f"{EncryptionDescription}\n" + FileEncrypted + "\n")
File.close()
elif choice == "2":
print("\n\nYou Have Chosen Decryption Method!\n")
File = open(r"File.txt",mode="r")
for line in File:
name = line.strip()
num = File.readline()
numBytes = bytes(num, 'utf-8')
encryptionTimeStamp = Fernet.extract_timestamp(f, numBytes)
currentTime = int(time.time())
timeElapsed = currentTime - encryptionTimeStamp
print( Fernet.decrypt(f,numBytes, timeElapsed))
else:
print("Sorry, We Do Not Recognise What You Have Entered. Please look at the options and think...")
exit(0)
###Debug Shit
#print(Fernet.generate_key()) # so i can find one key and keep it static:)
# print(File.read())
# print("File Print Successfull On Line ", get_linenumber())
# File.write("\nRawrar")
if __name__ == "__main__":
Main()
I am experimenting with Fernet from Cryptography module in Python and encountered certain heavy terms I was not able to understand, despite clear and good documentation of the Cryptography library.
My question is: how does a fernet key works exactly, and how do I use my own passwords as key to fernet class? And how do I store this derived key such that if it is compromised to an attacker, it is hard for the attacker to break it into its original pass phrase?
What I have tried so far :
class Main():
def __init__(self):
print("Running Sequences")
def lock_dir(self, dirc, pwd, zip_name, zip_pwd):#taking directory to lock , the password for fernet , the password for zip and name for the zip
#declaring all arguments in variables
self.dirc = dirc
self.pwd = pwd
self.zip_name = zip_name
self.zip_pwd = zip_pwd
#a separate path for key to be written
self.key_dirc = self.dirc + "\\key.txt"
# generating a key from the password
self.pwd_bytes = self.pwd.encode()
self.salt = os.urandom(16) #generating salt
self.kdf = Scrypt(salt = self.salt, length = 32, n = 2**20, r = 8, p = 1)
self.key = base64.urlsafe_b64encode(self.kdf.derive(self.pwd_bytes))
self.fernet_object = Fernet(self.key)
#traversing through the directory provided by the user
for files in os.listdir(self.dirc):
with open(os.path.join(self.dirc, files), "rb") as file:
self.file_data = file.read()
file.close()
encrypted_data = self.fernet_object.encrypt(self.file_data)
with open(os.path.join(self.dirc, files), "wb") as file:
file.write(encrypted_data)
file.close()
with open(self.key_dirc, "wb") as hash_file:
hash_file.write(self.key)
hash_file.close()
Now , another question is that would the attacker will be able to use this key.txt as a key to directly decrypt the data encrypted through it, compromising all efforts at vain or will this key.txt will be needed to derived again into a key to decrypt the data ?
Thank you
Here are some encryption and decryption functions that I created for a python key management library I am writing.
def generate_RSA():
bits = 2048
new_key = RSA.generate(bits)
public_key = new_key.publickey()
private_key = new_key
return private_key, public_key
def encrypt_data(in_fd, chunk_size, pub_key):
encryptor = PKCS1_OAEP.new(pub_key)
A = list()
with open(in_fd, 'rb') as in_file:
while True:
chunk = in_file.read(chunk_size)
if len(chunk) == 0:
break
elif len(chunk) % 16 != 0:
chunk += b' ' * (16 - len(chunk) % 16)
encrypted_file = encryptor.encrypt(chunk)
return encrypted_file
def decrypt_data(in_fd, chunk_size, priv_key):
decryptor = PKCS1_OAEP.new(priv_key)
with open(in_fd, 'rb') as in_file:
while True:
chunk = in_file.read(chunk_size)
if len(chunk) == 0:
break
decrypted_file = decryptor.decrypt(eval(str(chunk)))
return decrypted_file
I wanted to be able to insert the encrypt_data and decrypt_data into each other as the first arguments if need be. However I am running into a problem.
priv_key, pub_key = generate_RSA()
print(decrypt_data(encrypt_data('C:\\Users\cowbo\OneDrive\Documents\EWC\Haiku.txt', 8192, pub_key), 8192, priv_key))
Whenever I try to run the last line of code, I get the following traceback...
Traceback (most recent call last):
File "C:\Users\cowbo\source\repos\Python Practice\PythonPractice\FileCounter.py", line 57, in <module>
print(decrypt_data(encrypt_data('C:\\Users\cowbo\OneDrive\Documents\EWC\Haiku.txt', 8192, pub_key), 8192, priv_key))
File "C:\Users\cowbo\source\repos\Python Practice\Python Practice\FileCounter.py", line 31, in decrypt_data
with open(in_fd, 'rb') as in_file:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfd in position 1: invalid start byte
I have looked at other post on here concerning this same issue and I seem to encrypting and decrypting correctly so Im not sure what the issue is.
You are passing the result from encrypt_data() directly to decrypt_data():
print(decrypt_data(encrypt_data(...))
encrypt_data() returns the encrypted data, not a filename:
encrypted_file = encryptor.encrypt(chunk)
return encrypted_file
(You are only producing the last chunk of encrypted data there, not all of it, but that’s not the cause of this error).
decrypt_data() doesn’t accept encrypted data however. It accepts a filename:
def decrypt_data(in_fd, chunk_size, priv_key):
# ...
with open(in_fd, 'rb') as in_file:
What threw me at first was that on anything but Windows that’ll give you a “file not found” error, but on Windows, a binary value for a file path will first be decoded as UTF-8, and that fails for the encrypted data.
To fix this, you have three options:
Have the encryption function open a new file, write the encrypted data to that file and return the filename instead of the encrypted data. Then you at least pass on the correct information to the decryption function.
Create the file for the encrypted data the encrypted data the encryption function returns at the point where you call the encryption function. Don’t pass the result directly to the decryption function, pass the filename.
Change the decryption function to accept the data directly and not read it from a file.
As a side note, in the decryption function you use:
decryptor.decrypt(eval(str(chunk)))
That's... a rather odd way of passing chunk directly to the decryption function. This is enough:
decryptor.decrypt(chunk)
chunk is a bytes object, str(bytesvalue) gives you "b'...'" (where b' at the start and ' at the end are now part of the string) and eval() gives you the original bytesvalue again. Just pass the original in, no need to waste cycles there.
So I'm a Python n00b and I'm trying to hack on this script to create an end-point encryption tool. Basically, the script takes raw_input and uses a 16 digit string to encode it using AES. In order to decrypt that message, you need to manually paste the encoded text in there, followed by the key. Is there a way to pull the text in from a file and then output the encoded text to a different file?
Here's what I have thus far:
from Crypto.Cipher import AES
import string
import base64
import time
#import modules
PADDING = '{'
BLOCK_SIZE = 32
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
#prepare crypto method
EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)
#set encryption/decryption variables
loop=5
while loop==5:
#set up loop, so the program can be rerun again if desired without restarting
option=raw_input("Would You Like to Encrypt Or Decrypt Text?\nEncrypt: a\nDecrypt: b\n")
if option=='a':
letter=3
while letter==3:
secret = raw_input("Please Enter An Encryption Key {must be 16 characters long}: ")
countTotal= (len(secret))
if countTotal==16:
cipher = AES.new(secret)
letter=0
else:
print "Please Ensure The Key You Entered Is 16 Characters In Length\n"
letter=3
#this checks the encryption key to ensure it matches the correct length
# encode a string
data=raw_input("Please Enter Text You'd Like Encrypted: ")
encoded = EncodeAES(cipher, data)
print 'Encrypted string:', encoded
options=raw_input("Would You Like To Encrypt/Decrypt Again? Y/N\n")
if options=='y':
loop=5
if options=='n':
loop=0
if option=='b':
encoded=raw_input("Please Enter The Encoded String:\n")
letter=3
while letter==3:
secret=raw_input("Please Enter The Decryption Key:\n")
countTotal= (len(secret))
#this checks the encryption key to ensure it matches the correct length
if countTotal==16:
cipher = AES.new(secret)
letter=0
decoded = DecodeAES(cipher, encoded)
print 'Decrypted string:', decoded
options=raw_input("Would You Like To Encrypt/Decrypt Again? Y/N\n")
if options=='y':
loop=5
if options=='n':
loop=0
else:
print "Please Ensure The Key You Entered Is 16 Characters In Length\n"
letter=3
if loop==0:
print "Goodbye!!"
time.sleep(2)
exit
#exits the program if desired by user
You could open a specific file with open('filename.extension', 'r/w/...'). Then you could go through the file's content with read(), readline() or readlines(). To write to a file, simply open a file like this:
f = open('filename.txt', 'w') #make new file (open for write)
f.write('This is a test\n') #write to that file
for more info on reading and writing see: https://docs.python.org/2/tutorial/inputoutput.html