2021-05-30 07:23:22 +12:00
|
|
|
package main
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
Picocrypt v1.18
|
2021-05-30 07:23:22 +12:00
|
|
|
Copyright (c) Evan Su (https://evansu.cc)
|
|
|
|
Released under a GNU GPL v3 License
|
|
|
|
https://github.com/HACKERALERT/Picocrypt
|
|
|
|
|
|
|
|
~ In cryptography we trust ~
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
import (
|
2021-08-08 06:45:13 +12:00
|
|
|
_ "embed"
|
|
|
|
|
|
|
|
// Generic
|
2021-09-25 12:19:18 +12:00
|
|
|
"archive/zip"
|
|
|
|
"bytes"
|
|
|
|
"encoding/hex"
|
|
|
|
"encoding/json"
|
2021-08-08 06:45:13 +12:00
|
|
|
"fmt"
|
2021-09-25 12:19:18 +12:00
|
|
|
"hash"
|
|
|
|
"image"
|
|
|
|
"image/color"
|
|
|
|
"image/png"
|
2021-05-30 07:23:22 +12:00
|
|
|
"io"
|
2021-08-08 06:45:13 +12:00
|
|
|
"io/ioutil"
|
2021-05-30 07:23:22 +12:00
|
|
|
"math"
|
2021-08-10 11:51:25 +12:00
|
|
|
"math/big"
|
2021-05-30 07:23:22 +12:00
|
|
|
"net/http"
|
2021-09-25 12:19:18 +12:00
|
|
|
"os"
|
|
|
|
"os/exec"
|
2021-05-30 07:23:22 +12:00
|
|
|
"path/filepath"
|
2021-09-25 12:19:18 +12:00
|
|
|
"regexp"
|
|
|
|
"runtime"
|
2021-05-30 07:23:22 +12:00
|
|
|
"runtime/debug"
|
2021-09-25 12:19:18 +12:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
"syscall"
|
|
|
|
"time"
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
// Cryptography
|
|
|
|
"crypto/cipher"
|
2021-09-25 12:19:18 +12:00
|
|
|
"crypto/hmac"
|
2021-08-08 06:45:13 +12:00
|
|
|
"crypto/md5"
|
2021-09-25 12:19:18 +12:00
|
|
|
"crypto/rand"
|
2021-08-08 06:45:13 +12:00
|
|
|
"crypto/sha1"
|
|
|
|
"crypto/sha256"
|
2021-09-25 12:19:18 +12:00
|
|
|
"crypto/subtle"
|
|
|
|
|
|
|
|
"github.com/HACKERALERT/serpent"
|
2021-05-30 07:23:22 +12:00
|
|
|
"golang.org/x/crypto/argon2"
|
|
|
|
"golang.org/x/crypto/blake2b"
|
|
|
|
"golang.org/x/crypto/blake2s"
|
2021-08-08 06:45:13 +12:00
|
|
|
"golang.org/x/crypto/chacha20"
|
2021-09-25 12:19:18 +12:00
|
|
|
"golang.org/x/crypto/hkdf"
|
|
|
|
"golang.org/x/crypto/sha3"
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// UI
|
2021-08-08 06:45:13 +12:00
|
|
|
"github.com/AllenDang/giu"
|
|
|
|
|
|
|
|
// Reed-Solomon
|
2021-09-25 12:19:18 +12:00
|
|
|
"github.com/HACKERALERT/infectious"
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
// Helpers
|
2021-09-25 12:19:18 +12:00
|
|
|
"github.com/HACKERALERT/clipboard"
|
|
|
|
"github.com/HACKERALERT/dialog"
|
|
|
|
"github.com/HACKERALERT/jibber_jabber"
|
|
|
|
"github.com/HACKERALERT/zxcvbn-go"
|
2021-05-30 07:23:22 +12:00
|
|
|
)
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
//go:embed icon.png
|
|
|
|
var icon []byte
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-05 10:40:55 +12:00
|
|
|
//go:embed font.ttf
|
2021-08-08 06:45:13 +12:00
|
|
|
var font []byte
|
2021-09-05 10:40:55 +12:00
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
//go:embed sdelete64.exe
|
|
|
|
var sdelete64bytes []byte
|
2021-09-05 10:40:55 +12:00
|
|
|
|
|
|
|
//go:embed strings.json
|
|
|
|
var localeBytes []byte
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// Localization
|
|
|
|
type locale struct {
|
|
|
|
iso string
|
2021-09-05 10:40:55 +12:00
|
|
|
data []string
|
|
|
|
}
|
|
|
|
|
|
|
|
var locales []locale
|
|
|
|
var selectedLocale = "en"
|
|
|
|
var allLocales = []string{
|
|
|
|
"en",
|
|
|
|
}
|
2021-08-08 06:45:13 +12:00
|
|
|
var languages = []string{
|
|
|
|
"English",
|
|
|
|
}
|
|
|
|
var languageSelected int32
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// Generic variables
|
|
|
|
var version = "v1.18"
|
|
|
|
var dpi float32
|
|
|
|
var tab = 0
|
|
|
|
var mode string
|
|
|
|
var working bool
|
|
|
|
var recombine bool
|
|
|
|
var fill float32 = -0.0000001
|
|
|
|
var sdelete64path string
|
|
|
|
|
|
|
|
// Three variables store the input files
|
|
|
|
var onlyFiles []string
|
|
|
|
var onlyFolders []string
|
|
|
|
var allFiles []string
|
|
|
|
|
|
|
|
// Input file variables
|
|
|
|
var inputLabel = "Drop files and folders into this window."
|
2021-05-30 07:23:22 +12:00
|
|
|
var inputFile string
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// Password variables
|
2021-05-30 07:23:22 +12:00
|
|
|
var password string
|
2021-09-25 12:19:18 +12:00
|
|
|
var cPassword string
|
|
|
|
var passwordStrength int
|
2021-08-11 15:35:35 +12:00
|
|
|
var passwordState = giu.InputTextFlagsPassword
|
|
|
|
var passwordStateLabel = "Show"
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// Password generator variables
|
2021-08-11 15:35:35 +12:00
|
|
|
var showGenpass = false
|
|
|
|
var genpassCopy = true
|
|
|
|
var genpassLength int32 = 32
|
|
|
|
var genpassUpper = true
|
|
|
|
var genpassLower = true
|
|
|
|
var genpassNums = true
|
|
|
|
var genpassSymbols = true
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// Keyfile variables
|
|
|
|
var keyfile bool
|
|
|
|
var keyfiles []string
|
|
|
|
var keyfileOrderMatters bool
|
|
|
|
var keyfilePrompt = "None selected."
|
|
|
|
var showKeyfile bool
|
|
|
|
|
|
|
|
// Metadata variables
|
|
|
|
var metadata string
|
|
|
|
var metadataPrompt = "Metadata:"
|
|
|
|
var metadataDisabled bool
|
|
|
|
|
|
|
|
// Advanced options
|
|
|
|
var shredTemp bool
|
|
|
|
var fast bool
|
|
|
|
var paranoid bool
|
|
|
|
var reedsolo bool
|
|
|
|
var deleteWhenDone bool
|
|
|
|
var split bool
|
|
|
|
var splitSize string
|
|
|
|
var splitUnits = []string{
|
|
|
|
"KiB",
|
|
|
|
"MiB",
|
|
|
|
"GiB",
|
|
|
|
}
|
|
|
|
var splitSelected int32 = 1
|
|
|
|
var compress bool
|
|
|
|
var encryptFilename bool
|
|
|
|
var keep bool
|
|
|
|
var kept bool
|
|
|
|
|
|
|
|
// Output file variables
|
|
|
|
var outputFile string
|
|
|
|
|
|
|
|
// Status variables
|
|
|
|
var mainStatus = "Ready."
|
|
|
|
var mainStatusColor = color.RGBA{0xff, 0xff, 0xff, 0xff}
|
|
|
|
var popupStatus string
|
|
|
|
|
|
|
|
// Progress variables
|
|
|
|
var progress float32
|
|
|
|
var progressInfo string
|
|
|
|
var showProgress bool
|
|
|
|
|
|
|
|
// Confirm overwrite variables
|
|
|
|
var showConfirmation bool
|
|
|
|
|
2021-05-30 07:23:22 +12:00
|
|
|
// Reed-Solomon encoders
|
2021-09-25 12:19:18 +12:00
|
|
|
var rs1, _ = infectious.NewFEC(1, 3) // 1 data shard, 3 total -> 2 parity shards
|
|
|
|
var rs5, _ = infectious.NewFEC(5, 15)
|
|
|
|
var rs6, _ = infectious.NewFEC(6, 18)
|
|
|
|
var rs16, _ = infectious.NewFEC(16, 48)
|
|
|
|
var rs24, _ = infectious.NewFEC(24, 72)
|
|
|
|
var rs32, _ = infectious.NewFEC(32, 96)
|
|
|
|
var rs64, _ = infectious.NewFEC(64, 192)
|
|
|
|
var rs128, _ = infectious.NewFEC(128, 136)
|
2021-05-30 07:23:22 +12:00
|
|
|
|
|
|
|
// File checksum generator variables
|
2021-09-25 12:19:18 +12:00
|
|
|
var csMd5 string
|
|
|
|
var csSha1 string
|
|
|
|
var csSha256 string
|
|
|
|
var csSha3 string
|
|
|
|
var csBlake2b string
|
|
|
|
var csBlake2s string
|
|
|
|
var csValidate string
|
|
|
|
var md5Color = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
var sha1Color = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
var sha256Color = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
var sha3Color = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
var blake2bColor = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
var blake2sColor = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
var csProgress float32 = 0
|
|
|
|
var md5Selected = true
|
|
|
|
var sha1Selected = true
|
|
|
|
var sha256Selected = true
|
|
|
|
var sha3Selected = false
|
|
|
|
var blake2bSelected = false
|
|
|
|
var blake2sSelected = false
|
|
|
|
|
|
|
|
// Shredder variables
|
|
|
|
var shredding string = "Ready."
|
|
|
|
var shredPasses int32 = 4
|
|
|
|
var stopShredding bool
|
|
|
|
var shredProgress float32
|
|
|
|
var shredDone float32
|
|
|
|
var shredTotal float32
|
|
|
|
var shredOverlay string
|
2021-09-05 10:40:55 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
func draw() {
|
2021-08-08 06:45:13 +12:00
|
|
|
giu.SingleWindow().Layout(
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Custom(func() {
|
|
|
|
pos := giu.GetCursorPos()
|
|
|
|
w, _ := giu.CalcTextSize(languages[languageSelected])
|
|
|
|
giu.Row(
|
|
|
|
giu.Dummy(-w/dpi-34, 0),
|
|
|
|
giu.Combo("##language", languages[languageSelected], languages, &languageSelected).OnChange(func() {
|
|
|
|
selectedLocale = allLocales[languageSelected]
|
|
|
|
shredding = s(shredding)
|
|
|
|
}).Size(w/dpi+26),
|
|
|
|
).Build()
|
|
|
|
giu.SetCursorPos(pos)
|
|
|
|
|
|
|
|
giu.TabBar().TabItems(
|
|
|
|
giu.TabItem(s("Encryption")).Layout(
|
|
|
|
giu.Custom(func() {
|
|
|
|
if giu.IsItemActive() {
|
|
|
|
tab = 0
|
|
|
|
}
|
|
|
|
}),
|
2021-08-11 15:35:35 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Custom(func() {
|
|
|
|
if showGenpass {
|
|
|
|
giu.PopupModal(s("Generate password:")).
|
|
|
|
Flags(giu.WindowFlagsNoMove|giu.WindowFlagsNoResize).Layout(
|
|
|
|
giu.Row(
|
|
|
|
giu.Label(s("Length:")),
|
|
|
|
giu.SliderInt(&genpassLength, 4, 64).Size(fill),
|
|
|
|
),
|
|
|
|
giu.Checkbox(s("Uppercase"), &genpassUpper),
|
|
|
|
giu.Checkbox(s("Lowercase"), &genpassLower),
|
|
|
|
giu.Checkbox(s("Numbers"), &genpassNums),
|
|
|
|
giu.Checkbox(s("Symbols"), &genpassSymbols),
|
|
|
|
giu.Checkbox(s("Copy to clipboard"), &genpassCopy),
|
|
|
|
giu.Row(
|
|
|
|
giu.Button(s("Cancel")).Size(100, 0).OnClick(func() {
|
|
|
|
giu.CloseCurrentPopup()
|
|
|
|
showGenpass = false
|
|
|
|
}),
|
|
|
|
giu.Button(s("Generate")).Size(100, 0).OnClick(func() {
|
|
|
|
tmp := genPassword()
|
|
|
|
password = tmp
|
|
|
|
cPassword = tmp
|
|
|
|
passwordStrength = zxcvbn.PasswordStrength(password, nil).Score
|
|
|
|
giu.CloseCurrentPopup()
|
|
|
|
showGenpass = false
|
|
|
|
giu.Update()
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
).Build()
|
|
|
|
giu.OpenPopup(s("Generate password:"))
|
|
|
|
giu.Update()
|
|
|
|
}
|
|
|
|
}),
|
2021-09-05 10:40:55 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Custom(func() {
|
|
|
|
if showKeyfile {
|
|
|
|
giu.PopupModal(s("Manage keyfiles:")).
|
|
|
|
Flags(giu.WindowFlagsNoMove|giu.WindowFlagsNoResize).Layout(
|
|
|
|
giu.Row(
|
|
|
|
giu.Label(s("Drop and drop your keyfiles.")),
|
|
|
|
),
|
|
|
|
giu.Custom(func() {
|
|
|
|
if mode != "decrypt" {
|
|
|
|
giu.Checkbox(s("Require correct keyfile order"), &keyfileOrderMatters).Build()
|
|
|
|
giu.Tooltip(s("If checked, you will need to drop keyfiles in the correct order.")).Build()
|
|
|
|
} else if keyfileOrderMatters {
|
|
|
|
giu.Label(s("The correct order of keyfiles is required.")).Build()
|
|
|
|
}
|
|
|
|
}),
|
2021-09-05 10:40:55 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Custom(func() {
|
|
|
|
for _, i := range keyfiles {
|
|
|
|
giu.Row(
|
|
|
|
giu.Label(filepath.Base(i)),
|
|
|
|
giu.Button("Remove").OnClick(func() {
|
|
|
|
var tmp []string
|
|
|
|
for _, j := range keyfiles {
|
|
|
|
if j != i {
|
|
|
|
tmp = append(tmp, j)
|
2021-09-05 10:40:55 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
}
|
|
|
|
keyfiles = tmp
|
|
|
|
}),
|
|
|
|
).Build()
|
2021-09-05 10:40:55 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
}
|
|
|
|
}),
|
|
|
|
giu.Dummy(0, 200),
|
|
|
|
giu.Row(
|
|
|
|
giu.Button(s("Clear")).Size(150, 0).OnClick(func() {
|
|
|
|
keyfiles = nil
|
2021-09-05 10:40:55 +12:00
|
|
|
}),
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Tooltip(s("Remove all keyfiles.")),
|
|
|
|
giu.Button(s("Done")).Size(150, 0).OnClick(func() {
|
|
|
|
giu.CloseCurrentPopup()
|
|
|
|
showKeyfile = false
|
2021-09-05 10:40:55 +12:00
|
|
|
}),
|
2021-09-25 12:19:18 +12:00
|
|
|
),
|
|
|
|
).Build()
|
|
|
|
giu.OpenPopup(s("Manage keyfiles:"))
|
|
|
|
giu.Update()
|
|
|
|
}
|
|
|
|
}),
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Custom(func() {
|
|
|
|
if showConfirmation {
|
|
|
|
giu.PopupModal(s("Warning:")).
|
|
|
|
Flags(giu.WindowFlagsNoMove|giu.WindowFlagsNoResize).Layout(
|
|
|
|
giu.Label(s("Output already exists. Overwrite?")),
|
|
|
|
giu.Row(
|
|
|
|
giu.Button(s("No")).Size(100, 0).OnClick(func() {
|
|
|
|
giu.CloseCurrentPopup()
|
|
|
|
showConfirmation = false
|
2021-08-08 06:45:13 +12:00
|
|
|
}),
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Button(s("Yes")).Size(100, 0).OnClick(func() {
|
|
|
|
giu.CloseCurrentPopup()
|
|
|
|
showConfirmation = false
|
|
|
|
showProgress = true
|
|
|
|
giu.Update()
|
|
|
|
go func() {
|
|
|
|
work()
|
2021-08-08 06:45:13 +12:00
|
|
|
working = false
|
2021-09-25 12:19:18 +12:00
|
|
|
showProgress = false
|
|
|
|
debug.FreeOSMemory()
|
|
|
|
giu.Update()
|
|
|
|
}()
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
).Build()
|
|
|
|
giu.OpenPopup(s("Warning:"))
|
|
|
|
giu.Update()
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
|
|
|
|
giu.Custom(func() {
|
|
|
|
if showProgress {
|
|
|
|
giu.PopupModal(" ").
|
|
|
|
Flags(giu.WindowFlagsNoMove|giu.WindowFlagsNoResize|giu.WindowFlagsNoTitleBar).Layout(
|
|
|
|
giu.Custom(func() {
|
|
|
|
if !working {
|
|
|
|
giu.CloseCurrentPopup()
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
giu.Row(
|
|
|
|
giu.ProgressBar(progress).Size(280, 0).Overlay(progressInfo),
|
|
|
|
giu.Button(s("Cancel")).Size(58, 0).OnClick(func() {
|
|
|
|
working = false
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
giu.Label(popupStatus),
|
|
|
|
).Build()
|
|
|
|
giu.OpenPopup(" ")
|
|
|
|
giu.Update()
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
|
|
|
|
giu.Row(
|
|
|
|
giu.Label(inputLabel),
|
|
|
|
giu.Custom(func() {
|
|
|
|
w, _ := giu.GetAvailableRegion()
|
|
|
|
bw, _ := giu.CalcTextSize(s("Clear"))
|
|
|
|
p, _ := giu.GetWindowPadding()
|
|
|
|
bw += p * 2
|
|
|
|
dw := w - bw - p
|
|
|
|
giu.Dummy(dw/dpi, 0).Build()
|
|
|
|
giu.SameLine()
|
|
|
|
giu.Style().SetDisabled(len(allFiles) == 0 && len(onlyFiles) == 0).To(
|
|
|
|
giu.Button(s("Clear")).Size(bw/dpi, 0).OnClick(resetUI),
|
|
|
|
giu.Tooltip(s("Clear all input files and reset UI state.")),
|
|
|
|
).Build()
|
2021-08-08 06:45:13 +12:00
|
|
|
}),
|
2021-09-25 12:19:18 +12:00
|
|
|
),
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Separator(),
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Style().SetDisabled(len(allFiles) == 0 && len(onlyFiles) == 0).To(
|
2021-08-08 06:45:13 +12:00
|
|
|
giu.Row(
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Label(s("Password:")),
|
|
|
|
giu.Dummy(-124/dpi, 0),
|
|
|
|
giu.Style().SetDisabled(mode == "decrypt" && !keyfile).To(
|
|
|
|
giu.Label(s("Keyfiles:")),
|
|
|
|
),
|
2021-08-08 06:45:13 +12:00
|
|
|
),
|
|
|
|
giu.Row(
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Button(s(passwordStateLabel)).Size(54, 0).OnClick(func() {
|
|
|
|
if passwordState == giu.InputTextFlagsPassword {
|
|
|
|
passwordState = giu.InputTextFlagsNone
|
|
|
|
passwordStateLabel = "Hide"
|
|
|
|
} else {
|
|
|
|
passwordState = giu.InputTextFlagsPassword
|
|
|
|
passwordStateLabel = "Show"
|
2021-09-05 10:40:55 +12:00
|
|
|
}
|
|
|
|
}),
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Button(s("Clear")).Size(54, 0).OnClick(func() {
|
2021-09-05 10:40:55 +12:00
|
|
|
password = ""
|
|
|
|
cPassword = ""
|
2021-09-25 12:19:18 +12:00
|
|
|
}),
|
2021-09-05 10:40:55 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Button(s("Copy")).Size(54, 0).OnClick(func() {
|
|
|
|
clipboard.WriteAll(password)
|
|
|
|
}),
|
|
|
|
|
|
|
|
giu.Button(s("Paste")).Size(54, 0).OnClick(func() {
|
|
|
|
tmp, _ := clipboard.ReadAll()
|
|
|
|
password = tmp
|
|
|
|
if mode != "decrypt" {
|
|
|
|
cPassword = tmp
|
2021-09-05 10:40:55 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
passwordStrength = zxcvbn.PasswordStrength(password, nil).Score
|
|
|
|
giu.Update()
|
2021-08-10 11:51:25 +12:00
|
|
|
}),
|
2021-09-25 12:19:18 +12:00
|
|
|
|
|
|
|
giu.Style().SetDisabled(mode == "decrypt").To(
|
|
|
|
giu.Button(s("Create")).Size(54, 0).OnClick(func() {
|
|
|
|
showGenpass = true
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
|
|
|
|
giu.Style().SetDisabled(mode == "decrypt" && !keyfile).To(
|
|
|
|
giu.Row(
|
|
|
|
giu.Button(s("Edit")).Size(54, 0).OnClick(func() {
|
|
|
|
showKeyfile = true
|
|
|
|
}),
|
|
|
|
giu.Style().SetDisabled(mode == "decrypt").To(
|
|
|
|
giu.Button(s("Create")).Size(54, 0).OnClick(func() {
|
|
|
|
file, _ := dialog.File().Title(s("Save keyfile as:")).Save()
|
|
|
|
if file == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
fout, _ := os.Create(file)
|
|
|
|
data := make([]byte, 1048576)
|
|
|
|
rand.Read(data)
|
|
|
|
fout.Write(data)
|
|
|
|
fout.Close()
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
2021-08-08 06:45:13 +12:00
|
|
|
),
|
|
|
|
giu.Row(
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.InputText(&password).Flags(passwordState).Size(302/dpi).OnChange(func() {
|
|
|
|
passwordStrength = zxcvbn.PasswordStrength(password, nil).Score
|
2021-08-08 06:45:13 +12:00
|
|
|
}),
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Custom(func() {
|
|
|
|
c := giu.GetCanvas()
|
|
|
|
p := giu.GetCursorScreenPos()
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
var col color.RGBA
|
2021-09-25 12:19:18 +12:00
|
|
|
switch passwordStrength {
|
|
|
|
case 0:
|
|
|
|
col = color.RGBA{0xc8, 0x4c, 0x4b, 0xff}
|
|
|
|
case 1:
|
|
|
|
col = color.RGBA{0xa9, 0x6b, 0x4b, 0xff}
|
|
|
|
case 2:
|
|
|
|
col = color.RGBA{0x8a, 0x8a, 0x4b, 0xff}
|
|
|
|
case 3:
|
|
|
|
col = color.RGBA{0x6b, 0xa9, 0x4b, 0xff}
|
|
|
|
case 4:
|
|
|
|
col = color.RGBA{0x4c, 0xc8, 0x4b, 0xff}
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if password == "" || mode == "decrypt" {
|
|
|
|
col = color.RGBA{0xff, 0xff, 0xff, 0x00}
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
path := p.Add(image.Pt(
|
|
|
|
int(math.Round(float64(-20*dpi))),
|
2021-08-08 06:45:13 +12:00
|
|
|
int(math.Round(float64(12*dpi))),
|
|
|
|
))
|
2021-09-25 12:19:18 +12:00
|
|
|
c.PathArcTo(path, 6*dpi, -math.Pi/2, float32(passwordStrength+1)/5*2*math.Pi-math.Pi/2, -1)
|
|
|
|
c.PathStroke(col, false, 2)
|
2021-05-30 07:23:22 +12:00
|
|
|
}),
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Style().SetDisabled(true).To(
|
|
|
|
giu.InputText(&keyfilePrompt).Size(fill),
|
|
|
|
),
|
2021-08-08 06:45:13 +12:00
|
|
|
),
|
2021-09-25 12:19:18 +12:00
|
|
|
),
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Style().SetDisabled(password == "").To(
|
|
|
|
giu.Row(
|
|
|
|
giu.Style().SetDisabled(mode == "decrypt").To(
|
|
|
|
giu.Label(s("Confirm password:")),
|
|
|
|
),
|
|
|
|
giu.Dummy(-124/dpi, 0),
|
|
|
|
giu.Style().SetDisabled(true).To(
|
|
|
|
giu.Label(s("Custom Argon2:")),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
giu.Style().SetDisabled(password == "").To(
|
|
|
|
giu.Row(
|
|
|
|
giu.Style().SetDisabled(mode == "decrypt").To(
|
2021-08-11 15:35:35 +12:00
|
|
|
giu.Row(
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.InputText(&cPassword).Flags(passwordState).Size(302/dpi),
|
|
|
|
giu.Custom(func() {
|
|
|
|
c := giu.GetCanvas()
|
|
|
|
p := giu.GetCursorScreenPos()
|
|
|
|
col := color.RGBA{0x4c, 0xc8, 0x4b, 0xff}
|
|
|
|
|
|
|
|
if cPassword != password {
|
|
|
|
col = color.RGBA{0xc8, 0x4c, 0x4b, 0xff}
|
2021-08-11 15:35:35 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if password == "" || cPassword == "" || mode == "decrypt" {
|
|
|
|
col = color.RGBA{0xff, 0xff, 0xff, 0x00}
|
2021-08-11 15:35:35 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
|
|
|
|
path := p.Add(image.Pt(
|
|
|
|
int(math.Round(float64(-20*dpi))),
|
2021-08-11 15:35:35 +12:00
|
|
|
int(math.Round(float64(12*dpi))),
|
|
|
|
))
|
2021-09-25 12:19:18 +12:00
|
|
|
c.PathArcTo(path, 6*dpi, 0, 2*math.Pi, -1)
|
|
|
|
c.PathStroke(col, false, 2)
|
2021-08-11 15:35:35 +12:00
|
|
|
}),
|
2021-09-25 12:19:18 +12:00
|
|
|
),
|
|
|
|
),
|
|
|
|
giu.Style().SetDisabled(true).To(
|
2021-09-25 12:22:58 +12:00
|
|
|
giu.Button(s("W.I.P")).Size(fill, 0),
|
2021-09-25 12:19:18 +12:00
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
2021-09-05 10:40:55 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Dummy(0, 3),
|
|
|
|
giu.Separator(),
|
|
|
|
giu.Dummy(0, 0),
|
2021-09-05 10:40:55 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Style().SetDisabled(password == "" || (password != cPassword && mode == "encrypt")).To(
|
|
|
|
giu.Label(s(metadataPrompt)),
|
|
|
|
giu.Style().SetDisabled(metadataDisabled).To(
|
|
|
|
giu.InputText(&metadata).Size(fill),
|
|
|
|
),
|
2021-09-05 10:40:55 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Label(s("Advanced:")),
|
|
|
|
giu.Custom(func() {
|
|
|
|
if mode != "decrypt" {
|
2021-08-08 06:45:13 +12:00
|
|
|
giu.Row(
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Checkbox(s("Shred temporary files"), &shredTemp),
|
|
|
|
giu.Dummy(-221/dpi, 0),
|
|
|
|
giu.Checkbox(s("Encode with Reed-Solomon"), &reedsolo),
|
2021-08-08 06:45:13 +12:00
|
|
|
).Build()
|
|
|
|
giu.Row(
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Checkbox(s("Use fast mode"), &fast),
|
|
|
|
giu.Dummy(-221/dpi, 0),
|
|
|
|
giu.Checkbox(s("Delete files when complete"), &deleteWhenDone),
|
2021-08-08 06:45:13 +12:00
|
|
|
).Build()
|
2021-09-05 10:40:55 +12:00
|
|
|
giu.Row(
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Checkbox(s("Use paranoid mode"), ¶noid),
|
|
|
|
giu.Dummy(-221/dpi, 0),
|
|
|
|
giu.Style().SetDisabled(!(len(allFiles) > 1 || len(onlyFolders) > 0)).To(
|
|
|
|
giu.Checkbox(s("Compress files"), &compress),
|
|
|
|
),
|
2021-09-05 10:40:55 +12:00
|
|
|
).Build()
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Row(
|
2021-09-25 12:22:58 +12:00
|
|
|
giu.Style().SetDisabled(true).To(
|
|
|
|
giu.Checkbox(s("Encrypt filename (W.I.P)"), &encryptFilename),
|
|
|
|
),
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Dummy(-221/dpi, 0),
|
|
|
|
giu.Checkbox(s("Split every"), &split),
|
|
|
|
giu.InputText(&splitSize).Size(55).Flags(giu.InputTextFlagsCharsHexadecimal).OnChange(func() {
|
|
|
|
split = splitSize != ""
|
|
|
|
}),
|
|
|
|
giu.Combo("##splitter", splitUnits[splitSelected], splitUnits, &splitSelected).Size(52),
|
|
|
|
).Build()
|
|
|
|
} else {
|
|
|
|
giu.Checkbox(s("Keep decrypted output even if it's corrupted or modified"), &keep).Build()
|
|
|
|
giu.Checkbox(s("Delete the encrypted files after a successful decryption"), &deleteWhenDone).Build()
|
|
|
|
giu.Dummy(0, 52).Build()
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
}),
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Label(s("Save output as:")),
|
|
|
|
giu.Custom(func() {
|
|
|
|
w, _ := giu.GetAvailableRegion()
|
|
|
|
bw, _ := giu.CalcTextSize(s("Change"))
|
|
|
|
p, _ := giu.GetWindowPadding()
|
|
|
|
bw += p * 2
|
|
|
|
dw := w - bw - p
|
|
|
|
giu.Style().SetDisabled(true).To(
|
|
|
|
giu.InputText(&outputFile).Size(dw / dpi).Flags(giu.InputTextFlagsReadOnly),
|
|
|
|
).Build()
|
|
|
|
giu.SameLine()
|
|
|
|
giu.Button(s("Change")).Size(bw/dpi, 0).OnClick(func() {
|
|
|
|
file, _ := dialog.File().Title(s("Save as:")).Save()
|
|
|
|
if file == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if mode == "encrypt" {
|
|
|
|
if len(allFiles) > 1 || len(onlyFolders) > 0 {
|
|
|
|
file = strings.TrimSuffix(file, ".zip.pcv")
|
|
|
|
file = strings.TrimSuffix(file, ".pcv")
|
|
|
|
if !strings.HasSuffix(file, ".zip.pcv") {
|
|
|
|
file += ".zip.pcv"
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
file = strings.TrimSuffix(file, ".pcv")
|
|
|
|
ind := strings.Index(inputFile, ".")
|
|
|
|
file += inputFile[ind:]
|
|
|
|
if !strings.HasSuffix(file, ".pcv") {
|
|
|
|
file += ".pcv"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ind := strings.Index(file, ".")
|
|
|
|
if ind != -1 {
|
|
|
|
file = file[:ind]
|
|
|
|
}
|
|
|
|
if strings.HasSuffix(inputFile, ".zip.pcv") {
|
|
|
|
file += ".zip"
|
|
|
|
} else {
|
|
|
|
tmp := strings.TrimSuffix(filepath.Base(inputFile), ".pcv")
|
|
|
|
tmp = tmp[strings.Index(tmp, "."):]
|
|
|
|
file += tmp
|
|
|
|
}
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
|
|
|
|
outputFile = file
|
|
|
|
}).Build()
|
|
|
|
giu.Tooltip(s("Save the output with a custom path and name.")).Build()
|
|
|
|
}),
|
|
|
|
|
|
|
|
giu.Dummy(0, 2),
|
|
|
|
giu.Separator(),
|
|
|
|
giu.Dummy(0, 3),
|
|
|
|
|
|
|
|
giu.Button(s("Start")).Size(fill, 34).OnClick(func() {
|
|
|
|
if keyfile && keyfiles == nil {
|
|
|
|
mainStatus = "Please select your keyfiles."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff}
|
|
|
|
return
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
_, err := os.Stat(outputFile)
|
|
|
|
if err == nil {
|
2021-08-08 06:45:13 +12:00
|
|
|
showConfirmation = true
|
|
|
|
giu.Update()
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
2021-08-08 06:45:13 +12:00
|
|
|
showProgress = true
|
|
|
|
giu.Update()
|
2021-09-25 12:19:18 +12:00
|
|
|
go func() {
|
2021-08-08 06:45:13 +12:00
|
|
|
work()
|
|
|
|
working = false
|
|
|
|
showProgress = false
|
|
|
|
debug.FreeOSMemory()
|
|
|
|
giu.Update()
|
|
|
|
}()
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
}),
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Style().SetColor(giu.StyleColorText, mainStatusColor).To(
|
|
|
|
giu.Label(s(mainStatus)),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
giu.TabItem(s("Checksum")).Layout(
|
|
|
|
giu.Custom(func() {
|
|
|
|
if giu.IsItemActive() {
|
|
|
|
tab = 1
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
giu.Label(s("Toggle the hashes you would like to generate and drop a file here.")),
|
|
|
|
|
|
|
|
// MD5
|
|
|
|
giu.Custom(func() {
|
|
|
|
giu.Checkbox("MD5:", &md5Selected).OnChange(func() {
|
|
|
|
csMd5 = ""
|
|
|
|
}).Build()
|
|
|
|
giu.SameLine()
|
|
|
|
w, _ := giu.GetAvailableRegion()
|
|
|
|
bw, _ := giu.CalcTextSize(s("Copy"))
|
|
|
|
padding, _ := giu.GetWindowPadding()
|
|
|
|
bw += 2 * padding
|
|
|
|
size := w - bw - padding
|
|
|
|
giu.Dummy(size/dpi, 0).Build()
|
|
|
|
giu.SameLine()
|
|
|
|
giu.Button(s("Copy")+"##md5").Size(bw/dpi, 0).OnClick(func() {
|
|
|
|
clipboard.WriteAll(csMd5)
|
|
|
|
}).Build()
|
|
|
|
}),
|
|
|
|
giu.Style().SetColor(giu.StyleColorBorder, md5Color).To(
|
|
|
|
giu.Style().SetDisabled(true).To(
|
|
|
|
giu.InputText(&csMd5).Size(fill).Flags(giu.InputTextFlagsReadOnly),
|
2021-08-08 06:45:13 +12:00
|
|
|
),
|
2021-05-30 07:23:22 +12:00
|
|
|
),
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// SHA1
|
|
|
|
giu.Custom(func() {
|
|
|
|
giu.Checkbox("SHA1:", &sha1Selected).OnChange(func() {
|
|
|
|
csSha1 = ""
|
|
|
|
}).Build()
|
|
|
|
giu.SameLine()
|
|
|
|
w, _ := giu.GetAvailableRegion()
|
|
|
|
bw, _ := giu.CalcTextSize(s("Copy"))
|
|
|
|
padding, _ := giu.GetWindowPadding()
|
|
|
|
bw += 2 * padding
|
|
|
|
size := w - bw - padding
|
|
|
|
giu.Dummy(size/dpi, 0).Build()
|
|
|
|
giu.SameLine()
|
|
|
|
giu.Button(s("Copy")+"##sha1").Size(bw/dpi, 0).OnClick(func() {
|
|
|
|
clipboard.WriteAll(csSha1)
|
|
|
|
}).Build()
|
|
|
|
}),
|
|
|
|
giu.Style().SetColor(giu.StyleColorBorder, sha1Color).To(
|
|
|
|
giu.Style().SetDisabled(true).To(
|
|
|
|
giu.InputText(&csSha1).Size(fill).Flags(giu.InputTextFlagsReadOnly),
|
2021-08-08 06:45:13 +12:00
|
|
|
),
|
2021-09-25 12:19:18 +12:00
|
|
|
),
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// SHA256
|
|
|
|
giu.Custom(func() {
|
|
|
|
giu.Checkbox("SHA256:", &sha256Selected).OnChange(func() {
|
|
|
|
csSha256 = ""
|
|
|
|
}).Build()
|
|
|
|
giu.SameLine()
|
|
|
|
w, _ := giu.GetAvailableRegion()
|
|
|
|
bw, _ := giu.CalcTextSize(s("Copy"))
|
|
|
|
padding, _ := giu.GetWindowPadding()
|
|
|
|
bw += 2 * padding
|
|
|
|
size := w - bw - padding
|
|
|
|
giu.Dummy(size/dpi, 0).Build()
|
|
|
|
giu.SameLine()
|
|
|
|
giu.Button(s("Copy")+"##sha256").Size(bw/dpi, 0).OnClick(func() {
|
|
|
|
clipboard.WriteAll(csSha256)
|
|
|
|
}).Build()
|
|
|
|
}),
|
|
|
|
giu.Style().SetColor(giu.StyleColorBorder, sha256Color).To(
|
|
|
|
giu.Style().SetDisabled(true).To(
|
|
|
|
giu.InputText(&csSha256).Size(fill).Flags(giu.InputTextFlagsReadOnly),
|
2021-08-08 06:45:13 +12:00
|
|
|
),
|
2021-09-25 12:19:18 +12:00
|
|
|
),
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// SHA3-256
|
|
|
|
giu.Custom(func() {
|
|
|
|
giu.Checkbox("SHA3:", &sha3Selected).OnChange(func() {
|
|
|
|
csSha3 = ""
|
|
|
|
}).Build()
|
|
|
|
giu.SameLine()
|
|
|
|
w, _ := giu.GetAvailableRegion()
|
|
|
|
bw, _ := giu.CalcTextSize(s("Copy"))
|
|
|
|
padding, _ := giu.GetWindowPadding()
|
|
|
|
bw += 2 * padding
|
|
|
|
size := w - bw - padding
|
|
|
|
giu.Dummy(size/dpi, 0).Build()
|
|
|
|
giu.SameLine()
|
|
|
|
giu.Button(s("Copy")+"##sha3").Size(bw/dpi, 0).OnClick(func() {
|
|
|
|
clipboard.WriteAll(csSha3)
|
|
|
|
}).Build()
|
|
|
|
}),
|
|
|
|
giu.Style().SetColor(giu.StyleColorBorder, sha3Color).To(
|
|
|
|
giu.Style().SetDisabled(true).To(
|
|
|
|
giu.InputText(&csSha3).Size(fill).Flags(giu.InputTextFlagsReadOnly),
|
2021-08-08 06:45:13 +12:00
|
|
|
),
|
2021-09-25 12:19:18 +12:00
|
|
|
),
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// BLAKE2b
|
|
|
|
giu.Custom(func() {
|
|
|
|
giu.Checkbox("BLAKE2b:", &blake2bSelected).OnChange(func() {
|
|
|
|
csBlake2b = ""
|
|
|
|
}).Build()
|
|
|
|
giu.SameLine()
|
|
|
|
w, _ := giu.GetAvailableRegion()
|
|
|
|
bw, _ := giu.CalcTextSize(s("Copy"))
|
|
|
|
padding, _ := giu.GetWindowPadding()
|
|
|
|
bw += 2 * padding
|
|
|
|
size := w - bw - padding
|
|
|
|
giu.Dummy(size/dpi, 0).Build()
|
|
|
|
giu.SameLine()
|
|
|
|
giu.Button(s("Copy")+"##blake2b").Size(bw/dpi, 0).OnClick(func() {
|
|
|
|
clipboard.WriteAll(csBlake2b)
|
|
|
|
}).Build()
|
|
|
|
}),
|
|
|
|
giu.Style().SetColor(giu.StyleColorBorder, blake2bColor).To(
|
|
|
|
giu.Style().SetDisabled(true).To(
|
|
|
|
giu.InputText(&csBlake2b).Size(fill).Flags(giu.InputTextFlagsReadOnly),
|
2021-08-08 06:45:13 +12:00
|
|
|
),
|
2021-09-25 12:19:18 +12:00
|
|
|
),
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// BLAKE2s
|
|
|
|
giu.Custom(func() {
|
|
|
|
giu.Checkbox("BLAKE2s:", &blake2sSelected).OnChange(func() {
|
|
|
|
csBlake2s = ""
|
|
|
|
}).Build()
|
|
|
|
giu.SameLine()
|
|
|
|
w, _ := giu.GetAvailableRegion()
|
|
|
|
bw, _ := giu.CalcTextSize(s("Copy"))
|
|
|
|
padding, _ := giu.GetWindowPadding()
|
|
|
|
bw += 2 * padding
|
|
|
|
size := w - bw - padding
|
|
|
|
giu.Dummy(size/dpi, 0).Build()
|
|
|
|
giu.SameLine()
|
|
|
|
giu.Button(s("Copy")+"##blake2s").Size(bw/dpi, 0).OnClick(func() {
|
|
|
|
clipboard.WriteAll(csBlake2s)
|
|
|
|
}).Build()
|
|
|
|
}),
|
|
|
|
giu.Style().SetColor(giu.StyleColorBorder, blake2sColor).To(
|
|
|
|
giu.Style().SetDisabled(true).To(
|
|
|
|
giu.InputText(&csBlake2s).Size(fill).Flags(giu.InputTextFlagsReadOnly),
|
2021-08-08 06:45:13 +12:00
|
|
|
),
|
2021-09-25 12:19:18 +12:00
|
|
|
),
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Dummy(0, 23),
|
|
|
|
// Input entry for validating a checksum
|
|
|
|
giu.Row(
|
|
|
|
giu.Label(s("Validate a checksum:")),
|
|
|
|
giu.Custom(func() {
|
|
|
|
bw, _ := giu.CalcTextSize(s("Paste"))
|
|
|
|
padding, _ := giu.GetWindowPadding()
|
|
|
|
bw += 2 * padding
|
|
|
|
giu.Button(s("Paste")).Size(bw/dpi, 0).OnClick(func() {
|
|
|
|
tmp, _ := clipboard.ReadAll()
|
|
|
|
csValidate = tmp
|
|
|
|
md5Color = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
sha1Color = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
sha256Color = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
sha3Color = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
blake2bColor = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
blake2sColor = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
if csValidate == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
csValidate = strings.ToLower(csValidate)
|
|
|
|
if csValidate == csMd5 {
|
|
|
|
md5Color = color.RGBA{0x00, 0xff, 0x00, 0xff}
|
|
|
|
} else if csValidate == csSha1 {
|
|
|
|
sha1Color = color.RGBA{0x00, 0xff, 0x00, 0xff}
|
|
|
|
} else if csValidate == csSha256 {
|
|
|
|
sha256Color = color.RGBA{0x00, 0xff, 0x00, 0xff}
|
|
|
|
} else if csValidate == csSha3 {
|
|
|
|
sha3Color = color.RGBA{0x00, 0xff, 0x00, 0xff}
|
|
|
|
} else if csValidate == csBlake2b {
|
|
|
|
blake2bColor = color.RGBA{0x00, 0xff, 0x00, 0xff}
|
|
|
|
} else if csValidate == csBlake2s {
|
|
|
|
blake2sColor = color.RGBA{0x00, 0xff, 0x00, 0xff}
|
|
|
|
}
|
|
|
|
giu.Update()
|
2021-09-05 10:40:55 +12:00
|
|
|
}).Build()
|
|
|
|
}),
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Custom(func() {
|
|
|
|
bw, _ := giu.CalcTextSize(s("Paste"))
|
|
|
|
padding, _ := giu.GetWindowPadding()
|
|
|
|
bw += 2 * padding
|
|
|
|
giu.Button(s("Clear")).Size(bw/dpi, 0).OnClick(func() {
|
|
|
|
csValidate = ""
|
|
|
|
md5Color = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
sha1Color = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
sha256Color = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
sha3Color = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
blake2bColor = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
blake2sColor = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
}).Build()
|
2021-05-30 07:23:22 +12:00
|
|
|
}),
|
2021-09-25 12:19:18 +12:00
|
|
|
),
|
|
|
|
giu.Style().SetDisabled(true).To(
|
|
|
|
giu.InputText(&csValidate).Size(fill),
|
2021-05-30 07:23:22 +12:00
|
|
|
),
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// Progress bar
|
|
|
|
giu.Label(s("Progress:")),
|
|
|
|
giu.ProgressBar(csProgress).Size(fill, 0),
|
|
|
|
),
|
|
|
|
giu.TabItem(s("Shredder")).Layout(
|
|
|
|
giu.Custom(func() {
|
|
|
|
if giu.IsItemActive() {
|
|
|
|
tab = 2
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
|
|
|
|
giu.Label(s("Drop files and folders here to shred them.")),
|
|
|
|
giu.Custom(func() {
|
|
|
|
if runtime.GOOS == "darwin" {
|
|
|
|
giu.Label(s("Number of passes: Not supported on macOS")).Build()
|
|
|
|
} else {
|
2021-09-05 10:40:55 +12:00
|
|
|
giu.Row(
|
2021-09-25 12:19:18 +12:00
|
|
|
giu.Label(s("Number of passes:")),
|
|
|
|
giu.SliderInt(&shredPasses, 1, 32).Size(fill),
|
2021-09-05 10:40:55 +12:00
|
|
|
).Build()
|
2021-09-25 12:19:18 +12:00
|
|
|
}
|
|
|
|
}),
|
|
|
|
giu.Dummy(0, -50),
|
|
|
|
giu.Custom(func() {
|
|
|
|
w, _ := giu.GetAvailableRegion()
|
|
|
|
bw, _ := giu.CalcTextSize(s("Cancel"))
|
|
|
|
padding, _ := giu.GetWindowPadding()
|
|
|
|
bw += 2 * padding
|
|
|
|
size := w - bw - padding
|
|
|
|
giu.Row(
|
|
|
|
giu.ProgressBar(shredProgress).Overlay(shredOverlay).Size(size/dpi, 0),
|
|
|
|
giu.Button(s("Cancel")).Size(bw/dpi, 0).OnClick(func() {
|
|
|
|
stopShredding = true
|
|
|
|
shredding = s("Ready.")
|
|
|
|
shredProgress = 0
|
|
|
|
shredOverlay = ""
|
|
|
|
}),
|
|
|
|
).Build()
|
|
|
|
}),
|
|
|
|
giu.Custom(func() {
|
|
|
|
if len(shredding) > 60 {
|
|
|
|
shredding = "....." + shredding[len(shredding)-50:]
|
|
|
|
}
|
|
|
|
giu.Label(shredding).Wrapped(true).Build()
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
giu.TabItem(s("About")).Layout(
|
|
|
|
giu.Custom(func() {
|
|
|
|
if giu.IsItemActive() {
|
|
|
|
tab = 3
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
giu.Label(fmt.Sprintf(s("Picocrypt %s, created by Evan Su (https://evansu.cc/)."), version)),
|
|
|
|
giu.Label(s("Released under a GNU GPL v3 License.")),
|
|
|
|
giu.Label(s("A warm thank you to all the people listed below.")),
|
|
|
|
giu.Label(s("Patrons:")),
|
|
|
|
giu.Label(" - Frederick Doe"),
|
|
|
|
giu.Label(s("Donators:")),
|
|
|
|
giu.Label(" - jp26"),
|
|
|
|
giu.Label(" - W.Graham"),
|
|
|
|
giu.Label(" - N. Chin"),
|
|
|
|
giu.Label(" - Manjot"),
|
|
|
|
giu.Label(" - Phil P."),
|
|
|
|
giu.Label(" - E. Zahard"),
|
|
|
|
giu.Label(s("Translators:")),
|
|
|
|
giu.Label("umitseyhan75, digitalblossom, zeeaall, francirc, kurpau"),
|
|
|
|
giu.Label(s("Other:")),
|
|
|
|
giu.Label("Fuderal, u/greenreddits, u/Tall_Escape, u/NSABackdoors"),
|
|
|
|
),
|
|
|
|
).Build()
|
|
|
|
}),
|
2021-05-30 07:23:22 +12:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
func onDrop(names []string) {
|
|
|
|
if tab == 1 {
|
|
|
|
go generateChecksums(names[0])
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if tab == 2 {
|
|
|
|
go shred(names, true)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if showKeyfile {
|
|
|
|
keyfiles = append(keyfiles, names...)
|
|
|
|
tmp := []string{}
|
|
|
|
for _, i := range keyfiles {
|
|
|
|
duplicate := false
|
|
|
|
for _, j := range tmp {
|
|
|
|
if i == j {
|
|
|
|
duplicate = true
|
2021-09-05 10:40:55 +12:00
|
|
|
}
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
stat, _ := os.Stat(i)
|
|
|
|
if !duplicate && !stat.IsDir() {
|
|
|
|
tmp = append(tmp, i)
|
|
|
|
}
|
2021-09-05 10:40:55 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
keyfiles = tmp
|
|
|
|
if len(keyfiles) == 1 {
|
|
|
|
keyfilePrompt = s("Using 1 keyfile.")
|
|
|
|
}
|
|
|
|
keyfilePrompt = fmt.Sprintf(s("Using %d keyfiles."), len(keyfiles))
|
|
|
|
return
|
|
|
|
}
|
2021-09-05 10:40:55 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// Clear variables
|
|
|
|
recombine = false
|
|
|
|
onlyFiles = nil
|
|
|
|
onlyFolders = nil
|
|
|
|
allFiles = nil
|
|
|
|
files, folders := 0, 0
|
|
|
|
resetUI()
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
if len(names) == 1 {
|
|
|
|
stat, _ := os.Stat(names[0])
|
|
|
|
if stat.IsDir() {
|
|
|
|
// Update variables
|
|
|
|
mode = "encrypt"
|
|
|
|
folders++
|
|
|
|
inputLabel = s("1 folder selected.")
|
|
|
|
|
|
|
|
// Add the folder
|
|
|
|
onlyFolders = append(onlyFolders, names[0])
|
|
|
|
|
|
|
|
// Set the input and output paths
|
|
|
|
inputFile = filepath.Join(filepath.Dir(names[0]), s("Encrypted")) + ".zip"
|
|
|
|
outputFile = filepath.Join(filepath.Dir(names[0]), s("Encrypted")) + ".zip.pcv"
|
|
|
|
} else {
|
|
|
|
files++
|
|
|
|
name := filepath.Base(names[0])
|
|
|
|
nums := []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}
|
|
|
|
endsNum := false
|
|
|
|
for _, i := range nums {
|
|
|
|
if strings.HasSuffix(names[0], i) {
|
|
|
|
endsNum = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
isSplit := strings.Contains(names[0], ".pcv.") && endsNum
|
|
|
|
|
|
|
|
// Decide if encrypting or decrypting
|
|
|
|
if strings.HasSuffix(names[0], ".pcv") || isSplit {
|
|
|
|
//var err error
|
|
|
|
mode = "decrypt"
|
|
|
|
inputLabel = name + s(" (will decrypt)")
|
|
|
|
metadataPrompt = s("Metadata (read-only):")
|
|
|
|
metadataDisabled = true
|
|
|
|
|
|
|
|
if isSplit {
|
|
|
|
inputLabel = name + s(" (will recombine and decrypt)")
|
|
|
|
ind := strings.Index(names[0], ".pcv")
|
|
|
|
names[0] = names[0][:ind+4]
|
|
|
|
inputFile = names[0]
|
|
|
|
outputFile = names[0][:ind]
|
|
|
|
recombine = true
|
|
|
|
} else {
|
|
|
|
outputFile = names[0][:len(names[0])-4]
|
|
|
|
}
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// Open input file in read-only mode
|
|
|
|
var fin *os.File
|
|
|
|
if isSplit {
|
|
|
|
fin, _ = os.Open(names[0] + ".0")
|
|
|
|
} else {
|
|
|
|
fin, _ = os.Open(names[0])
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// Use regex to test if input is a valid Picocrypt volume
|
|
|
|
tmp := make([]byte, 30)
|
|
|
|
fin.Read(tmp)
|
|
|
|
if string(tmp[:5]) == "v1.13" {
|
|
|
|
resetUI()
|
|
|
|
mainStatus = "Please use Picocrypt v1.13 to decrypt this file."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff}
|
|
|
|
fin.Close()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if valid, _ := regexp.Match(`^v\d\.\d{2}.{10}0?\d+`, tmp); !valid && !isSplit {
|
|
|
|
resetUI()
|
|
|
|
mainStatus = "This doesn't seem to be a Picocrypt volume."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff}
|
|
|
|
fin.Close()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
fin.Seek(0, 0)
|
|
|
|
|
|
|
|
// Read metadata and insert into box
|
|
|
|
var err error
|
|
|
|
tmp = make([]byte, 15)
|
|
|
|
fin.Read(tmp)
|
|
|
|
tmp, _ = rsDecode(rs5, tmp)
|
|
|
|
if string(tmp) == "v1.14" || string(tmp) == "v1.15" || string(tmp) == "v1.16" {
|
|
|
|
resetUI()
|
|
|
|
mainStatus = "Please use Picocrypt v1.16 to decrypt this file."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff}
|
|
|
|
fin.Close()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
tmp = make([]byte, 15)
|
|
|
|
fin.Read(tmp)
|
|
|
|
tmp, err = rsDecode(rs5, tmp)
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
if err == nil {
|
|
|
|
metadataLength, _ := strconv.Atoi(string(tmp))
|
|
|
|
tmp = make([]byte, metadataLength*3)
|
2021-05-30 07:23:22 +12:00
|
|
|
fin.Read(tmp)
|
2021-09-25 12:19:18 +12:00
|
|
|
metadata = ""
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
for i := 0; i < metadataLength*3; i += 3 {
|
|
|
|
t, err := rsDecode(rs1, tmp[i:i+3])
|
|
|
|
if err != nil {
|
|
|
|
metadata = s("Metadata is corrupted.")
|
|
|
|
break
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
metadata += string(t)
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
|
|
|
metadata = s("Metadata is corrupted.")
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
flags := make([]byte, 18)
|
|
|
|
fin.Read(flags)
|
|
|
|
fin.Close()
|
|
|
|
flags, err = rsDecode(rs6, flags)
|
|
|
|
if err != nil {
|
|
|
|
mainStatus = "Input file is corrupt and cannot be decrypted."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff}
|
|
|
|
return
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
if flags[2] == 1 {
|
|
|
|
keyfile = true
|
|
|
|
keyfilePrompt = s("Keyfiles required.")
|
|
|
|
} else {
|
|
|
|
keyfilePrompt = s("Not applicable.")
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if flags[5] == 1 {
|
|
|
|
keyfileOrderMatters = true
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
mode = "encrypt"
|
|
|
|
inputLabel = name + s(" (will encrypt)")
|
|
|
|
inputFile = names[0]
|
|
|
|
outputFile = names[0] + ".pcv"
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// Add the file
|
|
|
|
onlyFiles = append(onlyFiles, names[0])
|
|
|
|
inputFile = names[0]
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
|
|
|
mode = "encrypt"
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// 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)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
if folders == 0 {
|
|
|
|
inputLabel = fmt.Sprintf(s("%d files selected."), files)
|
|
|
|
} else if files == 0 {
|
|
|
|
inputLabel = fmt.Sprintf(s("%d folders selected."), files)
|
|
|
|
} else {
|
|
|
|
if files == 1 && folders > 1 {
|
|
|
|
inputLabel = fmt.Sprintf(s("1 file and %d folders selected."), folders)
|
|
|
|
} else if folders == 1 && files > 1 {
|
|
|
|
inputLabel = fmt.Sprintf(s("%d files and 1 folder selected."), files)
|
|
|
|
} else if folders == 1 && files == 1 {
|
|
|
|
inputLabel = s("1 file and 1 folder selected.")
|
|
|
|
} else {
|
|
|
|
inputLabel = fmt.Sprintf(s("%d files and %d folders selected."), files, folders)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the input and output paths
|
|
|
|
inputFile = filepath.Join(filepath.Dir(names[0]), s("Encrypted")) + ".zip"
|
|
|
|
outputFile = filepath.Join(filepath.Dir(names[0]), s("Encrypted")) + ".zip.pcv"
|
|
|
|
}
|
|
|
|
// Recursively add all files to '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
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
func work() {
|
|
|
|
popupStatus = s("Starting...")
|
|
|
|
mainStatus = "Working..."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0xff, 0xff, 0xff}
|
2021-05-30 07:23:22 +12:00
|
|
|
working = true
|
2021-08-08 06:45:13 +12:00
|
|
|
padded := false
|
2021-09-25 12:19:18 +12:00
|
|
|
|
2021-05-30 07:23:22 +12:00
|
|
|
var salt []byte
|
2021-08-08 06:45:13 +12:00
|
|
|
var hkdfSalt []byte
|
|
|
|
var serpentSalt []byte
|
2021-05-30 07:23:22 +12:00
|
|
|
var nonce []byte
|
|
|
|
var keyHash []byte
|
|
|
|
var _keyHash []byte
|
2021-09-25 12:19:18 +12:00
|
|
|
var keyfileKey []byte
|
|
|
|
var keyfileHash []byte = make([]byte, 32)
|
|
|
|
var _keyfileHash []byte
|
|
|
|
var dataMac []byte
|
|
|
|
|
|
|
|
if mode == "encrypt" {
|
|
|
|
if compress {
|
|
|
|
popupStatus = s("Compressing files...")
|
|
|
|
} else {
|
|
|
|
popupStatus = s("Combining files...")
|
|
|
|
}
|
|
|
|
|
|
|
|
// "Tar" files together (a .zip file with no compression)
|
|
|
|
if len(allFiles) > 1 || len(onlyFolders) > 0 {
|
2021-08-08 06:45:13 +12:00
|
|
|
var rootDir string
|
2021-09-25 12:19:18 +12:00
|
|
|
if len(onlyFolders) > 0 {
|
2021-08-08 06:45:13 +12:00
|
|
|
rootDir = filepath.Dir(onlyFolders[0])
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
2021-08-08 06:45:13 +12:00
|
|
|
rootDir = filepath.Dir(onlyFiles[0])
|
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
file, err := os.Create(inputFile)
|
|
|
|
if err != nil {
|
|
|
|
mainStatus = "Access denied by operating system."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-05-30 07:23:22 +12:00
|
|
|
w := zip.NewWriter(file)
|
2021-09-25 12:19:18 +12:00
|
|
|
for i, path := range allFiles {
|
|
|
|
if !working {
|
2021-08-08 06:45:13 +12:00
|
|
|
w.Close()
|
|
|
|
file.Close()
|
|
|
|
os.Remove(inputFile)
|
2021-09-25 12:19:18 +12:00
|
|
|
mainStatus = "Operation cancelled by user."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0xff, 0xff, 0xff}
|
2021-08-08 06:45:13 +12:00
|
|
|
return
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
progressInfo = fmt.Sprintf("%d/%d", i, len(allFiles))
|
|
|
|
progress = float32(i) / float32(len(allFiles))
|
2021-08-08 06:45:13 +12:00
|
|
|
giu.Update()
|
2021-09-25 12:19:18 +12:00
|
|
|
if path == inputFile {
|
2021-05-30 07:23:22 +12:00
|
|
|
continue
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
|
|
|
|
stat, _ := os.Stat(path)
|
|
|
|
header, _ := zip.FileInfoHeader(stat)
|
|
|
|
header.Name = strings.TrimPrefix(path, rootDir)
|
|
|
|
|
|
|
|
// Windows requires forward slashes in a .zip file
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
header.Name = strings.ReplaceAll(header.Name, "\\", "/")
|
|
|
|
header.Name = strings.TrimPrefix(header.Name, "/")
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
if compress {
|
|
|
|
header.Method = zip.Deflate
|
|
|
|
} else {
|
|
|
|
header.Method = zip.Store
|
|
|
|
}
|
|
|
|
writer, _ := w.CreateHeader(header)
|
|
|
|
file, _ := os.Open(path)
|
|
|
|
io.Copy(writer, file)
|
2021-05-30 07:23:22 +12:00
|
|
|
file.Close()
|
|
|
|
}
|
|
|
|
w.Flush()
|
|
|
|
w.Close()
|
|
|
|
file.Close()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
if recombine {
|
|
|
|
popupStatus = s("Recombining file...")
|
2021-05-30 07:23:22 +12:00
|
|
|
total := 0
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
for {
|
|
|
|
_, err := os.Stat(fmt.Sprintf("%s.%d", inputFile, total))
|
|
|
|
if err != nil {
|
2021-05-30 07:23:22 +12:00
|
|
|
break
|
|
|
|
}
|
|
|
|
total++
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
|
|
|
|
fout, _ := os.Create(inputFile)
|
|
|
|
for i := 0; i < total; i++ {
|
|
|
|
fin, _ := os.Open(fmt.Sprintf("%s.%d", inputFile, i))
|
|
|
|
for {
|
|
|
|
data := make([]byte, 1048576)
|
|
|
|
read, err := fin.Read(data)
|
|
|
|
if err != nil {
|
2021-05-30 07:23:22 +12:00
|
|
|
break
|
|
|
|
}
|
|
|
|
data = data[:read]
|
|
|
|
fout.Write(data)
|
|
|
|
}
|
|
|
|
fin.Close()
|
2021-09-25 12:19:18 +12:00
|
|
|
progressInfo = fmt.Sprintf("%d/%d", i, total)
|
|
|
|
progress = float32(i) / float32(total)
|
2021-08-08 06:45:13 +12:00
|
|
|
giu.Update()
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
fout.Close()
|
|
|
|
progressInfo = ""
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
|
|
|
|
stat, _ := os.Stat(inputFile)
|
2021-05-30 07:23:22 +12:00
|
|
|
total := stat.Size()
|
2021-09-25 12:19:18 +12:00
|
|
|
if mode == "decrypt" {
|
2021-08-08 06:45:13 +12:00
|
|
|
total -= 789
|
|
|
|
}
|
|
|
|
|
|
|
|
// XChaCha20's max message size is 256 GiB
|
2021-09-25 12:19:18 +12:00
|
|
|
if total > 256*1073741824 {
|
|
|
|
mainStatus = "Total size is larger than 256 GiB, XChaCha20's limit."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff}
|
2021-08-08 06:45:13 +12:00
|
|
|
return
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
|
2021-05-30 07:23:22 +12:00
|
|
|
// Open input file in read-only mode
|
2021-09-25 12:19:18 +12:00
|
|
|
fin, err := os.Open(inputFile)
|
|
|
|
if err != nil {
|
|
|
|
mainStatus = "Access denied by operating system."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-05-30 07:23:22 +12:00
|
|
|
var fout *os.File
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// If encrypting, generate values; if decrypting, read values from file
|
|
|
|
if mode == "encrypt" {
|
|
|
|
popupStatus = s("Generating values...")
|
2021-08-08 06:45:13 +12:00
|
|
|
giu.Update()
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
var err error
|
|
|
|
fout, err = os.Create(outputFile)
|
|
|
|
if err != nil {
|
|
|
|
mainStatus = "Access denied by operating system."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate random cryptography values
|
|
|
|
salt = make([]byte, 16)
|
|
|
|
hkdfSalt = make([]byte, 32)
|
|
|
|
serpentSalt = make([]byte, 16)
|
|
|
|
nonce = make([]byte, 24)
|
|
|
|
|
2021-05-30 07:23:22 +12:00
|
|
|
// Write version to file
|
2021-09-25 12:19:18 +12:00
|
|
|
fout.Write(rsEncode(rs5, []byte(version)))
|
2021-05-30 07:23:22 +12:00
|
|
|
|
|
|
|
// Encode the length of the metadata with Reed-Solomon
|
2021-09-25 12:19:18 +12:00
|
|
|
metadataLength := []byte(fmt.Sprintf("%05d", len(metadata)))
|
|
|
|
metadataLength = rsEncode(rs5, metadataLength)
|
|
|
|
|
2021-05-30 07:23:22 +12:00
|
|
|
// Write the length of the metadata to file
|
|
|
|
fout.Write(metadataLength)
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
// Reed-Solomon-encode the metadata and write to file
|
2021-09-25 12:19:18 +12:00
|
|
|
for _, i := range []byte(metadata) {
|
|
|
|
fout.Write(rsEncode(rs1, []byte{i}))
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
flags := make([]byte, 6)
|
|
|
|
if fast {
|
2021-05-30 07:23:22 +12:00
|
|
|
flags[0] = 1
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if paranoid {
|
2021-05-30 07:23:22 +12:00
|
|
|
flags[1] = 1
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if len(keyfiles) > 0 {
|
2021-08-08 06:45:13 +12:00
|
|
|
flags[2] = 1
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if reedsolo {
|
2021-08-08 06:45:13 +12:00
|
|
|
flags[3] = 1
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if total%1048576 >= 1048448 {
|
2021-08-08 06:45:13 +12:00
|
|
|
flags[4] = 1
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if keyfileOrderMatters {
|
2021-09-05 10:40:55 +12:00
|
|
|
flags[5] = 1
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
flags = rsEncode(rs6, flags)
|
2021-05-30 07:23:22 +12:00
|
|
|
fout.Write(flags)
|
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
// Fill salts and nonce with Go's CSPRNG
|
2021-05-30 07:23:22 +12:00
|
|
|
rand.Read(salt)
|
2021-08-08 06:45:13 +12:00
|
|
|
rand.Read(hkdfSalt)
|
|
|
|
rand.Read(serpentSalt)
|
2021-05-30 07:23:22 +12:00
|
|
|
rand.Read(nonce)
|
|
|
|
|
|
|
|
// Encode salt with Reed-Solomon and write to file
|
2021-09-25 12:19:18 +12:00
|
|
|
_salt := rsEncode(rs16, salt)
|
2021-05-30 07:23:22 +12:00
|
|
|
fout.Write(_salt)
|
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
// Encode HKDF salt with Reed-Solomon and write to file
|
2021-09-25 12:19:18 +12:00
|
|
|
_hkdfSalt := rsEncode(rs32, hkdfSalt)
|
2021-08-08 06:45:13 +12:00
|
|
|
fout.Write(_hkdfSalt)
|
|
|
|
|
|
|
|
// Encode Serpent salt with Reed-Solomon and write to file
|
2021-09-25 12:19:18 +12:00
|
|
|
_serpentSalt := rsEncode(rs16, serpentSalt)
|
2021-08-08 06:45:13 +12:00
|
|
|
fout.Write(_serpentSalt)
|
|
|
|
|
2021-05-30 07:23:22 +12:00
|
|
|
// Encode nonce with Reed-Solomon and write to file
|
2021-09-25 12:19:18 +12:00
|
|
|
_nonce := rsEncode(rs24, nonce)
|
2021-08-08 06:45:13 +12:00
|
|
|
fout.Write(_nonce)
|
2021-09-25 12:19:18 +12:00
|
|
|
|
2021-05-30 07:23:22 +12:00
|
|
|
// Write placeholder for hash of key
|
2021-09-25 12:19:18 +12:00
|
|
|
fout.Write(make([]byte, 192))
|
|
|
|
|
2021-05-30 07:23:22 +12:00
|
|
|
// Write placeholder for hash of hash of keyfile
|
2021-09-25 12:19:18 +12:00
|
|
|
fout.Write(make([]byte, 96))
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
// Write placeholder for HMAC-BLAKE2b/HMAC-SHA3 of file
|
2021-09-25 12:19:18 +12:00
|
|
|
fout.Write(make([]byte, 192))
|
|
|
|
} else {
|
2021-08-08 06:45:13 +12:00
|
|
|
var err1 error
|
|
|
|
var err2 error
|
|
|
|
var err3 error
|
|
|
|
var err4 error
|
|
|
|
var err5 error
|
|
|
|
var err6 error
|
|
|
|
var err7 error
|
|
|
|
var err8 error
|
|
|
|
var err9 error
|
|
|
|
var err10 error
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
popupStatus = s("Reading values...")
|
2021-08-08 06:45:13 +12:00
|
|
|
giu.Update()
|
2021-09-25 12:19:18 +12:00
|
|
|
|
|
|
|
version := make([]byte, 15)
|
2021-05-30 07:23:22 +12:00
|
|
|
fin.Read(version)
|
2021-09-25 12:19:18 +12:00
|
|
|
_, err1 = rsDecode(rs5, version)
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
tmp := make([]byte, 15)
|
2021-05-30 07:23:22 +12:00
|
|
|
fin.Read(tmp)
|
2021-09-25 12:19:18 +12:00
|
|
|
tmp, err2 = rsDecode(rs5, tmp)
|
|
|
|
metadataLength, _ := strconv.Atoi(string(tmp))
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
fin.Read(make([]byte, metadataLength*3))
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
flags := make([]byte, 18)
|
2021-05-30 07:23:22 +12:00
|
|
|
fin.Read(flags)
|
2021-09-25 12:19:18 +12:00
|
|
|
flags, err3 = rsDecode(rs6, flags)
|
|
|
|
fast = flags[0] == 1
|
|
|
|
paranoid = flags[1] == 1
|
|
|
|
reedsolo = flags[3] == 1
|
|
|
|
padded = flags[4] == 1
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
salt = make([]byte, 48)
|
2021-05-30 07:23:22 +12:00
|
|
|
fin.Read(salt)
|
2021-09-25 12:19:18 +12:00
|
|
|
salt, err4 = rsDecode(rs16, salt)
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
hkdfSalt = make([]byte, 96)
|
2021-08-08 06:45:13 +12:00
|
|
|
fin.Read(hkdfSalt)
|
2021-09-25 12:19:18 +12:00
|
|
|
hkdfSalt, err5 = rsDecode(rs32, hkdfSalt)
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
serpentSalt = make([]byte, 48)
|
2021-08-08 06:45:13 +12:00
|
|
|
fin.Read(serpentSalt)
|
2021-09-25 12:19:18 +12:00
|
|
|
serpentSalt, err6 = rsDecode(rs16, serpentSalt)
|
|
|
|
|
|
|
|
nonce = make([]byte, 72)
|
2021-05-30 07:23:22 +12:00
|
|
|
fin.Read(nonce)
|
2021-09-25 12:19:18 +12:00
|
|
|
nonce, err7 = rsDecode(rs24, nonce)
|
|
|
|
|
|
|
|
_keyHash = make([]byte, 192)
|
2021-05-30 07:23:22 +12:00
|
|
|
fin.Read(_keyHash)
|
2021-09-25 12:19:18 +12:00
|
|
|
_keyHash, err8 = rsDecode(rs64, _keyHash)
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
_keyfileHash = make([]byte, 96)
|
|
|
|
fin.Read(_keyfileHash)
|
|
|
|
_keyfileHash, err9 = rsDecode(rs32, _keyfileHash)
|
|
|
|
|
|
|
|
dataMac = make([]byte, 192)
|
|
|
|
fin.Read(dataMac)
|
|
|
|
dataMac, err10 = rsDecode(rs64, dataMac)
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
// Is there a better way?
|
2021-09-25 12:19:18 +12:00
|
|
|
if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil ||
|
|
|
|
err6 != nil || err7 != nil || err8 != nil || err9 != nil || err10 != nil {
|
|
|
|
if keep {
|
2021-08-08 06:45:13 +12:00
|
|
|
kept = true
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
|
|
|
mainStatus = "The header is corrupt and the input file cannot be decrypted."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff}
|
2021-08-08 06:45:13 +12:00
|
|
|
fin.Close()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
popupStatus = s("Deriving key...")
|
2021-05-30 07:23:22 +12:00
|
|
|
progress = 0
|
2021-08-08 06:45:13 +12:00
|
|
|
progressInfo = ""
|
|
|
|
giu.Update()
|
2021-09-25 12:19:18 +12:00
|
|
|
|
|
|
|
// Derive encryption/decryption keys and subkeys
|
2021-05-30 07:23:22 +12:00
|
|
|
var key []byte
|
2021-09-25 12:19:18 +12:00
|
|
|
if fast {
|
2021-05-30 07:23:22 +12:00
|
|
|
key = argon2.IDKey(
|
|
|
|
[]byte(password),
|
|
|
|
salt,
|
|
|
|
4,
|
|
|
|
131072,
|
|
|
|
4,
|
|
|
|
32,
|
2021-09-25 12:19:18 +12:00
|
|
|
)
|
|
|
|
} else if paranoid {
|
2021-05-30 07:23:22 +12:00
|
|
|
key = argon2.IDKey(
|
|
|
|
[]byte(password),
|
|
|
|
salt,
|
|
|
|
8,
|
|
|
|
1048576,
|
|
|
|
8,
|
|
|
|
32,
|
2021-09-25 12:19:18 +12:00
|
|
|
)
|
|
|
|
} else {
|
2021-09-05 10:40:55 +12:00
|
|
|
key = argon2.IDKey(
|
|
|
|
[]byte(password),
|
|
|
|
salt,
|
|
|
|
4,
|
|
|
|
1048576,
|
|
|
|
4,
|
|
|
|
32,
|
2021-09-25 12:19:18 +12:00
|
|
|
)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
if !working {
|
|
|
|
mainStatus = "Operation cancelled by user."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0xff, 0xff, 0xff}
|
|
|
|
if mode == "encrypt" && (len(allFiles) > 1 || len(onlyFolders) > 0) {
|
|
|
|
os.Remove(outputFile)
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if recombine {
|
2021-08-08 06:45:13 +12:00
|
|
|
os.Remove(inputFile)
|
|
|
|
}
|
|
|
|
os.Remove(outputFile)
|
2021-05-30 07:23:22 +12:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
if len(keyfiles) > 0 || keyfile {
|
|
|
|
if keyfileOrderMatters {
|
2021-09-05 10:40:55 +12:00
|
|
|
var keysum = sha3.New256()
|
2021-09-25 12:19:18 +12:00
|
|
|
for _, path := range keyfiles {
|
|
|
|
kin, _ := os.Open(path)
|
|
|
|
kstat, _ := os.Stat(path)
|
|
|
|
kbytes := make([]byte, kstat.Size())
|
2021-09-05 10:40:55 +12:00
|
|
|
kin.Read(kbytes)
|
|
|
|
kin.Close()
|
|
|
|
keysum.Write(kbytes)
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
keyfileKey = keysum.Sum(nil)
|
|
|
|
keyfileSha3 := sha3.New256()
|
|
|
|
keyfileSha3.Write(keyfileKey)
|
|
|
|
keyfileHash = keyfileSha3.Sum(nil)
|
|
|
|
} else {
|
2021-09-05 10:40:55 +12:00
|
|
|
var keysum []byte
|
2021-09-25 12:19:18 +12:00
|
|
|
for _, path := range keyfiles {
|
|
|
|
kin, _ := os.Open(path)
|
|
|
|
kstat, _ := os.Stat(path)
|
|
|
|
kbytes := make([]byte, kstat.Size())
|
2021-09-05 10:40:55 +12:00
|
|
|
kin.Read(kbytes)
|
|
|
|
kin.Close()
|
|
|
|
ksha3 := sha3.New256()
|
|
|
|
ksha3.Write(kbytes)
|
2021-09-25 12:19:18 +12:00
|
|
|
keyfileKey := ksha3.Sum(nil)
|
|
|
|
if keysum == nil {
|
|
|
|
keysum = keyfileKey
|
|
|
|
} else {
|
|
|
|
for i, j := range keyfileKey {
|
2021-09-05 10:40:55 +12:00
|
|
|
keysum[i] ^= j
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
keyfileKey = keysum
|
|
|
|
keyfileSha3 := sha3.New256()
|
|
|
|
keyfileSha3.Write(keysum)
|
|
|
|
keyfileHash = keyfileSha3.Sum(nil)
|
2021-09-05 10:40:55 +12:00
|
|
|
}
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
|
2021-05-30 07:23:22 +12:00
|
|
|
sha3_512 := sha3.New512()
|
|
|
|
sha3_512.Write(key)
|
|
|
|
keyHash = sha3_512.Sum(nil)
|
2021-09-25 12:19:18 +12:00
|
|
|
|
|
|
|
// Validate password and/or keyfiles
|
|
|
|
if mode == "decrypt" {
|
2021-05-30 07:23:22 +12:00
|
|
|
keyCorrect := true
|
|
|
|
keyfileCorrect := true
|
|
|
|
var tmp bool
|
2021-09-25 12:19:18 +12:00
|
|
|
|
|
|
|
keyCorrect = !(subtle.ConstantTimeCompare(keyHash, _keyHash) == 0)
|
|
|
|
if keyfile {
|
|
|
|
keyfileCorrect = !(subtle.ConstantTimeCompare(keyfileHash, _keyfileHash) == 0)
|
|
|
|
tmp = !keyCorrect || !keyfileCorrect
|
|
|
|
} else {
|
2021-05-30 07:23:22 +12:00
|
|
|
tmp = !keyCorrect
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
|
|
|
|
if tmp || keep {
|
|
|
|
if keep {
|
2021-05-30 07:23:22 +12:00
|
|
|
kept = true
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
2021-05-30 07:23:22 +12:00
|
|
|
fin.Close()
|
2021-09-25 12:19:18 +12:00
|
|
|
if !keyCorrect {
|
|
|
|
mainStatus = "The provided password is incorrect."
|
|
|
|
} else {
|
|
|
|
if keyfileOrderMatters {
|
|
|
|
mainStatus = "Incorrect keyfiles and/or order."
|
|
|
|
} else {
|
|
|
|
mainStatus = "Incorrect keyfiles."
|
2021-09-05 10:40:55 +12:00
|
|
|
}
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff}
|
2021-05-30 07:23:22 +12:00
|
|
|
key = nil
|
2021-09-25 12:19:18 +12:00
|
|
|
if recombine {
|
2021-05-30 07:23:22 +12:00
|
|
|
os.Remove(inputFile)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
var err error
|
|
|
|
fout, err = os.Create(outputFile)
|
|
|
|
if err != nil {
|
|
|
|
mainStatus = "Access denied by operating system."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff}
|
|
|
|
return
|
|
|
|
}
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
if len(keyfiles) > 0 || keyfile {
|
2021-05-30 07:23:22 +12:00
|
|
|
// XOR key and keyfile
|
|
|
|
tmp := key
|
2021-09-25 12:19:18 +12:00
|
|
|
key = make([]byte, 32)
|
|
|
|
for i := range key {
|
|
|
|
key[i] = tmp[i] ^ keyfileKey[i]
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
|
2021-05-30 07:23:22 +12:00
|
|
|
done := 0
|
|
|
|
counter := 0
|
|
|
|
startTime := time.Now()
|
2021-09-25 12:19:18 +12:00
|
|
|
chacha20, _ := chacha20.NewUnauthenticatedCipher(key, nonce)
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
// Use HKDF-SHA3 to generate a subkey
|
|
|
|
var mac hash.Hash
|
2021-09-25 12:19:18 +12:00
|
|
|
subkey := make([]byte, 32)
|
|
|
|
hkdf := hkdf.New(sha3.New256, key, hkdfSalt, nil)
|
2021-08-08 06:45:13 +12:00
|
|
|
hkdf.Read(subkey)
|
2021-09-25 12:19:18 +12:00
|
|
|
if fast {
|
2021-08-08 06:45:13 +12:00
|
|
|
// Keyed BLAKE2b
|
2021-09-25 12:19:18 +12:00
|
|
|
mac, _ = blake2b.New512(subkey)
|
|
|
|
} else {
|
2021-08-08 06:45:13 +12:00
|
|
|
// HMAC-SHA3
|
2021-09-25 12:19:18 +12:00
|
|
|
mac = hmac.New(sha3.New512, subkey)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
// Generate another subkey and cipher (not used unless paranoid mode is checked)
|
2021-09-25 12:19:18 +12:00
|
|
|
serpentKey := make([]byte, 32)
|
2021-08-08 06:45:13 +12:00
|
|
|
hkdf.Read(serpentKey)
|
2021-09-25 12:19:18 +12:00
|
|
|
_serpent, _ := serpent.NewCipher(serpentKey)
|
|
|
|
serpentCTR := cipher.NewCTR(_serpent, serpentSalt)
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
for {
|
|
|
|
if !working {
|
|
|
|
mainStatus = "Operation cancelled by user."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0xff, 0xff, 0xff}
|
2021-05-30 07:23:22 +12:00
|
|
|
fin.Close()
|
|
|
|
fout.Close()
|
2021-09-25 12:19:18 +12:00
|
|
|
if mode == "encrypt" && (len(allFiles) > 1 || len(onlyFolders) > 0) {
|
|
|
|
os.Remove(outputFile)
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if recombine {
|
2021-08-08 06:45:13 +12:00
|
|
|
os.Remove(inputFile)
|
|
|
|
}
|
2021-05-30 07:23:22 +12:00
|
|
|
os.Remove(outputFile)
|
|
|
|
return
|
|
|
|
}
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-05-30 07:23:22 +12:00
|
|
|
var data []byte
|
2021-09-25 12:19:18 +12:00
|
|
|
if mode == "decrypt" && reedsolo {
|
|
|
|
data = make([]byte, 1114112)
|
|
|
|
} else {
|
|
|
|
data = make([]byte, 1048576)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
size, err := fin.Read(data)
|
|
|
|
if err != nil {
|
2021-05-30 07:23:22 +12:00
|
|
|
break
|
|
|
|
}
|
2021-08-08 06:45:13 +12:00
|
|
|
data = data[:size]
|
2021-09-25 12:19:18 +12:00
|
|
|
_data := make([]byte, len(data))
|
2021-05-30 07:23:22 +12:00
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
// "Actual" encryption is done in the next couple of lines
|
2021-09-25 12:19:18 +12:00
|
|
|
if mode == "encrypt" {
|
|
|
|
if paranoid {
|
|
|
|
serpentCTR.XORKeyStream(_data, data)
|
|
|
|
copy(data, _data)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
chacha20.XORKeyStream(_data, data)
|
2021-08-08 06:45:13 +12:00
|
|
|
mac.Write(_data)
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
if reedsolo {
|
|
|
|
copy(data, _data)
|
2021-08-08 06:45:13 +12:00
|
|
|
_data = nil
|
2021-09-25 12:19:18 +12:00
|
|
|
if len(data) == 1048576 {
|
|
|
|
for i := 0; i < 1048576; i += 128 {
|
|
|
|
tmp := data[i : i+128]
|
|
|
|
tmp = rsEncode(rs128, tmp)
|
|
|
|
_data = append(_data, tmp...)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
|
|
|
chunks := math.Floor(float64(len(data)) / 128)
|
|
|
|
for i := 0; float64(i) < chunks; i++ {
|
|
|
|
tmp := data[i*128 : (i+1)*128]
|
|
|
|
tmp = rsEncode(rs128, tmp)
|
|
|
|
_data = append(_data, tmp...)
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
|
|
|
tmp := data[int(chunks*128):]
|
2021-09-25 12:19:18 +12:00
|
|
|
_data = append(_data, rsEncode(rs128, pad(tmp))...)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
|
|
|
if reedsolo {
|
|
|
|
copy(_data, data)
|
2021-08-08 06:45:13 +12:00
|
|
|
data = nil
|
2021-09-25 12:19:18 +12:00
|
|
|
if len(_data) == 1114112 {
|
|
|
|
for i := 0; i < 1114112; i += 136 {
|
|
|
|
tmp := _data[i : i+136]
|
|
|
|
tmp, err = rsDecode(rs128, tmp)
|
|
|
|
if err != nil {
|
|
|
|
if keep {
|
2021-08-08 06:45:13 +12:00
|
|
|
kept = true
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
|
|
|
mainStatus = "The input file is too corrupted to decrypt."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff}
|
2021-08-08 06:45:13 +12:00
|
|
|
fin.Close()
|
|
|
|
fout.Close()
|
|
|
|
broken()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if i == 1113976 && done+1114112 >= int(total) && padded {
|
2021-08-08 06:45:13 +12:00
|
|
|
tmp = unpad(tmp)
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
data = append(data, tmp...)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
|
|
|
chunks := len(_data)/136 - 1
|
|
|
|
for i := 0; i < chunks; i++ {
|
|
|
|
tmp := _data[i*136 : (i+1)*136]
|
|
|
|
tmp, err = rsDecode(rs128, tmp)
|
|
|
|
if err != nil {
|
|
|
|
if keep {
|
2021-08-08 06:45:13 +12:00
|
|
|
kept = true
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
|
|
|
mainStatus = "The input file is too corrupted to decrypt."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff}
|
2021-08-08 06:45:13 +12:00
|
|
|
fin.Close()
|
|
|
|
fout.Close()
|
|
|
|
broken()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
data = append(data, tmp...)
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
|
|
|
tmp := _data[int(chunks)*136:]
|
2021-09-25 12:19:18 +12:00
|
|
|
tmp, err = rsDecode(rs128, tmp)
|
|
|
|
if err != nil {
|
|
|
|
if keep {
|
2021-08-08 06:45:13 +12:00
|
|
|
kept = true
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
|
|
|
mainStatus = "The input file is too corrupted to decrypt."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff}
|
2021-08-08 06:45:13 +12:00
|
|
|
fin.Close()
|
|
|
|
fout.Close()
|
|
|
|
broken()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tmp = unpad(tmp)
|
2021-09-25 12:19:18 +12:00
|
|
|
data = append(data, tmp...)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
_data = make([]byte, len(data))
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
mac.Write(data)
|
2021-09-25 12:19:18 +12:00
|
|
|
chacha20.XORKeyStream(_data, data)
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
if paranoid {
|
|
|
|
copy(data, _data)
|
|
|
|
serpentCTR.XORKeyStream(_data, data)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
}
|
2021-08-08 06:45:13 +12:00
|
|
|
fout.Write(_data)
|
2021-09-25 12:19:18 +12:00
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
// Update stats
|
2021-09-25 12:19:18 +12:00
|
|
|
if mode == "decrypt" && reedsolo {
|
2021-08-08 06:45:13 +12:00
|
|
|
done += 1114112
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
2021-08-08 06:45:13 +12:00
|
|
|
done += 1048576
|
|
|
|
}
|
2021-05-30 07:23:22 +12:00
|
|
|
counter++
|
2021-09-25 12:19:18 +12:00
|
|
|
progress = float32(done) / float32(total)
|
|
|
|
elapsed := float64(time.Since(startTime)) / math.Pow(10, 9)
|
|
|
|
speed := float64(done) / elapsed / math.Pow(10, 6)
|
|
|
|
eta := int(math.Floor(float64(total-int64(done)) / (speed * math.Pow(10, 6))))
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
if progress > 1 {
|
2021-08-08 06:45:13 +12:00
|
|
|
progress = 1
|
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
progressInfo = fmt.Sprintf("%.2f%%", progress*100)
|
|
|
|
popupStatus = fmt.Sprintf(s("Working at %.2f MB/s (ETA: %s)"), speed, humanize(eta))
|
2021-08-08 06:45:13 +12:00
|
|
|
giu.Update()
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
if mode == "encrypt" {
|
2021-08-08 06:45:13 +12:00
|
|
|
// Seek back to header and write important data
|
2021-09-25 12:19:18 +12:00
|
|
|
fout.Seek(int64(312+len(metadata)*3), 0)
|
|
|
|
fout.Write(rsEncode(rs64, keyHash))
|
|
|
|
fout.Write(rsEncode(rs32, keyfileHash))
|
|
|
|
fout.Write(rsEncode(rs64, mac.Sum(nil)))
|
|
|
|
} else {
|
2021-08-08 06:45:13 +12:00
|
|
|
// Validate the authenticity of decrypted data
|
2021-09-25 12:19:18 +12:00
|
|
|
if subtle.ConstantTimeCompare(mac.Sum(nil), dataMac) == 0 {
|
|
|
|
if keep {
|
2021-08-08 06:45:13 +12:00
|
|
|
kept = true
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
2021-08-08 06:45:13 +12:00
|
|
|
fin.Close()
|
|
|
|
fout.Close()
|
|
|
|
broken()
|
|
|
|
return
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-05-30 07:23:22 +12:00
|
|
|
fin.Close()
|
|
|
|
fout.Close()
|
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
// Split files into chunks
|
2021-09-25 12:19:18 +12:00
|
|
|
if split {
|
2021-08-08 06:45:13 +12:00
|
|
|
var splitted []string
|
2021-09-25 12:19:18 +12:00
|
|
|
popupStatus = s("Splitting file...")
|
|
|
|
stat, _ := os.Stat(outputFile)
|
2021-05-30 07:23:22 +12:00
|
|
|
size := stat.Size()
|
|
|
|
finished := 0
|
2021-09-25 12:19:18 +12:00
|
|
|
chunkSize, _ := strconv.Atoi(splitSize)
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
// User can choose KiB, MiB, and GiB
|
2021-09-25 12:19:18 +12:00
|
|
|
if splitSelected == 0 {
|
2021-05-30 07:23:22 +12:00
|
|
|
chunkSize *= 1024
|
2021-09-25 12:19:18 +12:00
|
|
|
} else if splitSelected == 1 {
|
2021-05-30 07:23:22 +12:00
|
|
|
chunkSize *= 1048576
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
2021-05-30 07:23:22 +12:00
|
|
|
chunkSize *= 1073741824
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
chunks := int(math.Ceil(float64(size) / float64(chunkSize)))
|
|
|
|
fin, _ := os.Open(outputFile)
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
for i := 0; i < chunks; i++ {
|
|
|
|
fout, _ := os.Create(fmt.Sprintf("%s.%d", outputFile, i))
|
2021-05-30 07:23:22 +12:00
|
|
|
done := 0
|
2021-09-25 12:19:18 +12:00
|
|
|
for {
|
|
|
|
data := make([]byte, 1048576)
|
|
|
|
read, err := fin.Read(data)
|
|
|
|
if err != nil {
|
2021-05-30 07:23:22 +12:00
|
|
|
break
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if !working {
|
2021-05-30 07:23:22 +12:00
|
|
|
fin.Close()
|
|
|
|
fout.Close()
|
2021-09-25 12:19:18 +12:00
|
|
|
mainStatus = "Operation cancelled by user."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0xff, 0xff, 0xff}
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
// If user cancels, remove the unfinished files
|
2021-09-25 12:19:18 +12:00
|
|
|
for _, j := range splitted {
|
2021-05-30 07:23:22 +12:00
|
|
|
os.Remove(j)
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
os.Remove(fmt.Sprintf("%s.%d", outputFile, i))
|
2021-05-30 07:23:22 +12:00
|
|
|
os.Remove(outputFile)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
data = data[:read]
|
|
|
|
fout.Write(data)
|
|
|
|
done += read
|
2021-09-25 12:19:18 +12:00
|
|
|
if done >= chunkSize {
|
2021-05-30 07:23:22 +12:00
|
|
|
break
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
}
|
2021-05-30 07:23:22 +12:00
|
|
|
fout.Close()
|
|
|
|
finished++
|
2021-09-25 12:19:18 +12:00
|
|
|
splitted = append(splitted, fmt.Sprintf("%s.%d", outputFile, i))
|
|
|
|
progress = float32(finished) / float32(chunks)
|
|
|
|
progressInfo = fmt.Sprintf("%d/%d", finished, chunks)
|
2021-08-08 06:45:13 +12:00
|
|
|
giu.Update()
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
fin.Close()
|
2021-09-25 12:19:18 +12:00
|
|
|
if shredTemp {
|
2021-05-30 07:23:22 +12:00
|
|
|
progressInfo = ""
|
2021-09-25 12:19:18 +12:00
|
|
|
popupStatus = s("Shredding temporary files...")
|
|
|
|
shred([]string{inputFile + ".pcv"}, false)
|
|
|
|
} else {
|
|
|
|
os.Remove(inputFile + ".pcv")
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
// Remove the temporary file used to combine a splitted Picocrypt volume
|
2021-09-25 12:19:18 +12:00
|
|
|
if recombine {
|
2021-05-30 07:23:22 +12:00
|
|
|
os.Remove(inputFile)
|
|
|
|
}
|
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
// Delete the temporary zip file if user wishes
|
2021-09-25 12:19:18 +12:00
|
|
|
if len(allFiles) > 1 || len(onlyFolders) > 0 {
|
|
|
|
if shredTemp {
|
2021-05-30 07:23:22 +12:00
|
|
|
progressInfo = ""
|
2021-09-25 12:19:18 +12:00
|
|
|
popupStatus = s("Shredding temporary files...")
|
2021-08-08 06:45:13 +12:00
|
|
|
giu.Update()
|
2021-09-25 12:19:18 +12:00
|
|
|
shred([]string{inputFile}, false)
|
|
|
|
} else {
|
|
|
|
os.Remove(inputFile)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
if deleteWhenDone {
|
|
|
|
progressInfo = ""
|
|
|
|
popupStatus = s("Deleted files...")
|
|
|
|
giu.Update()
|
|
|
|
if mode == "decrypt" {
|
|
|
|
if recombine {
|
|
|
|
total := 0
|
|
|
|
for {
|
|
|
|
_, err := os.Stat(fmt.Sprintf("%s.%d", inputFile, total))
|
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
os.Remove(fmt.Sprintf("%s.%d", inputFile, total))
|
|
|
|
total++
|
2021-09-05 10:40:55 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
|
|
|
os.Remove(inputFile)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for _, i := range onlyFiles {
|
|
|
|
os.Remove(i)
|
|
|
|
}
|
|
|
|
for _, i := range onlyFolders {
|
|
|
|
os.RemoveAll(i)
|
2021-09-05 10:40:55 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-30 07:23:22 +12:00
|
|
|
resetUI()
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
// If user chose to keep a corrupted/modified file, let them know
|
2021-09-25 12:19:18 +12:00
|
|
|
if kept {
|
|
|
|
mainStatus = "The input file is corrupted and/or modified. Please be careful."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0xff, 0x00, 0xff}
|
|
|
|
} else {
|
|
|
|
mainStatus = "Completed."
|
|
|
|
mainStatusColor = color.RGBA{0x00, 0xff, 0x00, 0xff}
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
// Clear UI state
|
2021-05-30 07:23:22 +12:00
|
|
|
working = false
|
|
|
|
kept = false
|
|
|
|
key = nil
|
2021-09-25 12:19:18 +12:00
|
|
|
popupStatus = s("Ready.")
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
// This function is run if an issue occurs during decryption
|
2021-09-25 12:19:18 +12:00
|
|
|
func broken() {
|
|
|
|
mainStatus = "The input file is either corrupted or intentionally modified."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff}
|
|
|
|
if recombine {
|
2021-08-08 06:45:13 +12:00
|
|
|
os.Remove(inputFile)
|
|
|
|
}
|
|
|
|
os.Remove(outputFile)
|
|
|
|
giu.Update()
|
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// Generate file checksums
|
|
|
|
func generateChecksums(file string) {
|
|
|
|
fin, _ := os.Open(file)
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
// Clear UI state
|
2021-09-25 12:19:18 +12:00
|
|
|
csMd5 = ""
|
|
|
|
csSha1 = ""
|
|
|
|
csSha256 = ""
|
|
|
|
csSha3 = ""
|
|
|
|
csBlake2b = ""
|
|
|
|
csBlake2s = ""
|
|
|
|
md5Color = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
sha1Color = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
sha256Color = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
sha3Color = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
blake2bColor = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
blake2sColor = color.RGBA{0x00, 0x00, 0x00, 0x00}
|
|
|
|
csValidate = ""
|
|
|
|
|
|
|
|
if md5Selected {
|
|
|
|
csMd5 = s("Calculating...")
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if sha1Selected {
|
|
|
|
csSha1 = s("Calculating...")
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if sha256Selected {
|
|
|
|
csSha256 = s("Calculating...")
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if sha3Selected {
|
|
|
|
csSha3 = s("Calculating...")
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if blake2bSelected {
|
|
|
|
csBlake2b = s("Calculating...")
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if blake2sSelected {
|
|
|
|
csBlake2s = s("Calculating...")
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the checksum objects
|
2021-09-25 12:19:18 +12:00
|
|
|
crcMd5 := md5.New()
|
|
|
|
crcSha1 := sha1.New()
|
|
|
|
crcSha256 := sha256.New()
|
|
|
|
crcSha3 := sha3.New256()
|
|
|
|
crcBlake2b, _ := blake2b.New256(nil)
|
|
|
|
crcBlake2s, _ := blake2s.New256(nil)
|
|
|
|
|
|
|
|
stat, _ := os.Stat(file)
|
2021-08-08 06:45:13 +12:00
|
|
|
total := stat.Size()
|
|
|
|
var done int64 = 0
|
2021-09-25 12:19:18 +12:00
|
|
|
for {
|
2021-08-08 06:45:13 +12:00
|
|
|
var data []byte
|
2021-09-25 12:19:18 +12:00
|
|
|
_data := make([]byte, 1048576)
|
|
|
|
size, err := fin.Read(_data)
|
|
|
|
if err != nil {
|
2021-08-08 06:45:13 +12:00
|
|
|
break
|
|
|
|
}
|
|
|
|
data = _data[:size]
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
if md5Selected {
|
|
|
|
crcMd5.Write(data)
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if sha1Selected {
|
|
|
|
crcSha1.Write(data)
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if sha256Selected {
|
|
|
|
crcSha256.Write(data)
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if sha3Selected {
|
|
|
|
crcSha3.Write(data)
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if blake2bSelected {
|
|
|
|
crcBlake2b.Write(data)
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if blake2sSelected {
|
|
|
|
crcBlake2s.Write(data)
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
done += int64(size)
|
2021-09-25 12:19:18 +12:00
|
|
|
csProgress = float32(done) / float32(total)
|
2021-08-08 06:45:13 +12:00
|
|
|
giu.Update()
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
csProgress = 0
|
|
|
|
if md5Selected {
|
|
|
|
csMd5 = hex.EncodeToString(crcMd5.Sum(nil))
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if sha1Selected {
|
|
|
|
csSha1 = hex.EncodeToString(crcSha1.Sum(nil))
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if sha256Selected {
|
|
|
|
csSha256 = hex.EncodeToString(crcSha256.Sum(nil))
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if sha3Selected {
|
|
|
|
csSha3 = hex.EncodeToString(crcSha3.Sum(nil))
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if blake2bSelected {
|
|
|
|
csBlake2b = hex.EncodeToString(crcBlake2b.Sum(nil))
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if blake2sSelected {
|
|
|
|
csBlake2s = hex.EncodeToString(crcBlake2s.Sum(nil))
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
fin.Close()
|
|
|
|
giu.Update()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recursively shred all file(s) and folder(s) passed in as 'names'
|
2021-09-25 12:19:18 +12:00
|
|
|
func shred(names []string, separate bool) {
|
2021-08-10 11:51:25 +12:00
|
|
|
stopShredding = false
|
2021-05-30 07:23:22 +12:00
|
|
|
shredTotal = 0
|
|
|
|
shredDone = 0
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
// 'separate' is true if this function is being called from the encryption/decryption tab
|
2021-09-25 12:19:18 +12:00
|
|
|
if separate {
|
2021-09-05 10:40:55 +12:00
|
|
|
shredOverlay = s("Shredding...")
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
// Walk through directories to get the total number of files for statistics
|
2021-09-25 12:19:18 +12:00
|
|
|
for _, name := range names {
|
|
|
|
filepath.Walk(name, func(path string, _ os.FileInfo, err error) error {
|
|
|
|
if err != nil {
|
2021-05-30 07:23:22 +12:00
|
|
|
return nil
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
stat, _ := os.Stat(path)
|
|
|
|
if !stat.IsDir() {
|
2021-05-30 07:23:22 +12:00
|
|
|
shredTotal++
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
for _, name := range names {
|
2021-05-30 07:23:22 +12:00
|
|
|
shredding = name
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
// Linux and macOS need a command with similar syntax and usage, so they're combined
|
2021-09-25 12:19:18 +12:00
|
|
|
if runtime.GOOS == "linux" || runtime.GOOS == "darwin" {
|
|
|
|
stat, _ := os.Stat(name)
|
|
|
|
if stat.IsDir() {
|
2021-05-30 07:23:22 +12:00
|
|
|
var coming []string
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
// Walk the folder recursively
|
2021-09-25 12:19:18 +12:00
|
|
|
filepath.Walk(name, func(path string, _ os.FileInfo, err error) error {
|
|
|
|
if err != nil {
|
2021-05-30 07:23:22 +12:00
|
|
|
return nil
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if stopShredding {
|
2021-08-10 11:51:25 +12:00
|
|
|
return nil
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
stat, _ := os.Stat(path)
|
|
|
|
if !stat.IsDir() {
|
|
|
|
if len(coming) == 128 {
|
2021-08-08 06:45:13 +12:00
|
|
|
// Use a WaitGroup to parallelize shredding
|
2021-05-30 07:23:22 +12:00
|
|
|
var wg sync.WaitGroup
|
2021-09-25 12:19:18 +12:00
|
|
|
for i, j := range coming {
|
2021-05-30 07:23:22 +12:00
|
|
|
wg.Add(1)
|
2021-09-25 12:19:18 +12:00
|
|
|
go func(wg *sync.WaitGroup, id int, j string) {
|
2021-05-30 07:23:22 +12:00
|
|
|
defer wg.Done()
|
2021-08-10 11:51:25 +12:00
|
|
|
shredding = j
|
2021-09-25 12:19:18 +12:00
|
|
|
var cmd *exec.Cmd
|
|
|
|
if runtime.GOOS == "linux" {
|
|
|
|
cmd = exec.Command("shred", "-ufvz", "-n", strconv.Itoa(int(shredPasses)), j)
|
|
|
|
} else {
|
|
|
|
cmd = exec.Command("rm", "-rfP", j)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
2021-08-08 06:45:13 +12:00
|
|
|
cmd.Run()
|
2021-05-30 07:23:22 +12:00
|
|
|
shredDone++
|
|
|
|
shredUpdate(separate)
|
2021-08-08 06:45:13 +12:00
|
|
|
giu.Update()
|
2021-09-25 12:19:18 +12:00
|
|
|
}(&wg, i, j)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
coming = nil
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
|
|
|
coming = append(coming, path)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
2021-09-25 12:19:18 +12:00
|
|
|
for _, i := range coming {
|
|
|
|
if stopShredding {
|
2021-08-10 11:51:25 +12:00
|
|
|
break
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
go func(i string) {
|
2021-08-10 11:51:25 +12:00
|
|
|
shredding = i
|
2021-09-25 12:19:18 +12:00
|
|
|
var cmd *exec.Cmd
|
|
|
|
if runtime.GOOS == "linux" {
|
|
|
|
cmd = exec.Command("shred", "-ufvz", "-n", strconv.Itoa(int(shredPasses)), i)
|
|
|
|
} else {
|
|
|
|
cmd = exec.Command("rm", "-rfP", i)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
2021-08-08 06:45:13 +12:00
|
|
|
cmd.Run()
|
2021-05-30 07:23:22 +12:00
|
|
|
shredDone++
|
|
|
|
shredUpdate(separate)
|
2021-08-08 06:45:13 +12:00
|
|
|
giu.Update()
|
2021-09-25 12:19:18 +12:00
|
|
|
}(i)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if !stopShredding {
|
2021-08-10 11:51:25 +12:00
|
|
|
os.RemoveAll(name)
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
} else { // The path is a file, not a directory, so just shred it
|
2021-08-10 11:51:25 +12:00
|
|
|
shredding = name
|
2021-09-25 12:19:18 +12:00
|
|
|
var cmd *exec.Cmd
|
|
|
|
if runtime.GOOS == "linux" {
|
|
|
|
cmd = exec.Command("shred", "-ufvz", "-n", strconv.Itoa(int(shredPasses)), name)
|
|
|
|
} else {
|
|
|
|
cmd = exec.Command("rm", "-rfP", name)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
2021-05-30 07:23:22 +12:00
|
|
|
cmd.Run()
|
|
|
|
shredDone++
|
|
|
|
shredUpdate(separate)
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
} else if runtime.GOOS == "windows" {
|
|
|
|
stat, _ := os.Stat(name)
|
|
|
|
if stat.IsDir() {
|
2021-08-08 06:45:13 +12:00
|
|
|
// Walk the folder recursively
|
2021-09-25 12:19:18 +12:00
|
|
|
filepath.Walk(name, func(path string, _ os.FileInfo, err error) error {
|
|
|
|
if err != nil {
|
2021-05-30 07:23:22 +12:00
|
|
|
return nil
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
stat, _ := os.Stat(path)
|
|
|
|
if stat.IsDir() {
|
|
|
|
if stopShredding {
|
2021-08-10 11:51:25 +12:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-05-30 07:23:22 +12:00
|
|
|
t := 0
|
2021-09-25 12:19:18 +12:00
|
|
|
files, _ := ioutil.ReadDir(path)
|
|
|
|
for _, f := range files {
|
|
|
|
if !f.IsDir() {
|
2021-05-30 07:23:22 +12:00
|
|
|
t++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
shredDone += float32(t)
|
|
|
|
shredUpdate(separate)
|
2021-09-25 12:19:18 +12:00
|
|
|
shredding = strings.ReplaceAll(path, "\\", "/") + "/*"
|
|
|
|
cmd := exec.Command(sdelete64path, "*", "-p", strconv.Itoa(int(shredPasses)))
|
2021-05-30 07:23:22 +12:00
|
|
|
cmd.Dir = path
|
2021-09-25 12:19:18 +12:00
|
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
2021-05-30 07:23:22 +12:00
|
|
|
cmd.Run()
|
2021-08-10 11:51:25 +12:00
|
|
|
giu.Update()
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
2021-08-10 11:51:25 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
if !stopShredding {
|
2021-08-10 11:51:25 +12:00
|
|
|
// sdelete64 doesn't delete the empty folder, so I'll do it manually
|
|
|
|
os.RemoveAll(name)
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
} else {
|
2021-08-10 11:51:25 +12:00
|
|
|
shredding = name
|
2021-09-25 12:19:18 +12:00
|
|
|
cmd := exec.Command(sdelete64path, name, "-p", strconv.Itoa(int(shredPasses)))
|
|
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
2021-08-08 08:40:01 +12:00
|
|
|
cmd.Run()
|
2021-05-30 07:23:22 +12:00
|
|
|
shredDone++
|
|
|
|
shredUpdate(separate)
|
|
|
|
}
|
|
|
|
}
|
2021-08-08 06:45:13 +12:00
|
|
|
giu.Update()
|
2021-09-25 12:19:18 +12:00
|
|
|
if stopShredding {
|
2021-08-10 11:51:25 +12:00
|
|
|
return
|
|
|
|
}
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
// Clear UI state
|
2021-09-05 10:40:55 +12:00
|
|
|
shredding = s("Completed.")
|
2021-05-30 07:23:22 +12:00
|
|
|
shredProgress = 0
|
|
|
|
shredOverlay = ""
|
|
|
|
}
|
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
// Update shredding statistics
|
2021-09-25 12:19:18 +12:00
|
|
|
func shredUpdate(separate bool) {
|
|
|
|
if separate {
|
|
|
|
shredOverlay = fmt.Sprintf("%d/%d", int(shredDone), int(shredTotal))
|
|
|
|
shredProgress = shredDone / shredTotal
|
|
|
|
} else {
|
|
|
|
popupStatus = fmt.Sprintf("%d/%d", int(shredDone), int(shredTotal))
|
|
|
|
progress = shredDone / shredTotal
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-08-08 06:45:13 +12:00
|
|
|
giu.Update()
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
// Reset the UI to a clean state with nothing selected or checked
|
2021-09-25 12:19:18 +12:00
|
|
|
func resetUI() {
|
2021-08-08 06:45:13 +12:00
|
|
|
mode = ""
|
2021-09-25 12:19:18 +12:00
|
|
|
onlyFiles = nil
|
|
|
|
onlyFolders = nil
|
|
|
|
allFiles = nil
|
|
|
|
inputLabel = s("Drop files and folders into this window.")
|
2021-05-30 07:23:22 +12:00
|
|
|
password = ""
|
|
|
|
cPassword = ""
|
2021-09-05 10:40:55 +12:00
|
|
|
keyfiles = nil
|
2021-05-30 07:23:22 +12:00
|
|
|
keyfile = false
|
2021-09-05 10:40:55 +12:00
|
|
|
keyfileOrderMatters = false
|
2021-09-25 12:19:18 +12:00
|
|
|
keyfilePrompt = s("None selected.")
|
2021-05-30 07:23:22 +12:00
|
|
|
metadata = ""
|
2021-09-25 12:19:18 +12:00
|
|
|
metadataPrompt = "Metadata:"
|
|
|
|
metadataDisabled = false
|
2021-08-08 06:45:13 +12:00
|
|
|
shredTemp = false
|
2021-05-30 07:23:22 +12:00
|
|
|
keep = false
|
|
|
|
reedsolo = false
|
|
|
|
split = false
|
|
|
|
splitSize = ""
|
2021-09-25 12:19:18 +12:00
|
|
|
splitSelected = 1
|
2021-05-30 07:23:22 +12:00
|
|
|
fast = false
|
2021-09-25 12:19:18 +12:00
|
|
|
deleteWhenDone = false
|
2021-08-08 06:45:13 +12:00
|
|
|
paranoid = false
|
2021-09-25 12:19:18 +12:00
|
|
|
compress = false
|
|
|
|
encryptFilename = false
|
|
|
|
inputFile = ""
|
|
|
|
outputFile = ""
|
2021-05-30 07:23:22 +12:00
|
|
|
progress = 0
|
|
|
|
progressInfo = ""
|
2021-09-25 12:19:18 +12:00
|
|
|
mainStatus = "Ready."
|
|
|
|
mainStatusColor = color.RGBA{0xff, 0xff, 0xff, 0xff}
|
2021-08-08 06:45:13 +12:00
|
|
|
giu.Update()
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
// Reed-Solomon encoder
|
2021-09-25 12:19:18 +12:00
|
|
|
func rsEncode(rs *infectious.FEC, data []byte) []byte {
|
2021-08-08 06:45:13 +12:00
|
|
|
var res []byte
|
2021-09-25 12:19:18 +12:00
|
|
|
rs.Encode(data, func(s infectious.Share) {
|
|
|
|
res = append(res, s.DeepCopy().Data[0])
|
2021-08-08 06:45:13 +12:00
|
|
|
})
|
|
|
|
return res
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
// Reed-Solomon decoder
|
2021-09-25 12:19:18 +12:00
|
|
|
func rsDecode(rs *infectious.FEC, data []byte) ([]byte, error) {
|
|
|
|
tmp := make([]infectious.Share, rs.Total())
|
|
|
|
for i := 0; i < rs.Total(); i++ {
|
2021-08-08 06:45:13 +12:00
|
|
|
tmp[i] = infectious.Share{
|
2021-09-25 12:19:18 +12:00
|
|
|
Number: i,
|
|
|
|
Data: []byte{data[i]},
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
res, err := rs.Decode(nil, tmp)
|
|
|
|
if err != nil {
|
|
|
|
if rs.Total() == 136 {
|
|
|
|
return data[:128], err
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
return data[:rs.Total()/3], err
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
return res, nil
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
// PKCS7 Pad (for use with Reed-Solomon, not for cryptographic purposes)
|
2021-09-25 12:19:18 +12:00
|
|
|
func pad(data []byte) []byte {
|
|
|
|
padLen := 128 - len(data)%128
|
|
|
|
padding := bytes.Repeat([]byte{byte(padLen)}, padLen)
|
|
|
|
return append(data, padding...)
|
2021-08-08 06:45:13 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
// PKCS7 Unpad
|
2021-09-25 12:19:18 +12:00
|
|
|
func unpad(data []byte) []byte {
|
2021-08-08 06:45:13 +12:00
|
|
|
length := len(data)
|
|
|
|
padLen := int(data[length-1])
|
|
|
|
return data[:length-padLen]
|
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
func genPassword() string {
|
2021-08-11 15:35:35 +12:00
|
|
|
chars := ""
|
2021-09-25 12:19:18 +12:00
|
|
|
if genpassUpper {
|
2021-08-11 15:35:35 +12:00
|
|
|
chars += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if genpassLower {
|
2021-08-11 15:35:35 +12:00
|
|
|
chars += "abcdefghijklmnopqrstuvwxyz"
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if genpassNums {
|
2021-08-11 15:35:35 +12:00
|
|
|
chars += "1234567890"
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if genpassSymbols {
|
2021-08-11 15:35:35 +12:00
|
|
|
chars += "-=!@#$^&()_+?"
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if chars == "" {
|
2021-08-11 15:35:35 +12:00
|
|
|
return chars
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
tmp := make([]byte, genpassLength)
|
|
|
|
for i := 0; i < int(genpassLength); i++ {
|
|
|
|
j, _ := rand.Int(rand.Reader, new(big.Int).SetUint64(uint64(len(chars))))
|
2021-08-10 11:51:25 +12:00
|
|
|
tmp[i] = chars[j.Int64()]
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
if genpassCopy {
|
2021-08-11 15:35:35 +12:00
|
|
|
clipboard.WriteAll(string(tmp))
|
|
|
|
}
|
2021-08-10 11:51:25 +12:00
|
|
|
return string(tmp)
|
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// Convert seconds to HH:MM:SS
|
|
|
|
func humanize(seconds int) string {
|
|
|
|
hours := int(math.Floor(float64(seconds) / 3600))
|
|
|
|
seconds %= 3600
|
|
|
|
minutes := int(math.Floor(float64(seconds) / 60))
|
|
|
|
seconds %= 60
|
|
|
|
hours = int(math.Max(float64(hours), 0))
|
|
|
|
minutes = int(math.Max(float64(minutes), 0))
|
|
|
|
seconds = int(math.Max(float64(seconds), 0))
|
|
|
|
return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
|
|
|
|
}
|
|
|
|
|
|
|
|
func s(term string) string {
|
|
|
|
for _, i := range locales {
|
|
|
|
if i.iso == selectedLocale {
|
|
|
|
for _, j := range locales {
|
|
|
|
if j.iso == "en" {
|
|
|
|
for k, l := range j.data {
|
|
|
|
if l == term {
|
2021-09-05 10:40:55 +12:00
|
|
|
return i.data[k]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-09-25 12:19:18 +12:00
|
|
|
|
2021-09-05 10:40:55 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return term
|
|
|
|
}
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
func main() {
|
2021-09-05 10:40:55 +12:00
|
|
|
// Parse locales
|
|
|
|
var obj map[string]json.RawMessage
|
2021-09-25 12:19:18 +12:00
|
|
|
json.Unmarshal(localeBytes, &obj)
|
|
|
|
for i := range obj {
|
2021-09-05 10:40:55 +12:00
|
|
|
var tmp []string
|
2021-09-25 12:19:18 +12:00
|
|
|
json.Unmarshal(obj[i], &tmp)
|
|
|
|
locales = append(locales, locale{
|
|
|
|
iso: i,
|
|
|
|
data: tmp,
|
2021-09-05 10:40:55 +12:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check system locale
|
2021-09-25 12:19:18 +12:00
|
|
|
for _, i := range locales {
|
|
|
|
tmp, err := jibber_jabber.DetectIETF()
|
|
|
|
if err == nil {
|
|
|
|
if strings.HasPrefix(tmp, i.iso) {
|
2021-09-05 10:40:55 +12:00
|
|
|
selectedLocale = i.iso
|
2021-09-25 12:19:18 +12:00
|
|
|
for j, k := range allLocales {
|
|
|
|
if k == i.iso {
|
2021-09-05 10:40:55 +12:00
|
|
|
languageSelected = int32(j)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-08 06:45:13 +12:00
|
|
|
// Create a temporary file to store sdelete64.exe
|
2021-09-25 12:19:18 +12:00
|
|
|
sdelete64, _ := os.CreateTemp("", "sdelete64.*.exe")
|
2021-08-08 06:45:13 +12:00
|
|
|
sdelete64path = sdelete64.Name()
|
|
|
|
sdelete64.Write(sdelete64bytes)
|
|
|
|
sdelete64.Close()
|
2021-09-25 12:19:18 +12:00
|
|
|
cmd := exec.Command(sdelete64path, "/accepteula")
|
|
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
2021-08-08 08:40:01 +12:00
|
|
|
cmd.Run()
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// Set a universal font
|
|
|
|
giu.SetDefaultFontFromBytes(font, 18)
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// Create the master window
|
|
|
|
window := giu.NewMasterWindow("Picocrypt", 442, 532, giu.MasterWindowFlagsNotResizable)
|
2021-08-08 06:45:13 +12:00
|
|
|
dialog.Init()
|
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// Set window icon
|
|
|
|
reader := bytes.NewReader(icon)
|
|
|
|
decoded, _ := png.Decode(reader)
|
|
|
|
window.SetIcon([]image.Image{decoded})
|
2021-08-08 06:45:13 +12:00
|
|
|
|
2021-09-25 12:19:18 +12:00
|
|
|
// Set callbacks
|
2021-05-30 07:23:22 +12:00
|
|
|
window.SetDropCallback(onDrop)
|
2021-09-25 12:19:18 +12:00
|
|
|
window.SetCloseCallback(func() bool {
|
|
|
|
return !working
|
2021-08-08 06:45:13 +12:00
|
|
|
})
|
2021-09-25 12:19:18 +12:00
|
|
|
|
|
|
|
// Set universal DPI
|
2021-08-08 06:45:13 +12:00
|
|
|
dpi = giu.Context.GetPlatform().GetContentScale()
|
2021-09-25 12:19:18 +12:00
|
|
|
|
|
|
|
// Start a goroutine to check if a newer version is available
|
|
|
|
go func() {
|
|
|
|
v, err := http.Get("https://raw.githubusercontent.com/HACKERALERT/Picocrypt/main/internals/version.txt")
|
|
|
|
if err == nil {
|
|
|
|
body, err := io.ReadAll(v.Body)
|
|
|
|
v.Body.Close()
|
|
|
|
if err == nil {
|
|
|
|
if string(body[:5]) != version {
|
|
|
|
mainStatus = "A newer version is available."
|
|
|
|
mainStatusColor = color.RGBA{0, 255, 0, 255}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Start the UI
|
|
|
|
window.Run(draw)
|
2021-08-08 06:45:13 +12:00
|
|
|
|
|
|
|
// Window closed, clean up
|
|
|
|
os.Remove(sdelete64path)
|
2021-05-30 07:23:22 +12:00
|
|
|
}
|