Finalize v1.15

This commit is contained in:
Evan Su 2021-08-09 19:51:25 -04:00 committed by GitHub
parent c59d8f0f69
commit 69c2b49a48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 94 additions and 22 deletions

View File

@ -2,7 +2,7 @@ package main
/* /*
Picocrypt v1.14 Picocrypt v1.15
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
@ -21,6 +21,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"math" "math"
"math/big"
"time" "time"
"sync" "sync"
"hash" "hash"
@ -69,7 +70,7 @@ import (
) )
var version = "v1.14" var version = "v1.15"
//go:embed NotoSans-Regular.ttf //go:embed NotoSans-Regular.ttf
var font []byte var font []byte
@ -118,6 +119,8 @@ var splitUnits = []string{
"GiB", "GiB",
} }
var splitSelected int32 // Index of which splitting unit was chosen from above var splitSelected int32 // Index of which splitting unit was chosen from above
var shredPasses = "4"
var stopShredding = false
var shredProgress float32 var shredProgress float32
var shredDone float32 var shredDone float32
var shredTotal float32 // Total files to shred (recursive) var shredTotal float32 // Total files to shred (recursive)
@ -171,6 +174,9 @@ var sha3_256_selected = false
var blake2b_selected = false var blake2b_selected = false
var blake2s_selected = false var blake2s_selected = false
// Link to a Wikipedia article on Reed-Solomon
var rsWikipedia = "https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction"
// Create the UI // Create the UI
func startUI(){ func startUI(){
giu.SingleWindow().Layout( giu.SingleWindow().Layout(
@ -291,11 +297,21 @@ func startUI(){
// Prompt for password // Prompt for password
giu.Row( giu.Row(
giu.Label("Password:"), giu.Label("Password:"),
giu.SmallButton("Generate").OnClick(func(){
tmp := genPassword()
password = tmp
cPassword = tmp
passwordStrength = zxcvbn.PasswordStrength(password,nil).Score
giu.Update()
}),
giu.SmallButton("Copy").OnClick(func(){
clipboard.WriteAll(password)
}),
giu.Dummy(-200,0), giu.Dummy(-200,0),
giu.Label(keyfilePrompt), giu.Label(keyfilePrompt),
), ),
giu.Row( giu.Row(
giu.InputText(&password).Size(240/dpi).Flags(giu.InputTextFlagsPassword).OnChange(func(){ giu.InputText(&password).Size(241/dpi).Flags(giu.InputTextFlagsPassword).OnChange(func(){
passwordStrength = zxcvbn.PasswordStrength(password,nil).Score passwordStrength = zxcvbn.PasswordStrength(password,nil).Score
}), }),
@ -325,7 +341,10 @@ func startUI(){
int(math.Round(float64(6*dpi))), int(math.Round(float64(6*dpi))),
int(math.Round(float64(12*dpi))), int(math.Round(float64(12*dpi))),
)) ))
canvas.PathArcTo(path,8*dpi,0,float32(passwordStrength+1)/5*(2*math.Pi),-1) canvas.PathArcTo(path,
8*dpi,-math.Pi/2,
float32(passwordStrength+1)/5*(2*math.Pi)-math.Pi/2,
-1)
canvas.PathStroke(col,false,3) canvas.PathStroke(col,false,3)
}), }),
giu.Dummy(-200,0), giu.Dummy(-200,0),
@ -348,7 +367,7 @@ func startUI(){
// Prompt to confirm password // Prompt to confirm password
giu.Label("Confirm password:"), giu.Label("Confirm password:"),
giu.Row( giu.Row(
giu.InputText(&cPassword).Size(240/dpi).Flags(giu.InputTextFlagsPassword), giu.InputText(&cPassword).Size(241/dpi).Flags(giu.InputTextFlagsPassword),
giu.Custom(func(){ giu.Custom(func(){
canvas := giu.GetCanvas() canvas := giu.GetCanvas()
pos := giu.GetCursorScreenPos() pos := giu.GetCursorScreenPos()
@ -388,12 +407,14 @@ func startUI(){
giu.Row( giu.Row(
giu.Checkbox("Encode with Reed-Solomon to prevent corruption (slow)",&reedsolo), giu.Checkbox("Encode with Reed-Solomon to prevent corruption (slow)",&reedsolo),
giu.Button("?").Size(24,25).OnClick(func(){ giu.Button("?").Size(24,25).OnClick(func(){
browser.OpenURL("https://bit.ly/3A2V7LR") browser.OpenURL(rsWikipedia)
}), }),
).Build() ).Build()
giu.Row( giu.Row(
giu.Checkbox("Split output into chunks of",&split), giu.Checkbox("Split output into chunks of",&split),
giu.InputText(&splitSize).Size(50).Flags(giu.InputTextFlagsCharsDecimal), giu.InputText(&splitSize).Size(50).Flags(giu.InputTextFlagsCharsDecimal).OnChange(func(){
split = true
}),
giu.Combo("##splitter",splitUnits[splitSelected],splitUnits,&splitSelected).Size(52), giu.Combo("##splitter",splitUnits[splitSelected],splitUnits,&splitSelected).Size(52),
).Build() ).Build()
giu.Dummy(0,1).Build() giu.Dummy(0,1).Build()
@ -569,7 +590,26 @@ func startUI(){
}), }),
giu.Label("Drop file(s) and folder(s) here to shred them."), giu.Label("Drop file(s) and folder(s) here to shred them."),
giu.ProgressBar(shredProgress).Overlay(shredOverlay).Size(-0.0000001,0), giu.Custom(func(){
if runtime.GOOS=="darwin"{
giu.Label("Number of passes: Not supported on macOS").Build()
}else{
giu.Row(
giu.Label("Number of passes:"),
giu.InputText(&shredPasses).Size(16).Flags(giu.InputTextFlagsCharsDecimal),
).Build()
}
}),
giu.Dummy(0,-50),
giu.Row(
giu.ProgressBar(shredProgress).Overlay(shredOverlay).Size(-65,0),
giu.Button("Cancel").Size(58,0).OnClick(func(){
stopShredding = true
shredding = "Ready."
shredProgress = 0
shredOverlay = ""
}),
),
giu.Custom(func(){ giu.Custom(func(){
if len(shredding)>50{ if len(shredding)>50{
shredding = "....."+shredding[len(shredding)-50:] shredding = "....."+shredding[len(shredding)-50:]
@ -688,7 +728,7 @@ func onDrop(names []string){
fin.Close() fin.Close()
return return
} }
if valid,_:=regexp.Match(`^v\d\.\d{2}.{10}0?\d+`,tmp);!valid{ if valid,_:=regexp.Match(`^v\d\.\d{2}.{10}0?\d+`,tmp);!valid&&!isSplit{
resetUI() resetUI()
_status = "This doesn't seem to be a Picocrypt volume." _status = "This doesn't seem to be a Picocrypt volume."
_status_color = color.RGBA{0xff,0x00,0x00,255} _status_color = color.RGBA{0xff,0x00,0x00,255}
@ -1633,6 +1673,7 @@ func generateChecksums(file string){
// Recursively shred all file(s) and folder(s) passed in as 'names' // Recursively shred all file(s) and folder(s) passed in as 'names'
func shred(names []string,separate bool){ func shred(names []string,separate bool){
stopShredding = false
shredTotal = 0 shredTotal = 0
shredDone = 0 shredDone = 0
@ -1669,6 +1710,9 @@ func shred(names []string,separate bool){
if err!=nil{ if err!=nil{
return nil return nil
} }
if stopShredding{
return nil
}
stat,_ := os.Stat(path) stat,_ := os.Stat(path)
if !stat.IsDir(){ if !stat.IsDir(){
if len(coming)==128{ if len(coming)==128{
@ -1678,15 +1722,15 @@ func shred(names []string,separate bool){
wg.Add(1) wg.Add(1)
go func(wg *sync.WaitGroup,id int,j string){ go func(wg *sync.WaitGroup,id int,j string){
defer wg.Done() defer wg.Done()
shredding = j
cmd := exec.Command("") cmd := exec.Command("")
if runtime.GOOS=="linux"{ if runtime.GOOS=="linux"{
cmd = exec.Command("shred","-ufvz","-n","3",j) cmd = exec.Command("shred","-ufvz","-n",shredPasses,j)
}else{ }else{
cmd = exec.Command("rm","-rfP",j) cmd = exec.Command("rm","-rfP",j)
} }
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow:true} cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow:true}
cmd.Run() cmd.Run()
shredding = j
shredDone++ shredDone++
shredUpdate(separate) shredUpdate(separate)
giu.Update() giu.Update()
@ -1701,32 +1745,37 @@ func shred(names []string,separate bool){
return nil return nil
}) })
for _,i := range coming{ for _,i := range coming{
if stopShredding{
break
}
go func(){ go func(){
shredding = i
cmd := exec.Command("") cmd := exec.Command("")
if runtime.GOOS=="linux"{ if runtime.GOOS=="linux"{
cmd = exec.Command("shred","-ufvz","-n","3",i) cmd = exec.Command("shred","-ufvz","-n",shredPasses,i)
}else{ }else{
cmd = exec.Command("rm","-rfP",i) cmd = exec.Command("rm","-rfP",i)
} }
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow:true} cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow:true}
cmd.Run() cmd.Run()
shredding = i
shredDone++ shredDone++
shredUpdate(separate) shredUpdate(separate)
giu.Update() giu.Update()
}() }()
} }
os.RemoveAll(name) if !stopShredding{
os.RemoveAll(name)
}
}else{ // The path is a file, not a directory, so just shred it }else{ // The path is a file, not a directory, so just shred it
shredding = name
cmd := exec.Command("") cmd := exec.Command("")
if runtime.GOOS=="linux"{ if runtime.GOOS=="linux"{
cmd = exec.Command("shred","-ufvz","-n","3",name) cmd = exec.Command("shred","-ufvz","-n",shredPasses,name)
}else{ }else{
cmd = exec.Command("rm","-rfP",name) cmd = exec.Command("rm","-rfP",name)
} }
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow:true} cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow:true}
cmd.Run() cmd.Run()
shredding = name+"/*"
shredDone++ shredDone++
shredUpdate(separate) shredUpdate(separate)
} }
@ -1740,6 +1789,10 @@ func shred(names []string,separate bool){
} }
stat,_ := os.Stat(path) stat,_ := os.Stat(path)
if stat.IsDir(){ if stat.IsDir(){
if stopShredding{
return nil
}
t := 0 t := 0
files,_ := ioutil.ReadDir(path) files,_ := ioutil.ReadDir(path)
for _,f := range files{ for _,f := range files{
@ -1749,18 +1802,23 @@ func shred(names []string,separate bool){
} }
shredDone += float32(t) shredDone += float32(t)
shredUpdate(separate) shredUpdate(separate)
cmd := exec.Command(sdelete64path,"*","-p","4") shredding = strings.ReplaceAll(path,"\\","/")+"/*"
cmd := exec.Command(sdelete64path,"*","-p",shredPasses)
cmd.Dir = path cmd.Dir = path
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow:true} cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow:true}
cmd.Run() cmd.Run()
shredding = strings.ReplaceAll(path,"\\","/")+"/*" giu.Update()
} }
return nil return nil
}) })
// sdelete64 doesn't delete the empty folder, so I'll do it manually
os.RemoveAll(name) if !stopShredding{
// sdelete64 doesn't delete the empty folder, so I'll do it manually
os.RemoveAll(name)
}
}else{ }else{
cmd := exec.Command(sdelete64path,name,"-p","4") shredding = name
cmd := exec.Command(sdelete64path,name,"-p",shredPasses)
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow:true} cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow:true}
cmd.Run() cmd.Run()
shredDone++ shredDone++
@ -1768,6 +1826,9 @@ func shred(names []string,separate bool){
} }
} }
giu.Update() giu.Update()
if stopShredding{
return
}
} }
// Clear UI state // Clear UI state
@ -1866,6 +1927,17 @@ func humanize(seconds int) string{
return fmt.Sprintf("%02d:%02d:%02d",hours,minutes,seconds) return fmt.Sprintf("%02d:%02d:%02d",hours,minutes,seconds)
} }
// Generate cryptographically secure high-entropy passwords
func genPassword() string{
chars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-=!@#$^&()_+?"
tmp := make([]byte,32)
for i:=0;i<32;i++{
j,_ := rand.Int(rand.Reader,new(big.Int).SetUint64(uint64(len(chars))))
tmp[i] = chars[j.Int64()]
}
return string(tmp)
}
func main(){ func main(){
// Create a temporary file to store sdelete64.exe // Create a temporary file to store sdelete64.exe
sdelete64,_ := os.CreateTemp("","sdelete64.*.exe") sdelete64,_ := os.CreateTemp("","sdelete64.*.exe")