From 0ebf21aa0135896695d7b4097b2f4dcec341b04c Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Mon, 3 May 2021 12:48:39 -0400 Subject: [PATCH] Update Picocrypt.go --- src/unstable/Picocrypt.go | 691 +++++++++++++++++++++++++++----------- 1 file changed, 495 insertions(+), 196 deletions(-) diff --git a/src/unstable/Picocrypt.go b/src/unstable/Picocrypt.go index 3137162..f494523 100644 --- a/src/unstable/Picocrypt.go +++ b/src/unstable/Picocrypt.go @@ -18,17 +18,26 @@ import ( "time" "strings" "strconv" - "image/color" + //"image/color" + "crypto/md5" "crypto/rand" + "crypto/sha1" + "encoding/hex" "path/filepath" + "crypto/sha256" + "github.com/pkg/browser" + "github.com/zeebo/blake3" "golang.org/x/crypto/sha3" "golang.org/x/crypto/argon2" - "golang.org/x/crypto/blake2b" g "github.com/AllenDang/giu" di "github.com/sqweek/dialog" - ig "github.com/AllenDang/imgui-go" + "golang.org/x/crypto/blake2b" + "golang.org/x/crypto/blake2s" + "github.com/atotto/clipboard" + //"github.com/AllenDang/imgui-go" "github.com/klauspost/reedsolomon" "golang.org/x/crypto/chacha20poly1305" + "github.com/HACKERALERT/Monocypher-Go/monocypher" ) // Global variables @@ -42,10 +51,13 @@ var inputFile string var outputFile string // UI-related global variables +var tab = 0 var inputLabel = "Drag and drop file(s) and folder(s) into this window." var outputEntry string var outputWidth float32 = 376 var orLabel = "or" +var passwordState = g.InputTextFlags_Password +var passwordToggleString = "Show" var progress float32 = 0 var progressInfo = "" var status = "Ready." @@ -57,6 +69,9 @@ var metadata string var keep bool var erase bool var reedsolo bool +var split bool +var splitSize string +var fast bool // Reed-Solomon encoders var rs5_128,_ = reedsolomon.New(5,128) @@ -66,225 +81,392 @@ var rs24_128,_ = reedsolomon.New(24,128) var rs32_128,_ = reedsolomon.New(32,128) var rs64_128,_ = reedsolomon.New(64,128) +// File checksum generator variables +var cs_md5 string +var cs_sha1 string +var cs_sha256 string +var cs_sha3_256 string +var cs_blake2b string +var cs_blake2s string +var cs_blake3 string +var cs_progress float32 = 0 +var md5_selected = false +var sha1_selected = false +var sha256_selected = false +var sha3_256_selected = false +var blake2b_selected = false +var blake2s_selected = false +var blake3_selected = false + // Create the user interface func startUI(){ g.SingleWindow("Picocrypt").Layout( - // Some styling for aesthetics - g.Style().SetColor( - ig.StyleColorBorder, - color.RGBA{0x06,0x34,0x55,255}, - ).To( - // The tab bar, which contains different tabs for different features - g.TabBar("TabBar").Layout( - // File encryption/decryption tab - g.TabItem("Encryption/decryption").Layout( - // Label listing the input files and button to clear input files - g.Dummy(30,0), - g.Line( - g.Label(inputLabel), - g.Button("Clear").OnClick(resetUI), - ), + // The tab bar, which contains different tabs for different features + g.TabBar("TabBar").Layout( + // File encryption/decryption tab + g.TabItem("Encryption/decryption").Layout( + // Update 'tab' to indicate active tab + g.Custom(func(){ + if g.IsItemActive(){ + tab = 0 + } + }), - // Allow user to choose a custom output path and name - g.Dummy(10,0), - g.Label("Save output as:"), - g.Line( - g.InputText("##output",&outputEntry).Size(outputWidth/dpi), - g.Label(orLabel), - g.Button("Save as").OnClick(func(){ - file,_ := di.File().Title("Save as").Save() + // Label listing the input files and button to clear input files + g.Dummy(30,0), + g.Line( + g.Label(inputLabel), + g.Button("Clear").OnClick(resetUI), + ), - // Return if user canceled the file dialog - if file==""{ - return - } + // Allow user to choose a custom output path and name + g.Dummy(10,0), + g.Label("Save output as:"), + g.Line( + g.InputText("##output",&outputEntry).Size(outputWidth/dpi), + g.Label(orLabel), + g.Button("Save as").OnClick(func(){ + file,_ := di.File().Title("Save as").Save() - // Remove the extra ".pcv" extension if needed - if strings.HasSuffix(file,".pcv"){ - file = file[:len(file)-4] - } - outputEntry = file - }), - ), + // Return if user canceled the file dialog + if file==""{ + return + } - // Prompt for password - g.Dummy(10,0), - g.Label("Password:"), - g.InputText("##password",&password).Size(200/dpi), + // Remove the extra ".pcv" extension if needed + if strings.HasSuffix(file,".pcv"){ + file = file[:len(file)-4] + } + outputEntry = file + }), + ), - // Prompt to confirm password - g.Dummy(10,0), - g.Label("Confirm password:"), - g.InputText("##cPassword",&cPassword).Size(200/dpi), + // Prompt for password + g.Dummy(10,0), + g.Label("Password:"), + g.Line( + g.InputText("##password",&password).Size(200/dpi).Flags(passwordState), + g.Button(passwordToggleString).OnClick(func(){ + if passwordState==g.InputTextFlags_Password{ + passwordState = g.InputTextFlags_None + passwordToggleString = "Hide" + }else{ + passwordState = g.InputTextFlags_Password + passwordToggleString = "Show" + } + g.Update() + }), + ), - // Optional metadata - g.Dummy(10,0), - g.Label("Metadata (optional):"), - g.InputTextMultiline("##metadata",&metadata).Size(200,80), + // Prompt to confirm password + g.Dummy(10,0), + g.Label("Confirm password:"), + g.InputText("##cPassword",&cPassword).Size(200/dpi).Flags(passwordState), - // Advanced options can be enabled with checkboxes - g.Dummy(10,0), - g.Checkbox("Keep decrypted output even if it's corrupted or modified",&keep), - g.Checkbox("Securely erase and delete original file(s)",&erase), + // Optional metadata + g.Dummy(10,0), + g.Label("Metadata (optional):"), + g.InputTextMultiline("##metadata",&metadata).Size(200,80), + + // Advanced options can be enabled with checkboxes + g.Dummy(10,0), + g.Checkbox("Keep decrypted output even if it's corrupted or modified",&keep), + g.Checkbox("Securely erase and delete original file(s)",&erase), + g.Line( g.Checkbox("Encode with Reed-Solomon to prevent corruption",&reedsolo), - - // Start and cancel buttons - g.Dummy(10,0), - g.Line( - g.Button("Start").Size(360,20).OnClick(func(){ - go work() - }), - g.Button("Cancel").Size(95,20), - ), - - // Progress bar - g.ProgressBar(progress).Size(-1,0).Overlay(progressInfo), - - // Status label - g.Dummy(10,0), - g.Label(status), - - // Credits and version - g.Line( - g.Label("Created by Evan Su."), - g.Label("v1.13"), - ), + g.Button("?").OnClick(func(){ + browser.OpenURL("https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction") + }), ), - - // File shredder tab - g.TabItem("Shredder").Layout( - + g.Line( + g.Checkbox("Split output into chunks of",&split), + g.InputText("##splitSize",&splitSize).Size(30).Flags(g.InputTextFlags_CharsDecimal), + g.Label("MB"), ), + g.Checkbox("Fast mode (less secure, not as durable)",&fast), - // File checksum generator tab - g.TabItem("Checksum generator").Layout( + // Start and cancel buttons + g.Dummy(10,0), + g.Button("Start").Size(-1,20).OnClick(func(){ + go work() + }), + /*// Progress bar + g.ProgressBar(progress).Size(-1,0).Overlay(progressInfo), + + // Status label + g.Dummy(10,0), + g.Label(status),*/ + + // Credits and version + g.Line( + g.Label("Created by Evan Su. See the About tab for more info."), + g.Dummy(46,0), + g.Label("v1.13"), ), ), + + // File shredder tab + g.TabItem("Shredder").Layout( + // Update 'tab' to indicate active tab + g.Custom(func(){ + if g.IsItemActive(){ + tab = 1 + } + }), + + ), + + // File checksum generator tab + g.TabItem("Checksum generator").Layout( + // Update 'tab' to indicate active tab + g.Custom(func(){ + if g.IsItemActive(){ + tab = 2 + } + }), + + g.Dummy(30,0), + g.Label("Toggle the hashes you would like to generate and drop a file here."), + + // MD5 + g.Dummy(10,0), + g.Line( + g.Checkbox("MD5:",&md5_selected), + g.Dummy(360,0), + g.Button("Copy").OnClick(func(){ + clipboard.WriteAll(cs_md5) + }), + ), + g.InputText("##cs_md5",&cs_md5).Size(-1).Flags(g.InputTextFlags_ReadOnly), + + // SHA1 + g.Dummy(10,0), + g.Line( + g.Checkbox("SHA1:",&sha1_selected), + g.Dummy(353,0), + g.Button("Copy").OnClick(func(){ + clipboard.WriteAll(cs_sha1) + }), + ), + g.InputText("##cs_sha1",&cs_sha1).Size(-1).Flags(g.InputTextFlags_ReadOnly), + + // SHA256 + g.Dummy(10,0), + g.Line( + g.Checkbox("SHA256:",&sha256_selected), + g.Dummy(341,0), + g.Button("Copy").OnClick(func(){ + clipboard.WriteAll(cs_sha256) + }), + ), + g.InputText("##cs_sha256",&cs_sha256).Size(-1).Flags(g.InputTextFlags_ReadOnly), + + // SHA3-256 + g.Dummy(10,0), + g.Line( + g.Checkbox("SHA3-256:",&sha3_256_selected), + g.Dummy(334,0), + g.Button("Copy").OnClick(func(){ + clipboard.WriteAll(cs_sha3_256) + }), + ), + g.InputText("##cs_sha3_256",&cs_sha3_256).Size(-1).Flags(g.InputTextFlags_ReadOnly), + + // BLAKE2b + g.Dummy(10,0), + g.Line( + g.Checkbox("BLAKE2b:",&blake2b_selected), + g.Dummy(320,0), + g.Button("Copy").OnClick(func(){ + clipboard.WriteAll(cs_blake2b) + }), + ), + g.InputText("##cs_blake2b",&cs_blake2b).Size(-1).Flags(g.InputTextFlags_ReadOnly), + + // BLAKE2s + g.Dummy(10,0), + g.Line( + g.Checkbox("BLAKE2s:",&blake2s_selected), + g.Dummy(320,0), + g.Button("Copy").OnClick(func(){ + clipboard.WriteAll(cs_blake2s) + }), + ), + g.InputText("##cs_blake2s",&cs_blake2s).Size(-1).Flags(g.InputTextFlags_ReadOnly), + + // BLAKE3 + g.Dummy(10,0), + g.Line( + g.Checkbox("BLAKE3:",&blake3_selected), + g.Dummy(323,0), + g.Button("Copy").OnClick(func(){ + clipboard.WriteAll(cs_blake3) + }), + ), + g.InputText("##cs_blake3",&cs_blake3).Size(-1).Flags(g.InputTextFlags_ReadOnly), + + // Progress bar + g.Dummy(10,0), + g.Label("Progress:"), + g.ProgressBar(cs_progress).Size(-1,0), + ), + g.TabItem("About").Layout( + // Update 'tab' to indicate active tab + g.Custom(func(){ + if g.IsItemActive(){ + tab = 3 + } + }), + g.Dummy(30,0), + g.Label("Picocrypt, created by Evan Su (https://evansu.cc)"), + ), ), ) + if working{ + g.SingleWindow("Working..").IsOpen(&working).Layout( + g.Dummy(30,0), + g.Label("Tips:"), + g.Label(" - Choose a strong password with more than 16 characters."), + g.Label(" - Use a unique password that isn't used anywhere else."), + + // Progress bar + g.ProgressBar(progress).Size(-1,0).Overlay(progressInfo), + + // Status label + g.Dummy(10,0), + g.Label(status), + + g.Button("Cancel").Size(95,20).OnClick(func(){ + working = false + }), + ) + } } // Handle files dropped into Picocrypt by user func onDrop(names []string){ - // Clear variables - onlyFiles = nil - onlyFolders = nil - allFiles = nil - files,folders := 0,0 - - // Reset UI - resetUI() + if tab==0{ + // Clear variables + onlyFiles = nil + onlyFolders = nil + allFiles = nil + files,folders := 0,0 - // Hide the ".pcv" label - orLabel = "or" - outputWidth = 376 + // Reset UI + resetUI() - // There's only one dropped item - if len(names)==1{ - stat,_ := os.Stat(names[0]) + // Hide the ".pcv" label + orLabel = "or" + outputWidth = 376 - // Check if dropped item is a file or a folder - if stat.IsDir(){ - folders++ - inputLabel = "1 folder selected." + // There's only one dropped item + if len(names)==1{ + stat,_ := os.Stat(names[0]) - // Add the folder - onlyFolders = append(onlyFolders,names[0]) + // Check if dropped item is a file or a folder + if stat.IsDir(){ + folders++ + inputLabel = "1 folder selected." + + // Add the folder + onlyFolders = append(onlyFolders,names[0]) + + // Set 'outputEntry' to 'Encrypted.zip' in the same directory + outputEntry = filepath.Join(filepath.Dir(names[0]),"Encrypted.zip") + }else{ + files++ + name := filepath.Base(names[0]) + + // Decide if encrypting or decrypting + if strings.HasSuffix(names[0],".pcv"){ + mode = "decrypt" + inputLabel = name+" (will decrypt)" + outputEntry = names[0][:len(names[0])-4] + + // Open input file in read-only mode + fin,_ := os.Open(names[0]) + defer fin.Close() + + // Read metadata and insert into box + fin.Read(make([]byte,133)) + tmp := make([]byte,138) + fin.Read(tmp) + tmp = rsDecode(tmp,rs10_128,10) + metadataLength,_ := strconv.Atoi(string(tmp)) + //fmt.Println(metadataLength) + tmp = make([]byte,metadataLength) + fin.Read(tmp) + metadata = string(tmp) + + }else{ + mode = "encrypt" + inputLabel = name+" (will encrypt)" + outputEntry = names[0] + + // Show the ".pcv" file extension + orLabel = ".pcv or" + outputWidth = 341 + } + + // Add the file + onlyFiles = append(onlyFiles,names[0]) + + inputFile = names[0] + } + }else{ + // There are multiple dropped items, check each one + for _,name := range names{ + stat,_ := os.Stat(name) + + // Check if item is a file or a directory + if stat.IsDir(){ + folders++ + onlyFolders = append(onlyFolders,name) + }else{ + files++ + onlyFiles = append(onlyFiles,name) + allFiles = append(allFiles,name) + } + } + + if folders==0{ + // If folders==0, then there are multiple files + inputLabel = fmt.Sprintf("%d files selected.",files) + }else if files==0{ + // If files==0, then there are multiple folders + inputLabel = fmt.Sprintf("%d folders selected.",folders) + }else{ + // There are multiple files and folders + if files==1&&folders>1{ + inputLabel = fmt.Sprintf("1 file and %d folders selected.",folders) + }else if folders==1&&files>1{ + inputLabel = fmt.Sprintf("%d files and 1 folder selected.",files) + }else{ + inputLabel = fmt.Sprintf("%d files and %d folders selected.",files,folders) + } + } // Set 'outputEntry' to 'Encrypted.zip' in the same directory outputEntry = filepath.Join(filepath.Dir(names[0]),"Encrypted.zip") - }else{ - files++ - name := filepath.Base(names[0]) - - // Decide if encrypting or decrypting - if strings.HasSuffix(names[0],".pcv"){ - mode = "decrypt" - inputLabel = name+" (will decrypt)" - outputEntry = names[0][:len(names[0])-4] - - // Open input file in read-only mode - fin,_ := os.Open(names[0]) - defer fin.Close() - - // Read metadata and insert into box - fin.Read(make([]byte,133)) - tmp := make([]byte,138) - fin.Read(tmp) - tmp = rsDecode(tmp,rs10_128,10) - metadataLength,_ := strconv.Atoi(string(tmp)) - //fmt.Println(metadataLength) - tmp = make([]byte,metadataLength) - fin.Read(tmp) - metadata = string(tmp) - - }else{ - mode = "encrypt" - inputLabel = name+" (will encrypt)" - outputEntry = names[0] - - // Show the ".pcv" file extension - orLabel = ".pcv or" - outputWidth = 341 - } - - // Add the file - onlyFiles = append(onlyFiles,names[0]) - - // Set the file as 'outputEntry' - outputEntry = names[0] - - inputFile = names[0] } - }else{ - // There are multiple dropped items, check each one - for _,name := range names{ - stat,_ := os.Stat(name) - // Check if item is a file or a directory - if stat.IsDir(){ - folders++ - onlyFolders = append(onlyFolders,name) - }else{ - files++ - onlyFiles = append(onlyFiles,name) - allFiles = append(allFiles,name) + // If there are folders that were dropped, recusively add all files into 'allFiles' + if folders>0{ + for _,name := range(onlyFolders){ + filepath.Walk(name,func(path string,_ os.FileInfo,_ error) error{ + stat,_ := os.Stat(path) + if !stat.IsDir(){ + allFiles = append(allFiles,path) + } + return nil + }) } } + }else if tab==1{ - if folders==0{ - // If folders==0, then there are multiple files - inputLabel = fmt.Sprintf("%d files selected.",files) - }else if files==0{ - // If files==0, then there are multiple folders - inputLabel = fmt.Sprintf("%d folders selected.",folders) - }else{ - // There are multiple files and folders - if files==1&&folders>1{ - inputLabel = fmt.Sprintf("1 file and %d folders selected.",folders) - }else if folders==1&&files>1{ - inputLabel = fmt.Sprintf("%d files and 1 folder selected.",files) - }else{ - inputLabel = fmt.Sprintf("%d files and %d folders selected.",files,folders) - } - } - - // Set 'outputEntry' to 'Encrypted.zip' in the same directory - outputEntry = filepath.Join(filepath.Dir(names[0]),"Encrypted.zip") - } - - // If there are folders that were dropped, recusively add all files into 'allFiles' - if folders>0{ - for _,name := range(onlyFolders){ - filepath.Walk(name,func(path string,_ os.FileInfo,_ error) error{ - stat,_ := os.Stat(path) - if !stat.IsDir(){ - allFiles = append(allFiles,path) - } - return nil - }) - } + }else if tab==2{ + go generateChecksums(names[0]) } // Update the UI @@ -367,7 +549,7 @@ func work(){ // Write placeholder for hash of key fout.Write(make([]byte,192)) - // Write placeholder for Blake2 CRC + // Write placeholder for Blake3 CRC fout.Write(make([]byte,160)) @@ -410,7 +592,7 @@ func work(){ fin.Read(crcHash) crcHash = rsDecode(crcHash,rs32_128,32) - _tmp := math.Ceil(float64(total-int64(metadataLength+919))/float64(1048744)) + _tmp := math.Ceil(float64(total-int64(metadataLength+1063))/float64(1048744)) nonces = make([]byte,int(_tmp*152)+144) fin.Read(nonces) @@ -448,12 +630,12 @@ func work(){ defer fout.Close() } - crc,_ := blake2b.New256(nil) + crc := blake3.New() done := 0 counter := 0 startTime := time.Now() - + cipher,_ := chacha20poly1305.NewX(key) if mode=="decrypt"{ @@ -482,6 +664,9 @@ func work(){ //fmt.Println("UNENCRYPTED NONCES: ",nonces) } for{ + if !working{ + return + } //fmt.Println("Encrypt/decrypt loop") var _data []byte var data []byte @@ -512,9 +697,16 @@ func work(){ //fmt.Println("Data nonce: ",_nonce) //fmt.Println("Data: ",data) if mode=="encrypt"{ - data = cipher.Seal(nil,_nonce,data,nil) + if fast{ + data = cipher.Seal(nil,_nonce,data,nil) + fout.Write(data) + }else{ + mac,data := monocypher.Lock(data,_nonce,key) + fout.Write(data) + fout.Write(mac) + } crc.Write(data) - fout.Write(data) + //fout.Write(data) }else{ //fmt.Println("DECODE LOOP") crc.Write(data) @@ -526,6 +718,7 @@ func work(){ done += 1048576 counter++ + progress = float32(done)/float32(total) elapsed:= float64(int64(time.Now().Sub(startTime)))/float64(1000000000) @@ -538,7 +731,6 @@ func work(){ status = fmt.Sprintf("Working at %.2f MB/s (ETA: %.1fs)",speed,eta) g.Update() - data = nil } if mode=="encrypt"{ @@ -571,6 +763,111 @@ func work(){ fmt.Println("==============================") resetUI() status = "Completed." + working = false +} + +// Generate file checksums +func generateChecksums(file string){ + fin,_ := os.Open(file) + + cs_md5 = "" + cs_sha1 = "" + cs_sha256 = "" + cs_sha3_256 = "" + cs_blake2b = "" + cs_blake2s = "" + cs_blake3 = "" + + if md5_selected{ + cs_md5 = "Calculating..." + } + if sha1_selected{ + cs_sha1 = "Calculating..." + } + if sha256_selected{ + cs_sha256 = "Calculating..." + } + if sha3_256_selected{ + cs_sha3_256 = "Calculating..." + } + if blake2b_selected{ + cs_blake2b = "Calculating..." + } + if blake2s_selected{ + cs_blake2s = "Calculating..." + } + if blake3_selected{ + cs_blake3 = "Calculating..." + } + + crc_md5 := md5.New() + crc_sha1 := sha1.New() + crc_sha256 := sha256.New() + crc_sha3_256 := sha3.New256() + crc_blake2b,_ := blake2b.New256(nil) + crc_blake2s,_ := blake2s.New256(nil) + crc_blake3 := blake3.New() + stat,_ := os.Stat(file) + total := stat.Size() + var done int64 = 0 + for{ + var data []byte + _data := make([]byte,1048576) + size,err := fin.Read(_data) + if err!=nil{ + break + } + data = _data[:size] + + if md5_selected{ + crc_md5.Write(data) + } + if sha1_selected{ + crc_sha1.Write(data) + } + if sha256_selected{ + crc_sha256.Write(data) + } + if sha3_256_selected{ + crc_sha3_256.Write(data) + } + if blake2b_selected{ + crc_blake2b.Write(data) + } + if blake2s_selected{ + crc_blake2s.Write(data) + } + if blake3_selected{ + crc_blake3.Write(data) + } + + done += int64(size) + cs_progress = float32(done)/float32(total) + g.Update() + } + cs_progress = 0 + if md5_selected{ + cs_md5 = hex.EncodeToString(crc_md5.Sum(nil)) + } + if sha1_selected{ + cs_sha1 = hex.EncodeToString(crc_sha1.Sum(nil)) + } + if sha256_selected{ + cs_sha256 = hex.EncodeToString(crc_sha256.Sum(nil)) + } + if sha3_256_selected{ + cs_sha3_256 = hex.EncodeToString(crc_sha3_256.Sum(nil)) + } + if blake2b_selected{ + cs_blake2b = hex.EncodeToString(crc_blake2b.Sum(nil)) + } + if blake2s_selected{ + cs_blake2s = hex.EncodeToString(crc_blake2s.Sum(nil)) + } + if blake3_selected{ + cs_blake3 = hex.EncodeToString(crc_blake3.Sum(nil)) + } + g.Update() } // Reset the UI to a clean state with no nothing selected @@ -585,6 +882,9 @@ func resetUI(){ keep = false erase = false reedsolo = false + split = false + splitSize = "" + fast = false progress = 0 progressInfo = "" g.Update() @@ -618,8 +918,7 @@ func rsDecode(data []byte,encoder reedsolomon.Encoder,size int) []byte{ // Create the master window, set callbacks, and start the UI func main(){ - window := g.NewMasterWindow("Picocrypt",480,470,g.MasterWindowFlagsNotResizable,nil) - window.SetBgColor(color.RGBA{0xf5,0xf6,0xf7,255}) + window := g.NewMasterWindow("Picocrypt",480,466,g.MasterWindowFlagsNotResizable,nil) window.SetDropCallback(onDrop) dpi = g.Context.GetPlatform().GetContentScale() window.Run(startUI)