Update Picocrypt.py

This commit is contained in:
Evan Su 2021-03-22 20:51:53 -04:00 committed by GitHub
parent 5b71a4dccc
commit ff5c7ce603
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 97 additions and 101 deletions

View File

@ -56,9 +56,9 @@ kept = False
working = False working = False
gMode = None gMode = None
headerRsc = None headerRsc = None
draggedFiles = False allFiles = False
draggedFolderPaths = False draggedFolderPaths = False
filesToErase = False files = False
adString = "File metadata (used to store some text along with the file):" adString = "File metadata (used to store some text along with the file):"
compressingNotice = "Compressing files together..." compressingNotice = "Compressing files together..."
passwordNotice = "Error. The provided password is incorrect." passwordNotice = "Error. The provided password is incorrect."
@ -96,29 +96,20 @@ s = tkinter.ttk.Style()
s.configure("TCheckbutton",background="#f5f6f7") s.configure("TCheckbutton",background="#f5f6f7")
# Event when user selects an input file # Event when user selects an input file
def inputSelected(draggedFile=None): def inputSelected(draggedFile):
global inputFile,working,headerRsc,draggedFiles global inputFile,working,headerRsc,allFiles
global draggedFolderPaths,filesToErase global draggedFolderPaths,files
dummy.focus() dummy.focus()
status.config(cursor="") status.config(cursor="")
status.bind("<Button-1>",lambda e:None) status.bind("<Button-1>",lambda e:None)
# Try to handle when select file is cancelled # Try to handle when select file is cancelled
try: try:
draggedFiles = None allFiles = []
filesToErase = None files = []
draggedFolderPaths = [] draggedFolderPaths = []
# Ask for input file # Ask for input file
suffix = "" suffix = ""
if not draggedFile:
tmp = filedialog.askopenfilename(
initialdir=expanduser("~")
)
if len(tmp)==0:
# Exception will be caught by except below
raise Exception("No file selected.")
inputFile = tmp
else:
tmp = [i for i in draggedFile] tmp = [i for i in draggedFile]
res = [] res = []
within = False within = False
@ -131,7 +122,6 @@ def inputSelected(draggedFile=None):
res.append(tmpName) res.append(tmpName)
tmpName = "" tmpName = ""
else: else:
print(tmpName)
if i==" " and not within: if i==" " and not within:
if tmpName!="": if tmpName!="":
res.append(tmpName) res.append(tmpName)
@ -141,28 +131,26 @@ def inputSelected(draggedFile=None):
if tmpName: if tmpName:
res.append(tmpName) res.append(tmpName)
draggedFiles = [] allFiles = []
filesToErase = [] files = []
for i in res: for i in res:
if isdir(i): if isdir(i):
draggedFolderPaths.append(i) draggedFolderPaths.append(i)
tmp = Path(i).rglob("*") tmp = Path(i).rglob("*")
for p in tmp: for p in tmp:
draggedFiles.append(abspath(p)) allFiles.append(abspath(p))
else: else:
filesToErase.append(i) files.append(i)
draggedFiles = list(filter(lambda i:not isdir(i),draggedFiles)) if len(files)==1 and len(allFiles)==0:
inputFile = files[0]
if len(draggedFiles)==1: files = []
draggedFiles = []
inputFile = draggedFiles[0]
else: else:
inputFile = "" inputFile = ""
# Decide if encrypting or decrypting # Decide if encrypting or decrypting
if ".pcv" in inputFile.split("/")[-1]: if inputFile.endswith(".pcv"):
suffix = " (will decrypt)" suffix = " (will decrypt)"
fin = open(inputFile,"rb") fin = open(inputFile,"rb")
@ -214,9 +202,9 @@ def inputSelected(draggedFile=None):
cpasswordString.set("Confirm password:") cpasswordString.set("Confirm password:")
# Show selected file(s) # Show selected file(s)
if draggedFiles: if allFiles or files:
inputString.set(f"{len(draggedFiles)} file(s) selected"+ inputString.set(f"{len(allFiles) or len(files)}"+
" (will encrypt).") " file(s) selected (will encrypt).")
else: else:
inputString.set(inputFile.split("/")[-1]+suffix) inputString.set(inputFile.split("/")[-1]+suffix)
@ -234,7 +222,7 @@ def inputSelected(draggedFile=None):
# No file selected, do nothing # No file selected, do nothing
except: except:
inputString.set("Please select a file.") inputString.set("Please drag and drop files here.")
resetUI() resetUI()
# Focus the dummy button to remove ugly borders # Focus the dummy button to remove ugly borders
@ -244,28 +232,19 @@ def inputSelected(draggedFile=None):
# Allow drag and drop # Allow drag and drop
def onDrop(e): def onDrop(e):
print(e.data)
inputSelected(e.data) inputSelected(e.data)
tk.drop_target_register(DND_FILES) tk.drop_target_register(DND_FILES)
tk.dnd_bind("<<Drop>>",onDrop) tk.dnd_bind("<<Drop>>",onDrop)
# Button to select input file
selectFileInput = tkinter.ttk.Button(
tk,
text="Select file",
command=inputSelected,
)
selectFileInput.place(x=19,y=20)
# Label that displays selected input file # Label that displays selected input file
inputString = tkinter.StringVar(tk) inputString = tkinter.StringVar(tk)
inputString.set("Please select a file.") inputString.set("Please drag and drop files here.")
selectedInput = tkinter.ttk.Label( selectedInput = tkinter.ttk.Label(
tk, tk,
textvariable=inputString textvariable=inputString
) )
selectedInput.config(background="#f5f6f7") selectedInput.config(background="#f5f6f7")
selectedInput.place(x=104,y=23) selectedInput.place(x=17,y=20)
# Label that prompts user to enter a password # Label that prompts user to enter a password
passwordString = tkinter.StringVar(tk) passwordString = tkinter.StringVar(tk)
@ -323,7 +302,7 @@ cpasswordInput["state"] = "disabled"
# Start the encryption/decryption process # Start the encryption/decryption process
def start(): def start():
global inputFile,outputFile,password,ad,kept global inputFile,outputFile,password,ad,kept
global working,gMode,headerRsc,draggedFiles,filesToErase global working,gMode,headerRsc,allFiles,files
global dragFolderPath global dragFolderPath
dummy.focus() dummy.focus()
reedsolo = False reedsolo = False
@ -377,15 +356,20 @@ def start():
rsc = RSCodec(13) rsc = RSCodec(13)
# Compress files together if user dragged multiple files # Compress files together if user dragged multiple files
if draggedFiles: if allFiles or files:
statusString.set(compressingNotice) statusString.set(compressingNotice)
tmp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") tmp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
zfPath = Path(draggedFiles[0]).parent.absolute() if files:
zfPath = Path(files[0]).parent.absolute()
else:
zfPath = Path(dirname(allFiles[0])).parent.absolute()
zfOffset = len(str(zfPath)) zfOffset = len(str(zfPath))
zfName = pathJoin(zfPath,tmp+".zip") zfName = pathJoin(zfPath,tmp+".zip")
zf = ZipFile(zfName,"w") zf = ZipFile(zfName,"w")
for i in draggedFiles: for i in allFiles:
zf.write(i,i[zfOffset:]) zf.write(i,i[zfOffset:])
for i in files:
zf.write(i,pathSplit(i)[1])
zf.close() zf.close()
inputFile = zfName inputFile = zfName
@ -403,7 +387,13 @@ def start():
wipe = erase.get()==1 wipe = erase.get()==1
# Open files # Open files
try:
fin = open(inputFile,"rb") fin = open(inputFile,"rb")
except:
resetEncryptionUI()
statusString.set("Folder is empty.")
return
if reedsolo and mode=="decrypt": if reedsolo and mode=="decrypt":
# Move pointer one forward # Move pointer one forward
fin.read(1) fin.read(1)
@ -714,39 +704,33 @@ def start():
fout.close() fout.close()
fin.close() fin.close()
print(draggedFolderPaths)
print(draggedFiles)
print(filesToErase)
input()
# Securely wipe files as necessary # Securely wipe files as necessary
if wipe: if wipe:
if draggedFolderPaths: if draggedFolderPaths:
for i in draggedFolderPaths: for i in draggedFolderPaths:
secureWipe(i) secureWipe(i)
if filesToErase: if files:
for i in range(len(filesToErase)): for i in range(len(files)):
statusString.set(erasingNotice+f" ({i}/{len(filesToErase)}") statusString.set(erasingNotice+f" ({i}/{len(files)}")
progress["value"] = i/len(filesToErase) progress["value"] = i/len(files)
print("Erasing file "+filesToErase[i]) secureWipe(files[i])
secureWipe(filesToErase[i])
secureWipe(inputFile) secureWipe(inputFile)
# Secure wipe not enabled # Secure wipe not enabled
else: else:
if draggedFiles: if allFiles:
# Remove temporary zip file if created # Remove temporary zip file if created
remove(inputFile) remove(inputFile)
# Show appropriate notice if file corrupted or modified # Show appropriate notice if file corrupted or modified
if not kept: if not kept:
if mode=="encrypt": statusString.set(f"Completed. (Click here to show output)")
output = inputFile.split("/")[-1]+".pcv"
else:
output = inputFile.split("/")[-1].replace(".pcv","")
statusString.set(f"Completed. (Output: {output})")
# Show Reed-Solomon stats if it fixed corrupted bytes # Show Reed-Solomon stats if it fixed corrupted bytes
if mode=="decrypt" and reedsolo and reedsoloFixedCount: if mode=="decrypt" and reedsolo and reedsoloFixedCount:
statusString.set(f"Completed with {reedsoloFixedCount} bytes fixed."+ statusString.set(
f" (Output: {output})") f"Completed with {reedsoloFixedCount}"+
f" bytes fixed. (Output: {output})"
)
else: else:
if kept=="modified": if kept=="modified":
statusString.set(kModifiedNotice) statusString.set(kModifiedNotice)
@ -756,7 +740,13 @@ def start():
statusString.set(kVeryCorruptedNotice) statusString.set(kVeryCorruptedNotice)
status.config(cursor="hand2") status.config(cursor="hand2")
status.bind("<Button-1>",lambda e:print(outputPath))
# A little hack since strings are immutable
output = "".join([i for i in outputFile])
# Bind the output file
status.bind("<Button-1>",
lambda e:showOutput(output.replace("/","\\"))
)
# Reset variables and UI states # Reset variables and UI states
resetUI() resetUI()
@ -766,7 +756,7 @@ def start():
ad = "" ad = ""
kept = False kept = False
working = False working = False
draggedFiles = False allFiles = False
dragFolderPath = False dragFolderPath = False
# Wipe keys for safety # Wipe keys for safety
@ -799,7 +789,6 @@ def startWorker():
# Securely wipe file # Securely wipe file
def secureWipe(fin): def secureWipe(fin):
global draggedFiles
statusString.set(erasingNotice) statusString.set(erasingNotice)
# Check platform, erase accordingly # Check platform, erase accordingly
if platform.system()=="Windows": if platform.system()=="Windows":
@ -812,20 +801,19 @@ def secureWipe(fin):
statusString.set(erasingNotice+f" ({i}/{len(paths)})") statusString.set(erasingNotice+f" ({i}/{len(paths)})")
progress["value"] = 100*i/len(paths) progress["value"] = 100*i/len(paths)
system(f'cd "{paths[i]}" && "{rootDir}/sdelete64.exe" * -p 4 -s -nobanner') system(f'cd "{paths[i]}" && "{rootDir}/sdelete64.exe" * -p 4 -s -nobanner')
system(f'cd "{i}"') system(f'cd "{rootDir}"')
rmtree(fin) rmtree(fin)
else: else:
statusString.set(erasingNotice) statusString.set(erasingNotice)
progress["value"] = 100 progress["value"] = 100
system(f'sdelete64.exe "{fin}" -p 4 -nobanner') system(f'sdelete64.exe "{fin}" -p 4 -nobanner')
elif platform.system()=="Darwin": elif platform.system()=="Darwin":
pass system(f'rm -rfP "{fin}"')
else: else:
system(f'shred -uz "{fin}" -n 4') system(f'shred -uz "{fin}" -n 4')
# Disable all inputs while encrypting/decrypting # Disable all inputs while encrypting/decrypting
def disableAllInputs(): def disableAllInputs():
selectFileInput["state"] = "disabled"
passwordInput["state"] = "disabled" passwordInput["state"] = "disabled"
cpasswordInput["state"] = "disabled" cpasswordInput["state"] = "disabled"
adArea["state"] = "disabled" adArea["state"] = "disabled"
@ -837,7 +825,6 @@ def disableAllInputs():
# Reset UI to encryption state # Reset UI to encryption state
def resetEncryptionUI(): def resetEncryptionUI():
global working global working
selectFileInput["state"] = "normal"
passwordInput["state"] = "normal" passwordInput["state"] = "normal"
cpasswordInput["state"] = "normal" cpasswordInput["state"] = "normal"
adArea["state"] = "normal" adArea["state"] = "normal"
@ -845,12 +832,13 @@ def resetEncryptionUI():
eraseBtn["state"] = "normal" eraseBtn["state"] = "normal"
rsBtn["state"] = "normal" rsBtn["state"] = "normal"
working = False working = False
progress.stop()
progress.config(mode="determinate")
progress["value"] = 100 progress["value"] = 100
# Reset UI to decryption state # Reset UI to decryption state
def resetDecryptionUI(): def resetDecryptionUI():
global working global working
selectFileInput["state"] = "normal"
passwordInput["state"] = "normal" passwordInput["state"] = "normal"
adArea["state"] = "normal" adArea["state"] = "normal"
startBtn["state"] = "normal" startBtn["state"] = "normal"
@ -862,7 +850,6 @@ def resetDecryptionUI():
# Reset UI to original state (no file selected) # Reset UI to original state (no file selected)
def resetUI(): def resetUI():
selectFileInput["state"] = "normal"
adArea["state"] = "normal" adArea["state"] = "normal"
adArea.delete("1.0",tkinter.END) adArea.delete("1.0",tkinter.END)
adArea["state"] = "disabled" adArea["state"] = "disabled"
@ -875,7 +862,7 @@ def resetUI():
cpasswordInput["state"] = "disabled" cpasswordInput["state"] = "disabled"
cpasswordString.set("Confirm password:") cpasswordString.set("Confirm password:")
progress["value"] = 0 progress["value"] = 0
inputString.set("Please select a file.") inputString.set("Please drag and drop files here.")
keepBtn["state"] = "normal" keepBtn["state"] = "normal"
keep.set(0) keep.set(0)
keepBtn["state"] = "disabled" keepBtn["state"] = "disabled"
@ -888,6 +875,15 @@ def resetUI():
progress.config(mode="determinate") progress.config(mode="determinate")
progress["value"] = 0 progress["value"] = 0
def showOutput(file):
if platform.system()=="Windows":
system(f'explorer /select,"{file}"')
elif platform.system()=="Darwin":
system(f'cd "{file}"; open -R .')
system(f'cd "{rootDir}"')
else:
system(f'xdg-open "{dirname(file)}"')
# ad stands for "associated data"/metadata # ad stands for "associated data"/metadata
adLabelString = tkinter.StringVar(tk) adLabelString = tkinter.StringVar(tk)
adLabelString.set(adString) adLabelString.set(adString)