mirror of
https://github.com/HACKERALERT/Picocrypt.git
synced 2024-12-29 02:44:21 +00:00
Update Picocrypt.py
This commit is contained in:
parent
25c716fd21
commit
d3b68e8beb
1 changed files with 106 additions and 133 deletions
|
@ -1,34 +1,17 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Dependencies: argon2-cffi, pycryptodome, reedsolo
|
|
||||||
|
Picocrypt v1.11 (Beta)
|
||||||
|
Dependencies: argon2-cffi, pycryptodome, reedsolo, tkinterdnd2
|
||||||
Copyright (c) Evan Su (https://evansu.cc)
|
Copyright (c) Evan Su (https://evansu.cc)
|
||||||
Released under a GNU GPL v3 License
|
Released under a GNU GPL v3 License
|
||||||
https://github.com/HACKERALERT/Picocrypt
|
https://github.com/HACKERALERT/Picocrypt
|
||||||
|
|
||||||
|
~ In cryptography we trust ~
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Test if libraries are installed
|
|
||||||
try:
|
|
||||||
from argon2.low_level import hash_secret_raw
|
|
||||||
from Crypto.Cipher import ChaCha20_Poly1305
|
|
||||||
try:
|
|
||||||
from creedsolo import ReedSolomonError
|
|
||||||
except:
|
|
||||||
from reedsolo import ReedSolomonError
|
|
||||||
except:
|
|
||||||
# Libraries missing, install them
|
|
||||||
from os import system
|
|
||||||
try:
|
|
||||||
# Debian/Ubuntu based
|
|
||||||
system("sudo apt-get install python3-tk")
|
|
||||||
except:
|
|
||||||
# Fedora
|
|
||||||
system("sudo dnf install python3-tkinter")
|
|
||||||
|
|
||||||
system("python3 -m pip install argon2-cffi --no-cache-dir")
|
|
||||||
system("python3 -m pip install pycryptodome --no-cache-dir")
|
|
||||||
system("python3 -m pip install reedsolo --no-cache-dir")
|
|
||||||
|
|
||||||
# Imports
|
# Imports
|
||||||
from tkinter import filedialog,messagebox
|
from tkinter import filedialog,messagebox
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
@ -38,19 +21,15 @@ from Crypto.Cipher import ChaCha20_Poly1305
|
||||||
from Crypto.Hash import SHA3_512 as sha3_512
|
from Crypto.Hash import SHA3_512 as sha3_512
|
||||||
from secrets import compare_digest
|
from secrets import compare_digest
|
||||||
from os import urandom,fsync,remove,system
|
from os import urandom,fsync,remove,system
|
||||||
from os.path import getsize,expanduser,dirname
|
from os.path import getsize,expanduser,isdir
|
||||||
from os.path import abspath
|
from tkinterdnd2 import TkinterDnD,DND_FILES
|
||||||
from TkinterDnD2 import *
|
|
||||||
import sys
|
import sys
|
||||||
import tkinter
|
import tkinter
|
||||||
import tkinter.ttk
|
import tkinter.ttk
|
||||||
import tkinter.scrolledtext
|
import tkinter.scrolledtext
|
||||||
import webbrowser
|
import webbrowser
|
||||||
import platform
|
import platform
|
||||||
try:
|
from creedsolo import RSCodec,ReedSolomonError
|
||||||
from creedsolo import RSCodec,ReedSolomonError
|
|
||||||
except:
|
|
||||||
from reedsolo import RSCodec,ReedSolomonError
|
|
||||||
|
|
||||||
# Tk/Tcl is a little barbaric, so I'm disabling
|
# Tk/Tcl is a little barbaric, so I'm disabling
|
||||||
# high DPI so it doesn't scale bad and look horrible
|
# high DPI so it doesn't scale bad and look horrible
|
||||||
|
@ -92,11 +71,6 @@ tk.title("Picocrypt")
|
||||||
tk.configure(background="#f5f6f7")
|
tk.configure(background="#f5f6f7")
|
||||||
tk.resizable(0,0)
|
tk.resizable(0,0)
|
||||||
|
|
||||||
def onDrop(e):
|
|
||||||
print(e)
|
|
||||||
tk.drop_target_register(DND_FILES)
|
|
||||||
tk.dnd_bind("<<Drop>>",onDrop)
|
|
||||||
|
|
||||||
# Try setting window icon if included with Picocrypt
|
# Try setting window icon if included with Picocrypt
|
||||||
try:
|
try:
|
||||||
favicon = tkinter.PhotoImage(file="./key.png")
|
favicon = tkinter.PhotoImage(file="./key.png")
|
||||||
|
@ -109,7 +83,7 @@ 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():
|
def inputSelected(draggedFile=None):
|
||||||
global inputFile,working,headerRsc
|
global inputFile,working,headerRsc
|
||||||
dummy.focus()
|
dummy.focus()
|
||||||
|
|
||||||
|
@ -117,13 +91,16 @@ def inputSelected():
|
||||||
try:
|
try:
|
||||||
# Ask for input file
|
# Ask for input file
|
||||||
suffix = ""
|
suffix = ""
|
||||||
tmp = filedialog.askopenfilename(
|
if not draggedFile:
|
||||||
initialdir=expanduser("~")
|
tmp = filedialog.askopenfilename(
|
||||||
)
|
initialdir=expanduser("~")
|
||||||
if len(tmp)==0:
|
)
|
||||||
# Exception will be caught by except below
|
if len(tmp)==0:
|
||||||
raise Exception("No file selected.")
|
# Exception will be caught by except below
|
||||||
inputFile = tmp
|
raise Exception("No file selected.")
|
||||||
|
inputFile = tmp
|
||||||
|
else:
|
||||||
|
inputFile = draggedFile
|
||||||
|
|
||||||
# Decide if encrypting or decrypting
|
# Decide if encrypting or decrypting
|
||||||
if ".pcv" in inputFile.split("/")[-1]:
|
if ".pcv" in inputFile.split("/")[-1]:
|
||||||
|
@ -163,6 +140,7 @@ def inputSelected():
|
||||||
cpasswordInput["state"] = "normal"
|
cpasswordInput["state"] = "normal"
|
||||||
cpasswordInput.delete(0,"end")
|
cpasswordInput.delete(0,"end")
|
||||||
cpasswordInput["state"] = "disabled"
|
cpasswordInput["state"] = "disabled"
|
||||||
|
cpasswordString.set("Confirm password (N/A):")
|
||||||
else:
|
else:
|
||||||
# Update the UI
|
# Update the UI
|
||||||
eraseBtn["state"] = "normal"
|
eraseBtn["state"] = "normal"
|
||||||
|
@ -174,6 +152,7 @@ def inputSelected():
|
||||||
adLabelString.set(adString)
|
adLabelString.set(adString)
|
||||||
cpasswordInput["state"] = "normal"
|
cpasswordInput["state"] = "normal"
|
||||||
cpasswordInput.delete(0,"end")
|
cpasswordInput.delete(0,"end")
|
||||||
|
cpasswordString.set("Confirm password:")
|
||||||
|
|
||||||
# Enable password box, etc.
|
# Enable password box, etc.
|
||||||
inputString.set(inputFile.split("/")[-1]+suffix)
|
inputString.set(inputFile.split("/")[-1]+suffix)
|
||||||
|
@ -197,6 +176,13 @@ def inputSelected():
|
||||||
dummy.focus()
|
dummy.focus()
|
||||||
working = False
|
working = False
|
||||||
|
|
||||||
|
# Allow drag and drop
|
||||||
|
def onDrop(e):
|
||||||
|
print(e.data)
|
||||||
|
inputSelected(e.data)
|
||||||
|
tk.drop_target_register(DND_FILES)
|
||||||
|
tk.dnd_bind("<<Drop>>",onDrop)
|
||||||
|
|
||||||
# Button to select input file
|
# Button to select input file
|
||||||
selectFileInput = tkinter.ttk.Button(
|
selectFileInput = tkinter.ttk.Button(
|
||||||
tk,
|
tk,
|
||||||
|
@ -304,26 +290,11 @@ def start():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Disable inputs and buttons while encrypting/decrypting
|
# Disable inputs and buttons while encrypting/decrypting
|
||||||
selectFileInput["state"] = "disabled"
|
disableAllInputs()
|
||||||
passwordInput["state"] = "disabled"
|
|
||||||
cpasswordInput["state"] = "disabled"
|
|
||||||
adArea["state"] = "disabled"
|
|
||||||
startBtn["state"] = "disabled"
|
|
||||||
eraseBtn["state"] = "disabled"
|
|
||||||
keepBtn["state"] = "disabled"
|
|
||||||
rsBtn["state"] = "disabled"
|
|
||||||
|
|
||||||
# Make sure passwords match
|
# Make sure passwords match
|
||||||
if passwordInput.get()!=cpasswordInput.get() and mode=="encrypt":
|
if passwordInput.get()!=cpasswordInput.get() and mode=="encrypt":
|
||||||
selectFileInput["state"] = "normal"
|
resetEncryptionUI()
|
||||||
passwordInput["state"] = "normal"
|
|
||||||
cpasswordInput["state"] = "normal"
|
|
||||||
adArea["state"] = "normal"
|
|
||||||
startBtn["state"] = "normal"
|
|
||||||
eraseBtn["state"] = "normal"
|
|
||||||
rsBtn["state"] = "normal"
|
|
||||||
working = False
|
|
||||||
progress["value"] = 100
|
|
||||||
statusString.set("Passwords don't match.")
|
statusString.set("Passwords don't match.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -433,15 +404,7 @@ def start():
|
||||||
fout.close()
|
fout.close()
|
||||||
remove(outputFile)
|
remove(outputFile)
|
||||||
# Reset UI
|
# Reset UI
|
||||||
selectFileInput["state"] = "normal"
|
resetDecryptionUI()
|
||||||
passwordInput["state"] = "normal"
|
|
||||||
adArea["state"] = "normal"
|
|
||||||
startBtn["state"] = "normal"
|
|
||||||
keepBtn["state"] = "normal"
|
|
||||||
working = False
|
|
||||||
progress.stop()
|
|
||||||
progress.config(mode="determinate")
|
|
||||||
progress["value"] = 100
|
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
kept = "badlyCorrupted"
|
kept = "badlyCorrupted"
|
||||||
|
@ -480,14 +443,7 @@ def start():
|
||||||
fout.close()
|
fout.close()
|
||||||
remove(outputFile)
|
remove(outputFile)
|
||||||
# Reset UI
|
# Reset UI
|
||||||
selectFileInput["state"] = "normal"
|
resetDecryptionUI()
|
||||||
passwordInput["state"] = "normal"
|
|
||||||
adArea["state"] = "normal"
|
|
||||||
startBtn["state"] = "normal"
|
|
||||||
keepBtn["state"] = "normal"
|
|
||||||
working = False
|
|
||||||
progress["value"] = 100
|
|
||||||
del key
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Create XChaCha20-Poly1305 object
|
# Create XChaCha20-Poly1305 object
|
||||||
|
@ -541,12 +497,7 @@ def start():
|
||||||
if keep.get()!=1:
|
if keep.get()!=1:
|
||||||
remove(outputFile)
|
remove(outputFile)
|
||||||
# Reset UI
|
# Reset UI
|
||||||
selectFileInput["state"] = "normal"
|
resetDecryptionUI()
|
||||||
passwordInput["state"] = "normal"
|
|
||||||
adArea["state"] = "normal"
|
|
||||||
startBtn["state"] = "normal"
|
|
||||||
keepBtn["state"] = "normal"
|
|
||||||
working = False
|
|
||||||
del fin,fout,cipher,key
|
del fin,fout,cipher,key
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
@ -567,12 +518,7 @@ def start():
|
||||||
if keep.get()!=1:
|
if keep.get()!=1:
|
||||||
remove(outputFile)
|
remove(outputFile)
|
||||||
# Reset UI
|
# Reset UI
|
||||||
selectFileInput["state"] = "normal"
|
resetDecryptionUI()
|
||||||
passwordInput["state"] = "normal"
|
|
||||||
adArea["state"] = "normal"
|
|
||||||
startBtn["state"] = "normal"
|
|
||||||
keepBtn["state"] = "normal"
|
|
||||||
working = False
|
|
||||||
del fin,fout,cipher,key
|
del fin,fout,cipher,key
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
@ -606,13 +552,7 @@ def start():
|
||||||
fout.close()
|
fout.close()
|
||||||
remove(outputFile)
|
remove(outputFile)
|
||||||
# Reset UI
|
# Reset UI
|
||||||
selectFileInput["state"] = "normal"
|
resetDecryptionUI()
|
||||||
passwordInput["state"] = "normal"
|
|
||||||
adArea["state"] = "normal"
|
|
||||||
startBtn["state"] = "normal"
|
|
||||||
keepBtn["state"] = "normal"
|
|
||||||
working = False
|
|
||||||
progress["value"] = 100
|
|
||||||
del fin,fout,cipher,key
|
del fin,fout,cipher,key
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
@ -712,27 +652,7 @@ def start():
|
||||||
statusString.set(kVeryCorruptedNotice)
|
statusString.set(kVeryCorruptedNotice)
|
||||||
|
|
||||||
# Reset variables and UI states
|
# Reset variables and UI states
|
||||||
selectFileInput["state"] = "normal"
|
resetUI()
|
||||||
adArea["state"] = "normal"
|
|
||||||
adArea.delete("1.0",tkinter.END)
|
|
||||||
adArea["state"] = "disabled"
|
|
||||||
startBtn["state"] = "disabled"
|
|
||||||
passwordInput["state"] = "normal"
|
|
||||||
passwordInput.delete(0,"end")
|
|
||||||
passwordInput["state"] = "disabled"
|
|
||||||
cpasswordInput["state"] = "normal"
|
|
||||||
cpasswordInput.delete(0,"end")
|
|
||||||
cpasswordInput["state"] = "disabled"
|
|
||||||
progress["value"] = 0
|
|
||||||
inputString.set("Please select a file.")
|
|
||||||
keepBtn["state"] = "normal"
|
|
||||||
keep.set(0)
|
|
||||||
keepBtn["state"] = "disabled"
|
|
||||||
eraseBtn["state"] = "normal"
|
|
||||||
erase.set(0)
|
|
||||||
eraseBtn["state"] = "disabled"
|
|
||||||
rs.set(0)
|
|
||||||
rsBtn["state"] = "disabled"
|
|
||||||
inputFile = ""
|
inputFile = ""
|
||||||
outputFile = ""
|
outputFile = ""
|
||||||
password = ""
|
password = ""
|
||||||
|
@ -751,36 +671,27 @@ def wrapper():
|
||||||
start()
|
start()
|
||||||
except:
|
except:
|
||||||
# Reset UI accordingly
|
# Reset UI accordingly
|
||||||
progress.stop()
|
|
||||||
progress.config(mode="determinate")
|
|
||||||
progress["value"] = 100
|
|
||||||
selectFileInput["state"] = "normal"
|
|
||||||
passwordInput["state"] = "normal"
|
|
||||||
startBtn["state"] = "normal"
|
|
||||||
|
|
||||||
if gMode=="decrypt":
|
if gMode=="decrypt":
|
||||||
keepBtn["state"] = "normal"
|
resetDecryptionUI()
|
||||||
else:
|
else:
|
||||||
adArea["state"] = "normal"
|
resetEncryptionUI()
|
||||||
cpasswordInput["state"] = "normal"
|
|
||||||
rsBtn["state"] = "normal"
|
|
||||||
eraseBtn["state"] = "normal"
|
|
||||||
|
|
||||||
statusString.set(unknownErrorNotice)
|
statusString.set(unknownErrorNotice)
|
||||||
dummy.focus()
|
dummy.focus()
|
||||||
working = False
|
|
||||||
finally:
|
finally:
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
# Encryption/decrypt is done is a separate thread
|
# Encryption/decrypt is done is a separate thread so the UI
|
||||||
# so the UI isn't blocked. This is a wrapper
|
# isn't blocked. This is a wrapper to spawn a thread and start it.
|
||||||
# to spawn a thread and start it.
|
|
||||||
def startWorker():
|
def startWorker():
|
||||||
thread = Thread(target=wrapper,daemon=True)
|
thread = Thread(target=wrapper,daemon=True)
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
|
# Securely wipe file
|
||||||
def secureWipe(fin):
|
def secureWipe(fin):
|
||||||
statusString.set("Securely erasing original file...")
|
statusString.set("Securely erasing original file...")
|
||||||
|
# Check platform, erase accordingly
|
||||||
if platform.system()=="Windows":
|
if platform.system()=="Windows":
|
||||||
system(f'sdelete64.exe "{inputFile}" -p 4')
|
system(f'sdelete64.exe "{inputFile}" -p 4')
|
||||||
elif platform.system()=="Darwin":
|
elif platform.system()=="Darwin":
|
||||||
|
@ -788,6 +699,68 @@ def secureWipe(fin):
|
||||||
else:
|
else:
|
||||||
system(f'shred -uz "{inputFile}"')
|
system(f'shred -uz "{inputFile}"')
|
||||||
|
|
||||||
|
# Disable all inputs while encrypting/decrypting
|
||||||
|
def disableAllInputs():
|
||||||
|
selectFileInput["state"] = "disabled"
|
||||||
|
passwordInput["state"] = "disabled"
|
||||||
|
cpasswordInput["state"] = "disabled"
|
||||||
|
adArea["state"] = "disabled"
|
||||||
|
startBtn["state"] = "disabled"
|
||||||
|
eraseBtn["state"] = "disabled"
|
||||||
|
keepBtn["state"] = "disabled"
|
||||||
|
rsBtn["state"] = "disabled"
|
||||||
|
|
||||||
|
# Reset UI to encryption state
|
||||||
|
def resetEncryptionUI():
|
||||||
|
global working
|
||||||
|
selectFileInput["state"] = "normal"
|
||||||
|
passwordInput["state"] = "normal"
|
||||||
|
cpasswordInput["state"] = "normal"
|
||||||
|
adArea["state"] = "normal"
|
||||||
|
startBtn["state"] = "normal"
|
||||||
|
eraseBtn["state"] = "normal"
|
||||||
|
rsBtn["state"] = "normal"
|
||||||
|
working = False
|
||||||
|
progress["value"] = 100
|
||||||
|
|
||||||
|
# Reset UI to decryption state
|
||||||
|
def resetDecryptionUI():
|
||||||
|
global working
|
||||||
|
selectFileInput["state"] = "normal"
|
||||||
|
passwordInput["state"] = "normal"
|
||||||
|
adArea["state"] = "normal"
|
||||||
|
startBtn["state"] = "normal"
|
||||||
|
keepBtn["state"] = "normal"
|
||||||
|
working = False
|
||||||
|
progress.stop()
|
||||||
|
progress.config(mode="determinate")
|
||||||
|
progress["value"] = 100
|
||||||
|
|
||||||
|
# Reset UI to original state (no file selected)
|
||||||
|
def resetUI():
|
||||||
|
selectFileInput["state"] = "normal"
|
||||||
|
adArea["state"] = "normal"
|
||||||
|
adArea.delete("1.0",tkinter.END)
|
||||||
|
adArea["state"] = "disabled"
|
||||||
|
startBtn["state"] = "disabled"
|
||||||
|
passwordInput["state"] = "normal"
|
||||||
|
passwordInput.delete(0,"end")
|
||||||
|
passwordInput["state"] = "disabled"
|
||||||
|
cpasswordInput["state"] = "normal"
|
||||||
|
cpasswordInput.delete(0,"end")
|
||||||
|
cpasswordInput["state"] = "disabled"
|
||||||
|
cpasswordString.set("Confirm password:")
|
||||||
|
progress["value"] = 0
|
||||||
|
inputString.set("Please select a file.")
|
||||||
|
keepBtn["state"] = "normal"
|
||||||
|
keep.set(0)
|
||||||
|
keepBtn["state"] = "disabled"
|
||||||
|
eraseBtn["state"] = "normal"
|
||||||
|
erase.set(0)
|
||||||
|
eraseBtn["state"] = "disabled"
|
||||||
|
rs.set(0)
|
||||||
|
rsBtn["state"] = "disabled"
|
||||||
|
|
||||||
# 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)
|
||||||
|
|
Loading…
Reference in a new issue