diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..8f0987f --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,32 @@ +name: "CodeQL" +on: + push: + paths: + - "src/Picocrypt.go" + - "src/go.mod" + - "src/go.sum" + pull_request: + branches: [ main ] +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + language: ['go'] + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/Changelog.md b/Changelog.md index c1ac440..a218d13 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,17 +1,23 @@ # Features Under Consideration -# v1.22 (A future release) +# v1.23 (A future release) + +# v1.22 (Released 12/22/2021) + # v1.21 (Released 11/19/2021) diff --git a/Internals.md b/Internals.md index b1e75b0..00807b9 100644 --- a/Internals.md +++ b/Internals.md @@ -4,10 +4,9 @@ If you're wondering about how Picocrypt handles cryptography, you've come to the # Core Cryptography Picocrypt uses the following cryptographic primitives: - XChaCha20 (cascaded with Serpent in CTR mode for paranoid mode) -- HMAC-SHA3 for normal and paranoid mode, keyed-BLAKE2b for fast mode (256-bit key, 512-bit digest) -- HKDF-SHA3-256 for deriving a subkey used with the MAC above, as well as a key for Serpent +- Keyed-BLAKE2b for normal mode, HMAC-SHA3 for paranoid mode (256-bit key, 512-bit digest) +- HKDF-SHA3 for deriving a subkey used with the MAC above, as well as a key for Serpent - Argon2id: - - Fast mode: 4 passes, 128 MiB memory, 4 threads - Normal mode: 4 passes, 1 GiB memory, 4 threads - Paranoid mode: 8 passes, 1 GiB memory, 8 threads @@ -19,3 +18,6 @@ Picocrypt allows the use of keyfiles as an additional (or only) form of authenti If "Require correct order" is not checked, Picocrypt will take the SHA3 hash of each file individually, and XORs the hashes together. Finally, the result is XORed to the master key. Because the XOR operation is both commutative and associative, the order in which the keyfiles hashes are XORed to each other doesn't matter -- the end result is the same. If "Require correct order" is checked, Picocrypt will combine (concatenate) the files together in the order they were dropped into the window, and take the SHA3 hash of the combined keyfiles. If the order is not correct, the keyfiles, when appended to each other, will result in a different file, and therefore a different hash. Thus, the correct order of keyfiles is required to successfully decrypt the volume. + +# Header Format +Work in progress... diff --git a/README.md b/README.md index df7b9f5..d7052a2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

English | Français | Español | Deutsch | Português | Türkçe | 中文 | русский | Magyar

Picocrypt

-Picocrypt is a very small (hence Pico), very simple, yet very secure encryption tool that you can use to protect your files, generate checksums, and much more. It's designed to be the go-to tool for encryption, with a focus on security, simplicity, and reliability. Picocrypt uses the secure XChaCha20 cipher and the SHA3 hash function to provide a high level of security, even from three-letter agencies like the NSA. It's designed for maximal security, making absolutely no compromises security-wise, and is built with Go's standard x/crypto modules. Your privacy and security is under attack. Take it back with confidence by protecting your files with Picocrypt. +Picocrypt is a very small (hence Pico), very simple, yet very secure encryption tool that you can use to protect your files, generate checksums, and much more. It's designed to be the go-to tool for encryption, with a focus on security, simplicity, and reliability. Picocrypt uses the secure XChaCha20 cipher and the Argon2 key derivation function to provide a high level of security, even from three-letter agencies like the NSA. It's designed for maximal security, making absolutely no compromises security-wise, and is built with Go's standard x/crypto modules. Your privacy and security is under attack. Take it back with confidence by protecting your files with Picocrypt.

Picocrypt

@@ -12,10 +12,10 @@ Please donate to Picocrypt on Ope Important: There's an outdated and useless piece of abandonware called PicoCrypt on the Internet, which was last updated in 2005. PicoCrypt is not related in any way to Picocrypt (this project). Make sure you only download Picocrypt from this repository to ensure that you get the authentic and backdoor-free Picocrypt. ## Windows -Picocrypt for Windows is as simple as it gets. To download the latest, standalone, and portable executable for Windows, click here. If Windows Defender or your antivirus flags Picocrypt as a virus, please do your part and submit it as a false positive for the betterment of everyone. +Picocrypt for Windows is as simple as it gets. To download the latest, standalone, and portable executable for Windows, click here. If Windows Defender or your antivirus flags Picocrypt as a virus, please do your part and submit it as a false positive for the betterment of everyone. ## macOS -Picocrypt for macOS is very simple as well. Download Picocrypt here, extract the zip file, and run Picocrypt which is inside. If you can't open Picocrypt because it's not from a verified developer, right click on Picocrypt and hit "Open". If you still get the warning, right click on Picocrypt and hit "Open" again and you should be able to start Picocrypt. +Picocrypt for macOS is very simple as well. Download Picocrypt here, extract the zip file, and run Picocrypt which is inside. If you can't open Picocrypt because it's not from a verified developer, right click on Picocrypt and hit "Open". If you still get the warning, right click on Picocrypt and hit "Open" again and you should be able to start Picocrypt. ## Linux A Snap is available for Linux. Assuming you're on a Debian-based system, a simple `apt install snapd` and `snap install picocrypt` will be enough. For other distros such as Fedora, detailed instructions are available at https://snapcraft.io/picocrypt. Due to the complexity of dependencies and static linking, I don't distribute standalone .deb or .rpm binaries because they would be unreliable and not worth the hassle. Snapcraft manages all dependencies and runtimes automatically and is the recommended way to run Picocrypt on any major Linux distribution. Additionally, Snapcraft provides better security and containerization than Flatpaks and AppImages, which is important for an encryption tool like Picocrypt. If you would prefer not to deal with Canonical, remember that building from source is always an option. @@ -27,7 +27,7 @@ Why should you use Picocrypt instead of BitLocker, NordLocker, VeraCrypt, AxCryp
  • Picocrypt is tiny. While NordLocker is over 100MB and VeraCrypt is over 30MB, Picocrypt sits at just 3MB, about the size of a high-resolution photo. And that's not all - Picocrypt is portable (doesn't need to be installed) and doesn't require administrator/root privileges.
  • Picocrypt is easier and more productive to use than VeraCrypt. To encrypt files with VeraCrypt, you'd have to spend at least five minutes setting up a volume. With Picocrypt's simple UI, all you have to do is drag and drop your files, enter a password, and hit Start. All the complex procedures are handled by Picocrypt internally. Who said secure encryption can't be simple?
  • Picocrypt is designed for security. 7-Zip is an archive utility and not an encryption tool, so its focus is not on security. Picocrypt, however, is built with security as the number one priority. Every part of Picocrypt exists for a reason and anything that could impact the security of Picocrypt is removed. Picocrypt is built with cryptography you can trust.
  • -
  • Picocrypt authenticates data in addition to protecting it, preventing hackers from maliciously modifying sensitive data. This is useful when you are sending encrypted files over an insecure channel and want to be sure that it arrives untouched. Picocrypt uses HMAC-SHA3 for authenticity, which is a highly secure hash function in a well-known construction.
  • +
  • Picocrypt authenticates data in addition to protecting it, preventing hackers from maliciously modifying sensitive data. This is useful when you are sending encrypted files over an insecure channel and want to be sure that it arrives untouched.
  • Picocrypt actively protects encrypted header data from corruption by adding extra Reed-Solomon parity bytes, so if part of a volume's header (which contains important cryptographic components) corrupts (e.g., hard drive bit rot), Picocrypt can still recover the header and decrypt your data with a high success rate. Picocrypt can also encode the entire volume with Reed-Solomon to prevent any corruption to your important files.
  • @@ -41,8 +41,7 @@ While being simple, Picocrypt also strives to be powerful in the hands of knowle
  • Password generator: Picocrypt provides a secure password generator that you can use to create cryptographically secure passwords. You can customize the password length, as well as the types of characters to include.
  • File metadata: Use this to store notes, information, and text along with the file (it won't be encrypted). For example, you can put a description of the file you're encrypting before sending it to someone. When the person you sent it to drops the file into Picocrypt, your description will be shown to that person.
  • Keyfiles: Picocrypt supports the use of keyfiles as an additional form of authentication. Not only can you use multiple keyfiles, but you can also require the correct order of keyfiles to be present, for a successful decryption to occur. A particularly good use case of multiple keyfiles is creating a shared volume, where each person holds a keyfile, and all of them (and their keyfiles) must be present in order to decrypt the shared volume.
  • -
  • Fast mode: Using this mode will greatly speed up encryption/decryption. In this mode, BLAKE2b will be used to authenticate data instead of SHA3, and Argon2 parameters will be lowered. Doing this provides higher speeds, but at a lower security margin. If all you need to do is encrypt some low-sensitivity files, this option can be a useful and performant choice.
  • -
  • Paranoid mode: Using this mode will encrypt your data with both XChaCha20 and Serpent in a cascade fashion. This is recommended for protecting top-secret files and provides the highest level of practical security attainable. In order for a hacker to crack your encrypted data, both the XChaCha20 cipher and the Serpent cipher must be broken, assuming you've chosen a good password.
  • +
  • Paranoid mode: Using this mode will encrypt your data with both XChaCha20 and Serpent in a cascade fashion, and use HMAC-SHA3 to authenticate data instead of BLAKE2b. This is recommended for protecting top-secret files and provides the highest level of practical security attainable. In order for a hacker to crack your encrypted data, both the XChaCha20 cipher and the Serpent cipher must be broken, assuming you've chosen a good password.
  • Prevent corruption using Reed-Solomon: This feature is very useful if you are planning to archive important data on a cloud provider or external medium for a long time. If checked, Picocrypt will use the Reed-Solomon error correction code to add 8 extra bytes for every 128 bytes to prevent file corruption. This means that up to ~3% of your file can corrupt and Picocrypt will still be able to correct the errors and decrypt your files with no corruption. Of course, if your file corrupts very badly (e.g., you dropped your hard drive), Picocrypt won't be able to fully recover your files, but it will try its best to recover what it can. Note that this option will slow down encryption and decryption considerably.
  • Keep decrypted output even if it's corrupted or modified: Picocrypt automatically checks for integrity upon decryption. If the file has been modified or is corrupted, Picocrypt will automatically delete the output for the user's safety. If you want to keep the corrupted or modified data after decryption, check this option. Also, if this option is checked and the Reed-Solomon feature was used on the encrypted file, Picocrypt will attempt to recover as much of the file as possible during decryption.
  • Split files into chunks: Don't feel like dealing with gargantuan files? No worries! With Picocrypt, you can choose to split your output file into custom-sized chunks, so large files can become more manageable and easier to upload to cloud providers. Simply choose a unit (KiB, MiB, or GiB) and enter your desired number for that unit. To decrypt the chunks, simply drag one of them into Picocrypt, and the chunks will be automatically recombined during decryption.
  • @@ -53,8 +52,6 @@ In addition to these comprehensive options for encryption and decryption, Picocr # Security For more information on how Picocrypt handles cryptography, see Internals for the technical details. If you're worried about the safety of me or this project, let me assure you that this repository won't be hijacked or backdoored. I have 2FA (TOTP) enabled on all accounts with a tie to Picocrypt (GitHub, Google, Reddit, Ubuntu One/Snapcraft, Discord, etc.), in addition to full-disk encryption on all of my portable devices. For further hardening, Picocrypt uses my isolated forks of dependencies and I fetch upstream only when I have taken a look at the changes and believe that there aren't any security issues. This means that if a dependency gets hacked or deleted by the author, Picocrypt will be using my fork of it and remain completely unaffected. You can feel confident about using Picocrypt. -In the unlikely scenario that a security vulnerability is discovered, please draft a security advisory in the Security tab of this repository and I will fix it as soon as possible. - # Community Here are some places where you can stay up to date with Picocrypt and get involved: Finally, thanks to these people for helping me out when needed: @@ -106,4 +104,5 @@ Finally, thanks to these people for helping me out when needed:
  • u/greenreddits for constant feedback and support
  • u/Tall_Escape for helping me test Picocrypt
  • u/NSABackdoors for doing plenty of testing
  • +
  • @samuel-lucas6 for feedback, suggestions, and support
  • diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..90f70fa --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,5 @@ +# Security Policy + +## Reporting a Vulnerability + +If you notice a security vulnerability, please contact me privately here. I don't have any bounties available, but I will put your name on the homepage as a thanks. Please do not create an Issue or post the vulnerability publicly, as it could be exploited by a hacker. Thank you. diff --git a/images/screenshot.png b/images/screenshot.png index 2e56f2c..66e72a6 100644 Binary files a/images/screenshot.png and b/images/screenshot.png differ diff --git a/internals/version.txt b/internals/version.txt index 64153b7..7999cbb 100644 --- a/internals/version.txt +++ b/internals/version.txt @@ -1 +1 @@ -v1.21 +v1.22 diff --git a/src/Picocrypt.go b/src/Picocrypt.go index 80d9089..2ab7563 100644 --- a/src/Picocrypt.go +++ b/src/Picocrypt.go @@ -2,7 +2,7 @@ package main /* -Picocrypt v1.21 +Picocrypt v1.22 Copyright (c) Evan Su (https://evansu.cc) Released under a GNU GPL v3 License https://github.com/HACKERALERT/Picocrypt @@ -45,7 +45,7 @@ import ( "crypto/sha256" "crypto/subtle" - "github.com/HACKERALERT/serpent" + "github.com/HACKERALERT/serpent" //v0.0.0-20210716182301-293b29869c66 "golang.org/x/crypto/argon2" "golang.org/x/crypto/blake2b" "golang.org/x/crypto/blake2s" @@ -54,16 +54,16 @@ import ( "golang.org/x/crypto/sha3" // UI - "github.com/HACKERALERT/giu" + "github.com/HACKERALERT/giu" //v0.5.7-0.20211216020632-65de69857557 // Reed-Solomon - "github.com/HACKERALERT/infectious" + "github.com/HACKERALERT/infectious" //v0.0.0-20211215232025-9d20874ad4b1 // Helpers - "github.com/HACKERALERT/clipboard" - "github.com/HACKERALERT/dialog" - "github.com/HACKERALERT/jibber_jabber" - "github.com/HACKERALERT/zxcvbn-go" + "github.com/HACKERALERT/clipboard" //v0.1.5-0.20211215214929-7345ba96aeca + "github.com/HACKERALERT/dialog" //v0.0.0-20211215220206-17f428aa513e + "github.com/HACKERALERT/jibber_jabber" //v0.0.0-20211215234401-c23e432f628b + "github.com/HACKERALERT/zxcvbn-go" //v0.0.0-20210927200100-f131a4666ad5 ) //go:embed icon.png @@ -92,7 +92,7 @@ var languages = []string{ var languageSelected int32 // Generic variables -var version = "v1.21" +var version = "v1.22" var window *giu.MasterWindow var windowOptimized bool var dpi float32 @@ -139,7 +139,6 @@ var metadataPrompt = "Metadata:" var metadataDisabled bool // Advanced options -var fast bool var paranoid bool var reedsolo bool var deleteWhenDone bool @@ -174,7 +173,6 @@ var showConfirmation bool // Reed-Solomon encoders 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) @@ -182,6 +180,7 @@ var rs64, _ = infectious.NewFEC(64, 192) var rs128, _ = infectious.NewFEC(128, 136) // File checksum generator variables +var csProgress float32 var csMd5 string var csSha1 string var csSha256 string @@ -195,7 +194,6 @@ 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 @@ -542,21 +540,19 @@ func draw() { giu.Label(s("Advanced:")), giu.Custom(func() { if mode != "decrypt" { - giu.Row( - giu.Checkbox(s("Use fast mode"), &fast), - giu.Dummy(-221, 0), - giu.Checkbox(s("Encode with Reed-Solomon"), &reedsolo), - ).Build() giu.Row( giu.Checkbox(s("Use paranoid mode"), ¶noid), giu.Dummy(-221, 0), - giu.Checkbox(s("Delete files when complete"), &deleteWhenDone), + giu.Checkbox(s("Encode with Reed-Solomon"), &reedsolo), ).Build() giu.Row( giu.Style().SetDisabled(!(len(allFiles) > 1 || len(onlyFolders) > 0)).To( giu.Checkbox(s("Compress files"), &compress), ), giu.Dummy(-221, 0), + giu.Checkbox(s("Delete files when complete"), &deleteWhenDone), + ).Build() + giu.Row( giu.Checkbox(s("Split every"), &split), giu.InputText(&splitSize).Size(55/dpi).Flags(giu.InputTextFlagsCharsHexadecimal).OnChange(func() { split = splitSize != "" @@ -865,19 +861,18 @@ func draw() { 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(s("Donors:")), giu.Label(" - jp26"), + giu.Label(" - Tybbs"), 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"), + giu.Label("umitseyhan75, digitalblossom, zeeaall, kurpau, francirc, yn, Etim-Orb").Wrapped(true), + giu.Label(s("Others:")), + giu.Label("Fuderal, u/greenreddits, u/Tall_Escape, u/NSABackdoors, @samuel-lucas6").Wrapped(true), ), ).Build() }), @@ -1025,6 +1020,14 @@ func onDrop(names []string) { fin.Close() return } + if string(tmp) == "v1.17" || string(tmp) == "v1.18" || string(tmp) == "v1.19" || + string(tmp) == "v1.20" || string(tmp) == "v1.21" { + resetUI() + mainStatus = "Please use Picocrypt v1.21 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) @@ -1047,23 +1050,23 @@ func onDrop(names []string) { metadata = s("Metadata is corrupted.") } - flags := make([]byte, 18) + flags := make([]byte, 15) fin.Read(flags) fin.Close() - flags, err = rsDecode(rs6, flags) + flags, err = rsDecode(rs5, flags) if err != nil { mainStatus = "Input file is corrupt and cannot be decrypted." mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff} return } - if flags[2] == 1 { + if flags[1] == 1 { keyfile = true keyfilePrompt = s("Keyfiles required.") } else { keyfilePrompt = s("Not applicable.") } - if flags[5] == 1 { + if flags[2] == 1 { keyfileOrderMatters = true } } else { @@ -1245,7 +1248,7 @@ func work() { stat, _ := os.Stat(inputFile) total := stat.Size() if mode == "decrypt" { - total -= 789 + total -= 786 } // XChaCha20's max message size is 256 GiB @@ -1299,14 +1302,14 @@ func work() { fout.Write(rsEncode(rs1, []byte{i})) } - flags := make([]byte, 6) - if fast { + flags := make([]byte, 5) + if paranoid { flags[0] = 1 } - if paranoid { + if len(keyfiles) > 0 { flags[1] = 1 } - if len(keyfiles) > 0 { + if keyfileOrderMatters { flags[2] = 1 } if reedsolo { @@ -1315,10 +1318,7 @@ func work() { if total%1048576 >= 1048448 { flags[4] = 1 } - if keyfileOrderMatters { - flags[5] = 1 - } - flags = rsEncode(rs6, flags) + flags = rsEncode(rs5, flags) fout.Write(flags) // Fill salts and nonce with Go's CSPRNG @@ -1377,11 +1377,10 @@ func work() { fin.Read(make([]byte, metadataLength*3)) - flags := make([]byte, 18) + flags := make([]byte, 15) fin.Read(flags) - flags, err3 = rsDecode(rs6, flags) - fast = flags[0] == 1 - paranoid = flags[1] == 1 + flags, err3 = rsDecode(rs5, flags) + paranoid = flags[0] == 1 reedsolo = flags[3] == 1 padded = flags[4] == 1 @@ -1434,16 +1433,7 @@ func work() { // Derive encryption/decryption keys and subkeys var key []byte - if fast { - key = argon2.IDKey( - []byte(password), - salt, - 4, - 131072, - 4, - 32, - ) - } else if paranoid { + if paranoid { key = argon2.IDKey( []byte(password), salt, @@ -1527,9 +1517,9 @@ func work() { keyfileCorrect := true var tmp bool - keyCorrect = !(subtle.ConstantTimeCompare(keyHash, _keyHash) == 0) + keyCorrect = subtle.ConstantTimeCompare(keyHash, _keyHash) != 0 if keyfile { - keyfileCorrect = !(subtle.ConstantTimeCompare(keyfileHash, _keyfileHash) == 0) + keyfileCorrect = subtle.ConstantTimeCompare(keyfileHash, _keyfileHash) != 0 tmp = !keyCorrect || !keyfileCorrect } else { tmp = !keyCorrect @@ -1586,12 +1576,12 @@ func work() { subkey := make([]byte, 32) hkdf := hkdf.New(sha3.New256, key, hkdfSalt, nil) hkdf.Read(subkey) - if fast { - // Keyed BLAKE2b - mac, _ = blake2b.New512(subkey) - } else { + if paranoid { // HMAC-SHA3 mac = hmac.New(sha3.New512, subkey) + } else { + // Keyed BLAKE2b + mac, _ = blake2b.New512(subkey) } // Generate another subkey and cipher (not used unless paranoid mode is checked) @@ -1757,7 +1747,7 @@ func work() { if mode == "encrypt" { // Seek back to header and write important data - fout.Seek(int64(312+len(metadata)*3), 0) + fout.Seek(int64(309+len(metadata)*3), 0) fout.Write(rsEncode(rs64, keyHash)) fout.Write(rsEncode(rs32, keyfileHash)) fout.Write(rsEncode(rs64, mac.Sum(nil))) @@ -2032,7 +2022,6 @@ func resetUI() { split = false splitSize = "" splitSelected = 1 - fast = false deleteWhenDone = false paranoid = false compress = false diff --git a/src/README.md b/src/README.md index 375f2b6..173878c 100644 --- a/src/README.md +++ b/src/README.md @@ -4,7 +4,7 @@ If you would like to run Picocrypt from source, or an executable isn't available # 1. Prerequisites Linux: ```bash -apt install -y gcc make libx11-dev libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev libgl1-mesa-dev libxxf86vm-dev libgtk-3-dev xdg-utils libglu1-mesa xclip +apt install -y gcc libx11-dev libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev libgl1-mesa-dev libxxf86vm-dev libgtk-3-dev libglu1-mesa xclip ``` macOS: ```bash diff --git a/src/go.mod b/src/go.mod index 385cc3a..cef1fb1 100644 --- a/src/go.mod +++ b/src/go.mod @@ -3,19 +3,18 @@ module Picocrypt go 1.17 require ( - github.com/HACKERALERT/clipboard v0.1.5-0.20210716140604-61d96bf4fc94 // indirect - github.com/HACKERALERT/dialog v0.0.0-20210716143851-223edea1d840 // indirect - github.com/HACKERALERT/giu v0.5.7-0.20211027224501-6357f8997cac // indirect - github.com/HACKERALERT/gl v0.0.0-20211027194356-838f5789a406 // indirect - github.com/HACKERALERT/glfw/v3.3/glfw v0.0.0-20211027203414-1b9369ce24d2 // indirect - github.com/HACKERALERT/go-findfont v0.0.0-20211027212021-2e5a409c1318 // indirect - github.com/HACKERALERT/imgui-go v1.12.1-0.20211027214916-5870dfea82b0 // indirect - github.com/HACKERALERT/infectious v0.0.0-20211027225427-984efcfa77a9 // indirect - github.com/HACKERALERT/jibber_jabber v0.0.0-20210819210536-54a4d27b5376 // indirect + github.com/HACKERALERT/clipboard v0.1.5-0.20211215214929-7345ba96aeca // indirect + github.com/HACKERALERT/dialog v0.0.0-20211215220206-17f428aa513e // indirect + github.com/HACKERALERT/giu v0.5.7-0.20211216020632-65de69857557 // indirect + github.com/HACKERALERT/gl v0.0.0-20211216002416-e8bf2db61361 // indirect + github.com/HACKERALERT/glfw/v3.3/glfw v0.0.0-20211216001154-d0da149b3bef // indirect + github.com/HACKERALERT/imgui-go v1.12.1-0.20211216003024-285d689cbdfc // indirect + github.com/HACKERALERT/infectious v0.0.0-20211215232025-9d20874ad4b1 // indirect + github.com/HACKERALERT/jibber_jabber v0.0.0-20211222174950-71570b6ee48b // indirect github.com/HACKERALERT/mainthread v0.0.0-20211027212305-2ec9e701cc14 // indirect github.com/HACKERALERT/serpent v0.0.0-20210716182301-293b29869c66 // indirect - github.com/HACKERALERT/w32 v0.0.0-20210716142531-faa7189c4abf // indirect + github.com/HACKERALERT/w32 v0.0.0-20211215215707-4b84c2675d8d // indirect github.com/HACKERALERT/zxcvbn-go v0.0.0-20210927200100-f131a4666ad5 // indirect - golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect - golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 // indirect + golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e // indirect + golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect ) diff --git a/src/go.sum b/src/go.sum index 1901465..12d7c07 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,36 +1,31 @@ -github.com/HACKERALERT/clipboard v0.1.5-0.20210716140604-61d96bf4fc94 h1:FNwFtZlPggOVFxx1IvUtBfCGZBR7OMhsmXygJAVHkzg= -github.com/HACKERALERT/clipboard v0.1.5-0.20210716140604-61d96bf4fc94/go.mod h1:kkjR9AGvIlIUJdjd/CBL1VfQvyPDE5kL31rAzY/r0s4= -github.com/HACKERALERT/dialog v0.0.0-20210716143851-223edea1d840 h1:7He527vRG3S8tVQHu+ZGl4cJ46JhjDk4/Iu1PevcE+Q= -github.com/HACKERALERT/dialog v0.0.0-20210716143851-223edea1d840/go.mod h1:oeUTfMKn6HhRJ+Lguhk21YAvURR/yk4OkeVcrHpUKbM= -github.com/HACKERALERT/giu v0.5.7-0.20211027223400-815bf822aada h1:IwNXnaf7iL3PaDcgJXCJsDyxZHGkpI7H5QQqvbJUBz4= -github.com/HACKERALERT/giu v0.5.7-0.20211027223400-815bf822aada/go.mod h1:zm4+x/08BnL7sAwOXqyYbaT0qT4x1FbPPeDQqKRKLhY= -github.com/HACKERALERT/giu v0.5.7-0.20211027224501-6357f8997cac h1:8z+sBiBisd96Cf1nI+bikh4bxtmt91Zom52dlz8x8XA= -github.com/HACKERALERT/giu v0.5.7-0.20211027224501-6357f8997cac/go.mod h1:/YCfEOyzu2UlGfOjh41QDQYe1UYCWfj09pD2nXkennk= -github.com/HACKERALERT/gl v0.0.0-20211027194356-838f5789a406 h1:87NS0Fx0EkDPxyDmKad2951/aMJRP2mIiJ3G6jzJI+8= -github.com/HACKERALERT/gl v0.0.0-20211027194356-838f5789a406/go.mod h1:ZUosVzfEKNGLMLk6aj9yo0FSAhWWsbTMjuzeIUXniB0= -github.com/HACKERALERT/glfw/v3.3/glfw v0.0.0-20211027203414-1b9369ce24d2 h1:iuBfCfVs/+LcGafOUDXNqFr7d+5Xh5f6Yovl9gK5xG4= -github.com/HACKERALERT/glfw/v3.3/glfw v0.0.0-20211027203414-1b9369ce24d2/go.mod h1:aP+FSN9tk1W3UsQisFWxRLQ4WOF7T3niq68UYw0B150= -github.com/HACKERALERT/go-findfont v0.0.0-20211027212021-2e5a409c1318 h1:2MNs2kJfnojX01dYJFPtD//0Z03nF9mkMrsKLFvUjqc= -github.com/HACKERALERT/go-findfont v0.0.0-20211027212021-2e5a409c1318/go.mod h1:L2Y9eyXVqwA6v+8o5lVm7vM1eokEvpZN5R1CYSp9vW4= -github.com/HACKERALERT/imgui-go v1.12.1-0.20211027214916-5870dfea82b0 h1:DndFdVvbiyzO4sajMFQ25zwuk5pWPg7DTO5EdfdjaRw= -github.com/HACKERALERT/imgui-go v1.12.1-0.20211027214916-5870dfea82b0/go.mod h1:778OLTsdd7wS4LLtskqROtc93vnzueQ2Y/JMYzHQHiY= -github.com/HACKERALERT/infectious v0.0.0-20211027211519-a810ec917770 h1:oWNxph0qM9CzPww04luj8HJufveToD+VjbESPVhvWw4= -github.com/HACKERALERT/infectious v0.0.0-20211027211519-a810ec917770/go.mod h1:gTfGH7xorTbSHZQZJ/HQBOp18E97v7zDquA2HcI9fgc= -github.com/HACKERALERT/infectious v0.0.0-20211027225427-984efcfa77a9 h1:SwsesmigJhD95MYv5RTkPNvICy3bdOdKX/xbeN8Z+64= -github.com/HACKERALERT/infectious v0.0.0-20211027225427-984efcfa77a9/go.mod h1:m3JCdt8lI79U7J+QavACBRIJBxTaih+2feAHRFq82Wg= -github.com/HACKERALERT/jibber_jabber v0.0.0-20210819210536-54a4d27b5376 h1:8FNjZ8C+WOKpOlQe9vaTq3vBGC7zuFWCVvzkEE6DOHs= -github.com/HACKERALERT/jibber_jabber v0.0.0-20210819210536-54a4d27b5376/go.mod h1:LhYTEuww35ooZaTD3BIjp9CyZqwv++gAnanWXKdiWJ8= +github.com/HACKERALERT/clipboard v0.1.5-0.20211215214929-7345ba96aeca h1:yZj12M2feFkat7l0r7s7QnKjJ4Q6UZOwVHroR4kQ4Nk= +github.com/HACKERALERT/clipboard v0.1.5-0.20211215214929-7345ba96aeca/go.mod h1:kkjR9AGvIlIUJdjd/CBL1VfQvyPDE5kL31rAzY/r0s4= +github.com/HACKERALERT/dialog v0.0.0-20211215220206-17f428aa513e h1:3tBZg/OOLNsQrSf5gZc8y3fXiHVxl+kg/iTs0maa0BA= +github.com/HACKERALERT/dialog v0.0.0-20211215220206-17f428aa513e/go.mod h1:GxPIEf2nKp6Gx+sdpjwTdFIGmW5kj6Jta7rRO50TgpU= +github.com/HACKERALERT/giu v0.5.7-0.20211216020632-65de69857557 h1:2vQfSuzTUDTQKv68HQbic5uJWa1qOBvzHJ3Rngo/70Q= +github.com/HACKERALERT/giu v0.5.7-0.20211216020632-65de69857557/go.mod h1:rq+zzA8hlxAiO0ryOTMuPPm4d2Y4bUx5JRmIfp0fdqQ= +github.com/HACKERALERT/gl v0.0.0-20211216002416-e8bf2db61361 h1:NMPzcOu/LpfEUf0wRZlayjlU0345ujYOWZbVKsfL6g4= +github.com/HACKERALERT/gl v0.0.0-20211216002416-e8bf2db61361/go.mod h1:ZUosVzfEKNGLMLk6aj9yo0FSAhWWsbTMjuzeIUXniB0= +github.com/HACKERALERT/glfw/v3.3/glfw v0.0.0-20211216001154-d0da149b3bef h1:MWA48bM0uKSblAiB51YtMDWEBhJtX+s3HcjlUN7o8cE= +github.com/HACKERALERT/glfw/v3.3/glfw v0.0.0-20211216001154-d0da149b3bef/go.mod h1:aP+FSN9tk1W3UsQisFWxRLQ4WOF7T3niq68UYw0B150= +github.com/HACKERALERT/imgui-go v1.12.1-0.20211216003024-285d689cbdfc h1:40aJqXAQbh6KjMN1QEzmPrwcNYCJsJH4uGS+nDa+k4Q= +github.com/HACKERALERT/imgui-go v1.12.1-0.20211216003024-285d689cbdfc/go.mod h1:Yo2L7QsU7d+Y6+Uput8+3AHYji0EFojRg4Sokun4Xb0= +github.com/HACKERALERT/infectious v0.0.0-20211215232025-9d20874ad4b1 h1:+Qp4t5OHvokaLdZO7Y1i7pX+i85kNtrHRzCg7S+Lj/s= +github.com/HACKERALERT/infectious v0.0.0-20211215232025-9d20874ad4b1/go.mod h1:Nr/zKoJunuzBaGVWwWRNz9F2D3iEXuBNWjRu3tgunYI= +github.com/HACKERALERT/jibber_jabber v0.0.0-20211215234401-c23e432f628b h1:/oowRlgjIPB9nTJGoRssumobxLz0q0GL5Sump5Wf3Vo= +github.com/HACKERALERT/jibber_jabber v0.0.0-20211215234401-c23e432f628b/go.mod h1:LhYTEuww35ooZaTD3BIjp9CyZqwv++gAnanWXKdiWJ8= +github.com/HACKERALERT/jibber_jabber v0.0.0-20211222174950-71570b6ee48b h1:Rl9dd3fhAtzbIE4AJeU2x4gwI0dHA1kXsn9v0AZJDOE= +github.com/HACKERALERT/jibber_jabber v0.0.0-20211222174950-71570b6ee48b/go.mod h1:LhYTEuww35ooZaTD3BIjp9CyZqwv++gAnanWXKdiWJ8= github.com/HACKERALERT/mainthread v0.0.0-20211027212305-2ec9e701cc14 h1:DwWXverhu/dEsPM/GPykuHGh4SxW69DaGZL5t3fANG4= github.com/HACKERALERT/mainthread v0.0.0-20211027212305-2ec9e701cc14/go.mod h1:jW534e7roGur9mmzAfPxZLQzKXZ+GE5+XeS7PSyqPbo= github.com/HACKERALERT/serpent v0.0.0-20210716182301-293b29869c66 h1:YDpFq+y6mRcu97rn/rhYg8u8FdeO0wzTuLgM2gVkA+c= github.com/HACKERALERT/serpent v0.0.0-20210716182301-293b29869c66/go.mod h1:d/+9q3sIxtIyOgHNgFGr3yGBKKVn5h3vL4hV1qlmoLs= -github.com/HACKERALERT/w32 v0.0.0-20210716142531-faa7189c4abf h1:L25UAtgOR6GC0TrLxaIx1Q3vUhd3SilulIPuEw+PkxI= -github.com/HACKERALERT/w32 v0.0.0-20210716142531-faa7189c4abf/go.mod h1:S+3Ad2AEm5MhhuHJeAaXUmyAXON0qFDxcP/Chw8q7+Y= +github.com/HACKERALERT/w32 v0.0.0-20211215215707-4b84c2675d8d h1:Ey0tgsr4MbX64pkl7Di26yUUQGG3mmZw8gUWqhQeW5g= +github.com/HACKERALERT/w32 v0.0.0-20211215215707-4b84c2675d8d/go.mod h1:S+3Ad2AEm5MhhuHJeAaXUmyAXON0qFDxcP/Chw8q7+Y= github.com/HACKERALERT/zxcvbn-go v0.0.0-20210927200100-f131a4666ad5 h1:cIW3wwoeZ6zru8VhdoGlZAinG+6ObzHx7BgQxUfhF34= github.com/HACKERALERT/zxcvbn-go v0.0.0-20210927200100-f131a4666ad5/go.mod h1:nykydiYjCDMkF/2vQXSPM38vR5N9W1DITHvupnN+eOk= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e h1:1SzTfNOXwIS2oWiMF+6qu0OUDKb0dauo6MoDUQyu+yU= +golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/sys v0.0.0-20211215211219-4abf325e0275/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/src/snap/gui/picocrypt.desktop b/src/snap/gui/picocrypt.desktop index ca214a0..a1aec18 100644 --- a/src/snap/gui/picocrypt.desktop +++ b/src/snap/gui/picocrypt.desktop @@ -1,5 +1,5 @@ [Desktop Entry] -Version=1.21 +Version=1.22 Encoding=UTF-8 Type=Application Terminal=false diff --git a/src/snapcraft.yaml b/src/snapcraft.yaml index e9d206d..7ac0aea 100644 --- a/src/snapcraft.yaml +++ b/src/snapcraft.yaml @@ -1,7 +1,7 @@ name: picocrypt summary: A very small, very simple, yet very secure encryption tool. -description: Picocrypt is a very small, very simple, yet very secure encryption tool that you can use to protect your files, generate checksums, and much more. It's designed to be the go-to tool for encryption, with a focus on security, simplicity, and reliability. Picocrypt uses the secure XChaCha20 cipher and the SHA3 hash function to provide a high level of security, even from three-letter agencies like the NSA. It's designed for maximal security, making absolutely no compromises security-wise, and is built with Go's standard x/crypto modules. Your privacy and security is under attack. Take it back with confidence by protecting your files with Picocrypt. -version: "1.21" +description: Picocrypt is a very small, very simple, yet very secure encryption tool that you can use to protect your files, generate checksums, and much more. It's designed to be the go-to tool for encryption, with a focus on security, simplicity, and reliability. Picocrypt uses the secure XChaCha20 cipher and the Argon2 key derivation function to provide a high level of security, even from three-letter agencies like the NSA. It's designed for maximal security, making absolutely no compromises security-wise, and is built with Go's standard x/crypto modules. Your privacy and security is under attack. Take it back with confidence by protecting your files with Picocrypt. +version: "1.22" confinement: strict base: core20 grade: stable @@ -20,7 +20,6 @@ parts: source: . build-packages: - gcc - - make - libx11-dev - libxcursor-dev - libxrandr-dev @@ -30,10 +29,8 @@ parts: - libxxf86vm-dev - libgtk-3-dev stage-packages: - - xclip - - xdg-utils - libglu1-mesa - - language-pack-en-base + - xclip after: - desktop-glib-only desktop-glib-only: diff --git a/src/unstable/Picocrypt.go b/src/unstable/Picocrypt.go deleted file mode 100644 index 153c985..0000000 --- a/src/unstable/Picocrypt.go +++ /dev/null @@ -1,2214 +0,0 @@ -package main - -/* - -Picocrypt v1.21 -Copyright (c) Evan Su (https://evansu.cc) -Released under a GNU GPL v3 License -https://github.com/HACKERALERT/Picocrypt - -~ In cryptography we trust ~ - -*/ - -import ( - _ "embed" - - // Generic - "archive/zip" - "bytes" - "encoding/hex" - "encoding/json" - "fmt" - "hash" - "image" - "image/color" - "image/png" - "io" - "math" - "math/big" - "net/http" - "os" - "path/filepath" - "regexp" - "runtime/debug" - "strconv" - "strings" - "time" - - // Cryptography - "crypto/cipher" - "crypto/hmac" - "crypto/md5" - "crypto/rand" - "crypto/sha1" - "crypto/sha256" - "crypto/subtle" - - "github.com/HACKERALERT/serpent" - "golang.org/x/crypto/argon2" - "golang.org/x/crypto/blake2b" - "golang.org/x/crypto/blake2s" - "golang.org/x/crypto/chacha20" - "golang.org/x/crypto/hkdf" - "golang.org/x/crypto/sha3" - - // UI - "github.com/HACKERALERT/giu" - - // Reed-Solomon - "github.com/HACKERALERT/infectious" - - // Helpers - "github.com/HACKERALERT/clipboard" - "github.com/HACKERALERT/dialog" - "github.com/HACKERALERT/jibber_jabber" - "github.com/HACKERALERT/zxcvbn-go" -) - -//go:embed icon.png -var icon []byte - -//go:embed font.ttf -var font []byte - -//go:embed strings.json -var localeBytes []byte - -// Localization -type locale struct { - iso string - data []string -} - -var locales []locale -var selectedLocale = "en" -var allLocales = []string{ - "en", -} -var languages = []string{ - "English", -} -var languageSelected int32 - -// Generic variables -var version = "v1.21" -var window *giu.MasterWindow -var windowOptimized bool -var dpi float32 -var tab = 0 -var mode string -var working bool -var recombine bool - -// 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." -var inputFile string - -// Password variables -var password string -var cPassword string -var passwordStrength int -var passwordState = giu.InputTextFlagsPassword -var passwordStateLabel = "Show" - -// Password generator variables -var showGenpass = false -var genpassCopy = true -var genpassLength int32 = 32 -var genpassUpper = true -var genpassLower = true -var genpassNums = true -var genpassSymbols = true - -// 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 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 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 - -// Reed-Solomon encoders -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) - -// File checksum generator variables -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 - -func draw() { - giu.SingleWindow().Flags(giu.WindowFlagsNoDecoration|giu.WindowFlagsNoNavFocus|giu.WindowFlagsNoMove| - giu.WindowFlagsNoScrollWithMouse).Layout( - 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] - }).Size(w/dpi+26), - ).Build() - giu.SetCursorPos(pos) - - giu.TabBar().TabItems( - giu.TabItem(s("Encryption")).Layout( - giu.Custom(func() { - if giu.IsItemActive() { - tab = 0 - } - }), - - 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(giu.Auto), - ), - 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() - } - }), - - giu.Custom(func() { - if showKeyfile { - giu.PopupModal(s("Manage keyfiles:")). - Flags(giu.WindowFlagsNoMove|giu.WindowFlagsNoResize|giu.WindowFlagsAlwaysAutoResize).Layout( - giu.Label(s("Drag and drop your keyfiles here.")), - 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() - } - }), - - giu.Custom(func() { - for _, i := range keyfiles { - giu.Row( - giu.SmallButton("×").OnClick(func() { - var tmp []string - for _, j := range keyfiles { - if j != i { - tmp = append(tmp, j) - } - } - keyfiles = tmp - if len(keyfiles) == 0 { - keyfilePrompt = s("None selected.") - } else if len(keyfiles) == 1 { - keyfilePrompt = s("Using 1 keyfile.") - } else { - keyfilePrompt = fmt.Sprintf(s("Using %d keyfiles."), len(keyfiles)) - } - }), - giu.Label(filepath.Base(i)), - ).Build() - - } - }), - giu.Row( - giu.Button(s("Clear")).Size(150, 0).OnClick(func() { - keyfiles = nil - keyfilePrompt = s("None selected.") - }), - giu.Tooltip(s("Remove all keyfiles.")), - giu.Button(s("Done")).Size(150, 0).OnClick(func() { - giu.CloseCurrentPopup() - showKeyfile = false - }), - ), - ).Build() - giu.OpenPopup(s("Manage keyfiles:")) - giu.Update() - } - }), - - 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 - }), - giu.Button(s("Yes")).Size(100, 0).OnClick(func() { - giu.CloseCurrentPopup() - showConfirmation = false - showProgress = true - giu.Update() - go func() { - work() - working = false - 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).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() { - bw, _ := giu.CalcTextSize(s("Clear")) - p, _ := giu.GetWindowPadding() - bw += p * 2 - giu.Dummy(float32(float64(-(bw+p)/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() - }), - ), - - giu.Separator(), - - giu.Style().SetDisabled(len(allFiles) == 0 && len(onlyFiles) == 0).To( - giu.Row( - giu.Label(s("Password:")), - giu.Dummy(-124, 0), - giu.Style().SetDisabled(mode == "decrypt" && !keyfile).To( - giu.Label(s("Keyfiles:")), - ), - ), - giu.Row( - giu.Button(s(passwordStateLabel)).Size(54, 0).OnClick(func() { - if passwordState == giu.InputTextFlagsPassword { - passwordState = giu.InputTextFlagsNone - passwordStateLabel = "Hide" - } else { - passwordState = giu.InputTextFlagsPassword - passwordStateLabel = "Show" - } - }), - - giu.Button(s("Clear")).Size(54, 0).OnClick(func() { - password = "" - cPassword = "" - }), - - 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 - } - passwordStrength = zxcvbn.PasswordStrength(password, nil).Score - giu.Update() - }), - - 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() - }), - ), - ), - ), - ), - giu.Row( - giu.InputText(&password).Flags(passwordState).Size(302/dpi).OnChange(func() { - passwordStrength = zxcvbn.PasswordStrength(password, nil).Score - }), - giu.Custom(func() { - c := giu.GetCanvas() - p := giu.GetCursorScreenPos() - - var col color.RGBA - 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} - } - if password == "" || mode == "decrypt" { - col = color.RGBA{0xff, 0xff, 0xff, 0x00} - } - - path := p.Add(image.Pt( - int(math.Round(float64(-20*dpi))), - int(math.Round(float64(12*dpi))), - )) - c.PathArcTo(path, 6*dpi, -math.Pi/2, float32(passwordStrength+1)/5*2*math.Pi-math.Pi/2, -1) - c.PathStroke(col, false, 2) - }), - giu.Style().SetDisabled(true).To( - giu.InputText(&keyfilePrompt).Size(giu.Auto), - ), - ), - ), - - giu.Style().SetDisabled(password == "").To( - giu.Row( - giu.Style().SetDisabled(mode == "decrypt").To( - giu.Label(s("Confirm password:")), - ), - giu.Dummy(-124, 0), - giu.Style().SetDisabled(true).To( - giu.Label(s("Custom Argon2:")), - ), - ), - ), - giu.Style().SetDisabled(password == "").To( - giu.Row( - giu.Style().SetDisabled(mode == "decrypt").To( - giu.Row( - 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} - } - if password == "" || cPassword == "" || mode == "decrypt" { - col = color.RGBA{0xff, 0xff, 0xff, 0x00} - } - - path := p.Add(image.Pt( - int(math.Round(float64(-20*dpi))), - int(math.Round(float64(12*dpi))), - )) - c.PathArcTo(path, 6*dpi, 0, 2*math.Pi, -1) - c.PathStroke(col, false, 2) - }), - ), - ), - giu.Style().SetDisabled(true).To( - giu.Button(s("W.I.P")).Size(giu.Auto, 0), - ), - ), - ), - - giu.Dummy(0, 3), - giu.Separator(), - giu.Dummy(0, 0), - - giu.Style().SetDisabled(password == "" || (password != cPassword && mode == "encrypt")).To( - giu.Label(s(metadataPrompt)), - giu.Style().SetDisabled(metadataDisabled).To( - giu.InputText(&metadata).Size(giu.Auto), - ), - - giu.Label(s("Advanced:")), - giu.Custom(func() { - if mode != "decrypt" { - giu.Row( - giu.Checkbox(s("Use fast mode"), &fast), - giu.Dummy(-221, 0), - giu.Checkbox(s("Encode with Reed-Solomon"), &reedsolo), - ).Build() - giu.Row( - giu.Checkbox(s("Use paranoid mode"), ¶noid), - giu.Dummy(-221, 0), - giu.Checkbox(s("Delete files when complete"), &deleteWhenDone), - ).Build() - giu.Row( - giu.Style().SetDisabled(!(len(allFiles) > 1 || len(onlyFolders) > 0)).To( - giu.Checkbox(s("Compress files"), &compress), - ), - giu.Dummy(-221, 0), - giu.Checkbox(s("Split every"), &split), - giu.InputText(&splitSize).Size(55/dpi).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.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 / 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 - } - } - - 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(giu.Auto, 34).OnClick(func() { - if keyfile && keyfiles == nil { - mainStatus = "Please select your keyfiles." - mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff} - return - } - _, err := os.Stat(outputFile) - if err == nil { - showConfirmation = true - giu.Update() - } else { - showProgress = true - giu.Update() - go func() { - work() - working = false - showProgress = false - debug.FreeOSMemory() - giu.Update() - }() - } - }), - 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(giu.Auto).Flags(giu.InputTextFlagsReadOnly), - ), - ), - - // 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(giu.Auto).Flags(giu.InputTextFlagsReadOnly), - ), - ), - - // 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(giu.Auto).Flags(giu.InputTextFlagsReadOnly), - ), - ), - - // 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(giu.Auto).Flags(giu.InputTextFlagsReadOnly), - ), - ), - - // 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(giu.Auto).Flags(giu.InputTextFlagsReadOnly), - ), - ), - - // 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(giu.Auto).Flags(giu.InputTextFlagsReadOnly), - ), - ), - - // 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() - }).Build() - }), - 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() - }), - ), - giu.Style().SetDisabled(true).To( - giu.InputText(&csValidate).Size(giu.Auto), - ), - - // Progress bar - giu.Label(s("Progress:")), - giu.ProgressBar(csProgress).Size(giu.Auto, 0), - ), - giu.TabItem(s("About")).Layout( - giu.Custom(func() { - if giu.IsItemActive() { - tab = 2 - } - }), - 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() - }), - giu.Custom(func() { - if !windowOptimized || windowOptimized { - windowOptimized = true - var pad int - if tab == 1 { - pad = 6 - } - if tab == 2 { - pad = 1 - } - if tab == 3 { - pad = 2 - } - window.SetSize(int(442*dpi), giu.GetCursorPos().Y+1+pad) - } - }), - ) -} - -func onDrop(names []string) { - if tab == 1 { - go generateChecksums(names[0]) - return - } - if tab == 2 { - return - } - - if showKeyfile { - keyfiles = append(keyfiles, names...) - var tmp []string - for _, i := range keyfiles { - duplicate := false - for _, j := range tmp { - if i == j { - duplicate = true - } - } - stat, _ := os.Stat(i) - if !duplicate && !stat.IsDir() { - tmp = append(tmp, i) - } - } - keyfiles = tmp - if len(keyfiles) == 1 { - keyfilePrompt = s("Using 1 keyfile.") - } else { - keyfilePrompt = fmt.Sprintf(s("Using %d keyfiles."), len(keyfiles)) - } - return - } - - // Clear variables - recombine = false - onlyFiles = nil - onlyFolders = nil - allFiles = nil - files, folders := 0, 0 - resetUI() - - 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] - } - - // 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]) - } - - // 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) - - if err == nil { - metadataLength, _ := strconv.Atoi(string(tmp)) - tmp = make([]byte, metadataLength*3) - fin.Read(tmp) - metadata = "" - - 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 - } - metadata += string(t) - } - } else { - metadata = s("Metadata is corrupted.") - } - - 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 - } - - if flags[2] == 1 { - keyfile = true - keyfilePrompt = s("Keyfiles required.") - } else { - keyfilePrompt = s("Not applicable.") - } - if flags[5] == 1 { - keyfileOrderMatters = true - } - } else { - mode = "encrypt" - inputLabel = name + s(" (will encrypt)") - inputFile = names[0] - outputFile = names[0] + ".pcv" - } - - // Add the file - onlyFiles = append(onlyFiles, names[0]) - inputFile = names[0] - } - } else { - mode = "encrypt" - - // There are multiple dropped items, check each one - for _, name := range names { - stat, _ := os.Stat(name) - - // Check if item is a file or a directory - if stat.IsDir() { - folders++ - onlyFolders = append(onlyFolders, name) - } else { - files++ - onlyFiles = append(onlyFiles, name) - allFiles = append(allFiles, name) - } - } - - if folders == 0 { - 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 - }) - } - } -} - -func work() { - popupStatus = s("Starting...") - mainStatus = "Working..." - mainStatusColor = color.RGBA{0xff, 0xff, 0xff, 0xff} - working = true - padded := false - - var salt []byte - var hkdfSalt []byte - var serpentSalt []byte - var nonce []byte - var keyHash []byte - var _keyHash []byte - 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 { - var rootDir string - if len(onlyFolders) > 0 { - rootDir = filepath.Dir(onlyFolders[0]) - } else { - rootDir = filepath.Dir(onlyFiles[0]) - } - - file, err := os.Create(inputFile) - if err != nil { - mainStatus = "Access denied by operating system." - mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff} - return - } - - w := zip.NewWriter(file) - for i, path := range allFiles { - if !working { - w.Close() - file.Close() - os.Remove(inputFile) - mainStatus = "Operation cancelled by user." - mainStatusColor = color.RGBA{0xff, 0xff, 0xff, 0xff} - return - } - progressInfo = fmt.Sprintf("%d/%d", i, len(allFiles)) - progress = float32(i) / float32(len(allFiles)) - giu.Update() - if path == inputFile { - continue - } - - stat, _ := os.Stat(path) - header, _ := zip.FileInfoHeader(stat) - header.Name = strings.TrimPrefix(path, rootDir) - header.Name = filepath.ToSlash(header.Name) - header.Name = strings.TrimPrefix(header.Name, "/") - - if compress { - header.Method = zip.Deflate - } else { - header.Method = zip.Store - } - writer, _ := w.CreateHeader(header) - file, _ := os.Open(path) - io.Copy(writer, file) - file.Close() - } - w.Flush() - w.Close() - file.Close() - } - } - - if recombine { - popupStatus = s("Recombining file...") - total := 0 - - for { - _, err := os.Stat(fmt.Sprintf("%s.%d", inputFile, total)) - if err != nil { - break - } - total++ - } - - 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 { - break - } - data = data[:read] - fout.Write(data) - } - fin.Close() - progressInfo = fmt.Sprintf("%d/%d", i, total) - progress = float32(i) / float32(total) - giu.Update() - } - fout.Close() - progressInfo = "" - } - - stat, _ := os.Stat(inputFile) - total := stat.Size() - if mode == "decrypt" { - total -= 789 - } - - // XChaCha20's max message size is 256 GiB - if total > 256*1073741824 { - mainStatus = "Total size is larger than 256 GiB, XChaCha20's limit." - mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff} - return - } - - // Open input file in read-only mode - fin, err := os.Open(inputFile) - if err != nil { - mainStatus = "Access denied by operating system." - mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff} - return - } - - var fout *os.File - - // If encrypting, generate values; if decrypting, read values from file - if mode == "encrypt" { - popupStatus = s("Generating values...") - giu.Update() - - 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) - - // Write version to file - fout.Write(rsEncode(rs5, []byte(version))) - - // Encode the length of the metadata with Reed-Solomon - metadataLength := []byte(fmt.Sprintf("%05d", len(metadata))) - metadataLength = rsEncode(rs5, metadataLength) - - // Write the length of the metadata to file - fout.Write(metadataLength) - - // Reed-Solomon-encode the metadata and write to file - for _, i := range []byte(metadata) { - fout.Write(rsEncode(rs1, []byte{i})) - } - - flags := make([]byte, 6) - if fast { - flags[0] = 1 - } - if paranoid { - flags[1] = 1 - } - if len(keyfiles) > 0 { - flags[2] = 1 - } - if reedsolo { - flags[3] = 1 - } - if total%1048576 >= 1048448 { - flags[4] = 1 - } - if keyfileOrderMatters { - flags[5] = 1 - } - flags = rsEncode(rs6, flags) - fout.Write(flags) - - // Fill salts and nonce with Go's CSPRNG - rand.Read(salt) - rand.Read(hkdfSalt) - rand.Read(serpentSalt) - rand.Read(nonce) - - // Encode salt with Reed-Solomon and write to file - _salt := rsEncode(rs16, salt) - fout.Write(_salt) - - // Encode HKDF salt with Reed-Solomon and write to file - _hkdfSalt := rsEncode(rs32, hkdfSalt) - fout.Write(_hkdfSalt) - - // Encode Serpent salt with Reed-Solomon and write to file - _serpentSalt := rsEncode(rs16, serpentSalt) - fout.Write(_serpentSalt) - - // Encode nonce with Reed-Solomon and write to file - _nonce := rsEncode(rs24, nonce) - fout.Write(_nonce) - - // Write placeholder for hash of key - fout.Write(make([]byte, 192)) - - // Write placeholder for hash of hash of keyfile - fout.Write(make([]byte, 96)) - - // Write placeholder for HMAC-BLAKE2b/HMAC-SHA3 of file - fout.Write(make([]byte, 192)) - } else { - 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 - - popupStatus = s("Reading values...") - giu.Update() - - version := make([]byte, 15) - fin.Read(version) - _, err1 = rsDecode(rs5, version) - - tmp := make([]byte, 15) - fin.Read(tmp) - tmp, err2 = rsDecode(rs5, tmp) - metadataLength, _ := strconv.Atoi(string(tmp)) - - fin.Read(make([]byte, metadataLength*3)) - - flags := make([]byte, 18) - fin.Read(flags) - flags, err3 = rsDecode(rs6, flags) - fast = flags[0] == 1 - paranoid = flags[1] == 1 - reedsolo = flags[3] == 1 - padded = flags[4] == 1 - - salt = make([]byte, 48) - fin.Read(salt) - salt, err4 = rsDecode(rs16, salt) - - hkdfSalt = make([]byte, 96) - fin.Read(hkdfSalt) - hkdfSalt, err5 = rsDecode(rs32, hkdfSalt) - - serpentSalt = make([]byte, 48) - fin.Read(serpentSalt) - serpentSalt, err6 = rsDecode(rs16, serpentSalt) - - nonce = make([]byte, 72) - fin.Read(nonce) - nonce, err7 = rsDecode(rs24, nonce) - - _keyHash = make([]byte, 192) - fin.Read(_keyHash) - _keyHash, err8 = rsDecode(rs64, _keyHash) - - _keyfileHash = make([]byte, 96) - fin.Read(_keyfileHash) - _keyfileHash, err9 = rsDecode(rs32, _keyfileHash) - - dataMac = make([]byte, 192) - fin.Read(dataMac) - dataMac, err10 = rsDecode(rs64, dataMac) - - // Is there a better way? - if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil || - err6 != nil || err7 != nil || err8 != nil || err9 != nil || err10 != nil { - if keep { - kept = true - } else { - mainStatus = "The header is corrupt and the input file cannot be decrypted." - mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff} - fin.Close() - return - } - } - } - - popupStatus = s("Deriving key...") - progress = 0 - progressInfo = "" - giu.Update() - - // Derive encryption/decryption keys and subkeys - var key []byte - if fast { - key = argon2.IDKey( - []byte(password), - salt, - 4, - 131072, - 4, - 32, - ) - } else if paranoid { - key = argon2.IDKey( - []byte(password), - salt, - 8, - 1048576, - 8, - 32, - ) - } else { - key = argon2.IDKey( - []byte(password), - salt, - 4, - 1048576, - 4, - 32, - ) - } - - 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) - } - if recombine { - os.Remove(inputFile) - } - os.Remove(outputFile) - return - } - - if len(keyfiles) > 0 || keyfile { - if keyfileOrderMatters { - var keysum = sha3.New256() - for _, path := range keyfiles { - kin, _ := os.Open(path) - kstat, _ := os.Stat(path) - kbytes := make([]byte, kstat.Size()) - kin.Read(kbytes) - kin.Close() - keysum.Write(kbytes) - } - keyfileKey = keysum.Sum(nil) - keyfileSha3 := sha3.New256() - keyfileSha3.Write(keyfileKey) - keyfileHash = keyfileSha3.Sum(nil) - } else { - var keysum []byte - for _, path := range keyfiles { - kin, _ := os.Open(path) - kstat, _ := os.Stat(path) - kbytes := make([]byte, kstat.Size()) - kin.Read(kbytes) - kin.Close() - ksha3 := sha3.New256() - ksha3.Write(kbytes) - keyfileKey := ksha3.Sum(nil) - if keysum == nil { - keysum = keyfileKey - } else { - for i, j := range keyfileKey { - keysum[i] ^= j - } - } - } - keyfileKey = keysum - keyfileSha3 := sha3.New256() - keyfileSha3.Write(keysum) - keyfileHash = keyfileSha3.Sum(nil) - } - } - - sha3_512 := sha3.New512() - sha3_512.Write(key) - keyHash = sha3_512.Sum(nil) - - // Validate password and/or keyfiles - if mode == "decrypt" { - keyCorrect := true - keyfileCorrect := true - var tmp bool - - keyCorrect = !(subtle.ConstantTimeCompare(keyHash, _keyHash) == 0) - if keyfile { - keyfileCorrect = !(subtle.ConstantTimeCompare(keyfileHash, _keyfileHash) == 0) - tmp = !keyCorrect || !keyfileCorrect - } else { - tmp = !keyCorrect - } - - if tmp || keep { - if keep { - kept = true - } else { - fin.Close() - if !keyCorrect { - mainStatus = "The provided password is incorrect." - } else { - if keyfileOrderMatters { - mainStatus = "Incorrect keyfiles and/or order." - } else { - mainStatus = "Incorrect keyfiles." - } - } - mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff} - key = nil - if recombine { - os.Remove(inputFile) - } - return - } - } - - 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 - } - } - - if len(keyfiles) > 0 || keyfile { - // XOR key and keyfile - tmp := key - key = make([]byte, 32) - for i := range key { - key[i] = tmp[i] ^ keyfileKey[i] - } - } - - done := 0 - counter := 0 - startTime := time.Now() - chacha20, _ := chacha20.NewUnauthenticatedCipher(key, nonce) - - // Use HKDF-SHA3 to generate a subkey - var mac hash.Hash - subkey := make([]byte, 32) - hkdf := hkdf.New(sha3.New256, key, hkdfSalt, nil) - hkdf.Read(subkey) - if fast { - // Keyed BLAKE2b - mac, _ = blake2b.New512(subkey) - } else { - // HMAC-SHA3 - mac = hmac.New(sha3.New512, subkey) - } - - // Generate another subkey and cipher (not used unless paranoid mode is checked) - serpentKey := make([]byte, 32) - hkdf.Read(serpentKey) - _serpent, _ := serpent.NewCipher(serpentKey) - serpentCTR := cipher.NewCTR(_serpent, serpentSalt) - - for { - if !working { - mainStatus = "Operation cancelled by user." - mainStatusColor = color.RGBA{0xff, 0xff, 0xff, 0xff} - fin.Close() - fout.Close() - if mode == "encrypt" && (len(allFiles) > 1 || len(onlyFolders) > 0) { - os.Remove(outputFile) - } - if recombine { - os.Remove(inputFile) - } - os.Remove(outputFile) - return - } - - var data []byte - if mode == "decrypt" && reedsolo { - data = make([]byte, 1114112) - } else { - data = make([]byte, 1048576) - } - - size, err := fin.Read(data) - if err != nil { - break - } - data = data[:size] - _data := make([]byte, len(data)) - - // "Actual" encryption is done in the next couple of lines - if mode == "encrypt" { - if paranoid { - serpentCTR.XORKeyStream(_data, data) - copy(data, _data) - } - - chacha20.XORKeyStream(_data, data) - mac.Write(_data) - - if reedsolo { - copy(data, _data) - _data = nil - if len(data) == 1048576 { - for i := 0; i < 1048576; i += 128 { - tmp := data[i : i+128] - tmp = rsEncode(rs128, tmp) - _data = append(_data, tmp...) - } - } 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...) - } - tmp := data[int(chunks*128):] - _data = append(_data, rsEncode(rs128, pad(tmp))...) - } - } - } else { - if reedsolo { - copy(_data, data) - data = nil - 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 { - kept = true - } else { - mainStatus = "The input file is too corrupted to decrypt." - mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff} - fin.Close() - fout.Close() - broken() - return - } - } - if i == 1113976 && done+1114112 >= int(total) && padded { - tmp = unpad(tmp) - } - data = append(data, tmp...) - } - } 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 { - kept = true - } else { - mainStatus = "The input file is too corrupted to decrypt." - mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff} - fin.Close() - fout.Close() - broken() - return - } - } - data = append(data, tmp...) - } - tmp := _data[int(chunks)*136:] - tmp, err = rsDecode(rs128, tmp) - if err != nil { - if keep { - kept = true - } else { - mainStatus = "The input file is too corrupted to decrypt." - mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff} - fin.Close() - fout.Close() - broken() - return - } - } - tmp = unpad(tmp) - data = append(data, tmp...) - } - _data = make([]byte, len(data)) - } - - mac.Write(data) - chacha20.XORKeyStream(_data, data) - - if paranoid { - copy(data, _data) - serpentCTR.XORKeyStream(_data, data) - } - } - fout.Write(_data) - - // Update stats - if mode == "decrypt" && reedsolo { - done += 1114112 - } else { - done += 1048576 - } - counter++ - 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)))) - - if progress > 1 { - progress = 1 - } - - progressInfo = fmt.Sprintf("%.2f%%", progress*100) - popupStatus = fmt.Sprintf(s("Working at %.2f MB/s (ETA: %s)"), speed, humanize(eta)) - giu.Update() - } - - if mode == "encrypt" { - // Seek back to header and write important data - 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 { - // Validate the authenticity of decrypted data - if subtle.ConstantTimeCompare(mac.Sum(nil), dataMac) == 0 { - if keep { - kept = true - } else { - fin.Close() - fout.Close() - broken() - return - } - } - } - - fin.Close() - fout.Close() - - // Split files into chunks - if split { - var splitted []string - popupStatus = s("Splitting file...") - stat, _ := os.Stat(outputFile) - size := stat.Size() - finished := 0 - chunkSize, _ := strconv.Atoi(splitSize) - - // User can choose KiB, MiB, and GiB - if splitSelected == 0 { - chunkSize *= 1024 - } else if splitSelected == 1 { - chunkSize *= 1048576 - } else { - chunkSize *= 1073741824 - } - chunks := int(math.Ceil(float64(size) / float64(chunkSize))) - fin, _ := os.Open(outputFile) - - for i := 0; i < chunks; i++ { - fout, _ := os.Create(fmt.Sprintf("%s.%d", outputFile, i)) - done := 0 - for { - data := make([]byte, 1048576) - read, err := fin.Read(data) - if err != nil { - break - } - if !working { - fin.Close() - fout.Close() - mainStatus = "Operation cancelled by user." - mainStatusColor = color.RGBA{0xff, 0xff, 0xff, 0xff} - - // If user cancels, remove the unfinished files - for _, j := range splitted { - os.Remove(j) - } - os.Remove(fmt.Sprintf("%s.%d", outputFile, i)) - os.Remove(outputFile) - return - } - data = data[:read] - fout.Write(data) - done += read - if done >= chunkSize { - break - } - } - fout.Close() - finished++ - splitted = append(splitted, fmt.Sprintf("%s.%d", outputFile, i)) - progress = float32(finished) / float32(chunks) - progressInfo = fmt.Sprintf("%d/%d", finished, chunks) - giu.Update() - } - fin.Close() - os.Remove(outputFile) - } - - // Remove the temporary file used to combine a splitted Picocrypt volume - if recombine { - os.Remove(inputFile) - } - - // Delete the temporary zip file if user wishes - if len(allFiles) > 1 || len(onlyFolders) > 0 { - os.Remove(inputFile) - } - - 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++ - } - } else { - os.Remove(inputFile) - } - } else { - for _, i := range onlyFiles { - os.Remove(i) - } - for _, i := range onlyFolders { - os.RemoveAll(i) - } - } - } - - resetUI() - - // If user chose to keep a corrupted/modified file, let them know - 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} - } - - // Clear UI state - working = false - kept = false - key = nil - popupStatus = s("Ready.") -} - -// This function is run if an issue occurs during decryption -func broken() { - mainStatus = "The input file is either corrupted or intentionally modified." - mainStatusColor = color.RGBA{0xff, 0x00, 0x00, 0xff} - if recombine { - os.Remove(inputFile) - } - os.Remove(outputFile) - giu.Update() -} - -// Generate file checksums -func generateChecksums(file string) { - fin, _ := os.Open(file) - - // Clear UI state - 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...") - } - if sha1Selected { - csSha1 = s("Calculating...") - } - if sha256Selected { - csSha256 = s("Calculating...") - } - if sha3Selected { - csSha3 = s("Calculating...") - } - if blake2bSelected { - csBlake2b = s("Calculating...") - } - if blake2sSelected { - csBlake2s = s("Calculating...") - } - - // Create the checksum objects - crcMd5 := md5.New() - crcSha1 := sha1.New() - crcSha256 := sha256.New() - crcSha3 := sha3.New256() - crcBlake2b, _ := blake2b.New256(nil) - crcBlake2s, _ := blake2s.New256(nil) - - stat, _ := os.Stat(file) - total := stat.Size() - var done int64 = 0 - for { - var data []byte - _data := make([]byte, 1048576) - size, err := fin.Read(_data) - if err != nil { - break - } - data = _data[:size] - - if md5Selected { - crcMd5.Write(data) - } - if sha1Selected { - crcSha1.Write(data) - } - if sha256Selected { - crcSha256.Write(data) - } - if sha3Selected { - crcSha3.Write(data) - } - if blake2bSelected { - crcBlake2b.Write(data) - } - if blake2sSelected { - crcBlake2s.Write(data) - } - - done += int64(size) - csProgress = float32(done) / float32(total) - giu.Update() - } - csProgress = 0 - if md5Selected { - csMd5 = hex.EncodeToString(crcMd5.Sum(nil)) - } - if sha1Selected { - csSha1 = hex.EncodeToString(crcSha1.Sum(nil)) - } - if sha256Selected { - csSha256 = hex.EncodeToString(crcSha256.Sum(nil)) - } - if sha3Selected { - csSha3 = hex.EncodeToString(crcSha3.Sum(nil)) - } - if blake2bSelected { - csBlake2b = hex.EncodeToString(crcBlake2b.Sum(nil)) - } - if blake2sSelected { - csBlake2s = hex.EncodeToString(crcBlake2s.Sum(nil)) - } - - fin.Close() - giu.Update() -} - -// Reset the UI to a clean state with nothing selected or checked -func resetUI() { - mode = "" - onlyFiles = nil - onlyFolders = nil - allFiles = nil - inputLabel = s("Drop files and folders into this window.") - password = "" - cPassword = "" - keyfiles = nil - keyfile = false - keyfileOrderMatters = false - keyfilePrompt = s("None selected.") - metadata = "" - metadataPrompt = "Metadata:" - metadataDisabled = false - keep = false - reedsolo = false - split = false - splitSize = "" - splitSelected = 1 - fast = false - deleteWhenDone = false - paranoid = false - compress = false - inputFile = "" - outputFile = "" - progress = 0 - progressInfo = "" - mainStatus = "Ready." - mainStatusColor = color.RGBA{0xff, 0xff, 0xff, 0xff} - giu.Update() -} - -// Reed-Solomon encoder -func rsEncode(rs *infectious.FEC, data []byte) []byte { - var res []byte - rs.Encode(data, func(s infectious.Share) { - res = append(res, s.DeepCopy().Data[0]) - }) - return res -} - -// Reed-Solomon decoder -func rsDecode(rs *infectious.FEC, data []byte) ([]byte, error) { - tmp := make([]infectious.Share, rs.Total()) - for i := 0; i < rs.Total(); i++ { - tmp[i] = infectious.Share{ - Number: i, - Data: []byte{data[i]}, - } - } - res, err := rs.Decode(nil, tmp) - if err != nil { - if rs.Total() == 136 { - return data[:128], err - } - return data[:rs.Total()/3], err - } - return res, nil -} - -// PKCS7 Pad (for use with Reed-Solomon, not for cryptographic purposes) -func pad(data []byte) []byte { - padLen := 128 - len(data)%128 - padding := bytes.Repeat([]byte{byte(padLen)}, padLen) - return append(data, padding...) -} - -// PKCS7 Unpad -func unpad(data []byte) []byte { - length := len(data) - padLen := int(data[length-1]) - return data[:length-padLen] -} - -func genPassword() string { - chars := "" - if genpassUpper { - chars += "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - } - if genpassLower { - chars += "abcdefghijklmnopqrstuvwxyz" - } - if genpassNums { - chars += "1234567890" - } - if genpassSymbols { - chars += "-=!@#$^&()_+?" - } - if chars == "" { - return chars - } - tmp := make([]byte, genpassLength) - for i := 0; i < int(genpassLength); i++ { - j, _ := rand.Int(rand.Reader, new(big.Int).SetUint64(uint64(len(chars)))) - tmp[i] = chars[j.Int64()] - } - if genpassCopy { - clipboard.WriteAll(string(tmp)) - } - return string(tmp) -} - -// 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 { - return i.data[k] - } - } - } - } - - } - } - return term -} - -func main() { - // Parse locales - var obj map[string]json.RawMessage - json.Unmarshal(localeBytes, &obj) - for i := range obj { - var tmp []string - json.Unmarshal(obj[i], &tmp) - locales = append(locales, locale{ - iso: i, - data: tmp, - }) - } - - // Check system locale - for _, i := range locales { - tmp, err := jibber_jabber.DetectIETF() - if err == nil { - if strings.HasPrefix(tmp, i.iso) { - selectedLocale = i.iso - for j, k := range allLocales { - if k == i.iso { - languageSelected = int32(j) - } - } - } - } - } - - // Set a universal font - giu.SetDefaultFontFromBytes(font, 18) - - // Create the master window - window = giu.NewMasterWindow("Picocrypt", 442, 532, giu.MasterWindowFlagsNotResizable) - dialog.Init() - - // Set window icon - reader := bytes.NewReader(icon) - decoded, _ := png.Decode(reader) - window.SetIcon([]image.Image{decoded}) - - // Set callbacks - window.SetDropCallback(onDrop) - window.SetCloseCallback(func() bool { - return !working - }) - - // Set universal DPI - dpi = giu.Context.GetPlatform().GetContentScale() - - // 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{0x00, 0xff, 0x00, 0xff} - } - } - } - }() - - // Start the UI - window.Run(draw) -} diff --git a/src/unstable/README.md b/src/unstable/README.md deleted file mode 100644 index f671cbb..0000000 --- a/src/unstable/README.md +++ /dev/null @@ -1 +0,0 @@ -This is the latest and in-development version of Picocrypt. It might be unstable (and might not even work), as it will have new fixes and features, so I recommend you not use any file in here for production.