From b57e431b181a2a0e92b74b73264c419c1971f5f0 Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Tue, 14 Dec 2021 21:37:17 -0500 Subject: [PATCH 01/32] Add back CodeQL --- .github/workflows/codeql-analysis.yml | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..76f9261 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,30 @@ +name: "CodeQL" +on: + push: + paths: + - "src/Picocrypt.go" + 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 From 958220cf52e43650a0206d7a9c2c02ca5934fb86 Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Tue, 14 Dec 2021 21:39:44 -0500 Subject: [PATCH 02/32] Test workflow --- src/Picocrypt.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Picocrypt.go b/src/Picocrypt.go index 80d9089..153c985 100644 --- a/src/Picocrypt.go +++ b/src/Picocrypt.go @@ -2,7 +2,7 @@ package main /* -Picocrypt v1.21 +Picocrypt v1.21 Copyright (c) Evan Su (https://evansu.cc) Released under a GNU GPL v3 License https://github.com/HACKERALERT/Picocrypt From f960e09d9076587a9d37d50044fe8cef60ed3575 Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Tue, 14 Dec 2021 21:47:48 -0500 Subject: [PATCH 03/32] Test again --- src/Picocrypt.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Picocrypt.go b/src/Picocrypt.go index 153c985..8a88ffb 100644 --- a/src/Picocrypt.go +++ b/src/Picocrypt.go @@ -1,7 +1,7 @@ package main /* - + Picocrypt v1.21 Copyright (c) Evan Su (https://evansu.cc) Released under a GNU GPL v3 License From 5250f9de57442caf817cd39632233b3379fc26da Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Tue, 14 Dec 2021 22:37:18 -0500 Subject: [PATCH 04/32] Create SECURITY.md --- SECURITY.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 SECURITY.md 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. From 37c9da3f170e845d1460ef90f59c138b21216760 Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Tue, 14 Dec 2021 22:37:44 -0500 Subject: [PATCH 05/32] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 612bf70..728c1b1 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,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: +# v1.22 (ETA unknown for now) + + # v1.21 (Released 11/19/2021) -# v1.22 (A future release) +# v1.23 (A future release) Finally, thanks to these people for helping me out when needed: @@ -104,4 +105,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
  • From c3aa8edadba643384b2b63de009751e18c606b20 Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Thu, 16 Dec 2021 17:09:43 -0500 Subject: [PATCH 12/32] Update go modules --- src/go.mod | 23 ++++++++++------------- src/go.sum | 35 +++++++++++++++-------------------- 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/src/go.mod b/src/go.mod index 0043ece..ad1387d 100644 --- a/src/go.mod +++ b/src/go.mod @@ -3,21 +3,18 @@ module Picocrypt go 1.17 require ( - github.com/HACKERALERT/clipboard v0.1.5-0.20210716140604-61d96bf4fc94 - github.com/HACKERALERT/dialog v0.0.0-20210716143851-223edea1d840 - github.com/HACKERALERT/giu v0.5.7-0.20211216020632-65de69857557 - github.com/HACKERALERT/infectious v0.0.0-20211027225427-984efcfa77a9 - github.com/HACKERALERT/jibber_jabber v0.0.0-20210819210536-54a4d27b5376 - github.com/HACKERALERT/serpent v0.0.0-20210716182301-293b29869c66 - github.com/HACKERALERT/zxcvbn-go v0.0.0-20210927200100-f131a4666ad5 - golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 -) - -require ( + 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-20211215234401-c23e432f628b // indirect github.com/HACKERALERT/mainthread v0.0.0-20211027212305-2ec9e701cc14 // indirect - github.com/HACKERALERT/w32 v0.0.0-20210716142531-faa7189c4abf // indirect - golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 // indirect + github.com/HACKERALERT/serpent v0.0.0-20210716182301-293b29869c66 // 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-20211215165025-cf75a172585e // indirect + golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect ) diff --git a/src/go.sum b/src/go.sum index d189df0..a93318c 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,7 +1,7 @@ -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/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= @@ -10,25 +10,20 @@ github.com/HACKERALERT/glfw/v3.3/glfw v0.0.0-20211216001154-d0da149b3bef h1:MWA4 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-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/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/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/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -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/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +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= From b849b4e00d1c0f484c07b9e02f0aaf8aa7a8cde3 Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Thu, 16 Dec 2021 17:16:20 -0500 Subject: [PATCH 13/32] Also scan when updating go.mod and go.sum --- .github/workflows/codeql-analysis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 76f9261..8f0987f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -3,6 +3,8 @@ on: push: paths: - "src/Picocrypt.go" + - "src/go.mod" + - "src/go.sum" pull_request: branches: [ main ] jobs: From 1787376951a41b78fbb68edca561d56bdadbb63f Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Thu, 16 Dec 2021 17:19:28 -0500 Subject: [PATCH 14/32] Successfully removed fast mode and updated normal --- Changelog.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Changelog.md b/Changelog.md index 08b4f8d..0b6c500 100644 --- a/Changelog.md +++ b/Changelog.md @@ -16,9 +16,9 @@ # v1.22 (ETA unknown for now) From a704fc4efd747dfde485a302ed2cbc196cb7b88e Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Thu, 16 Dec 2021 17:20:01 -0500 Subject: [PATCH 15/32] Remove unfeasible new features --- Changelog.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/Changelog.md b/Changelog.md index 0b6c500..6bf271d 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,7 +1,5 @@ # Features Under Consideration From 9432aca8b32804aa7b96e0b90697982a04e7bcda Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Thu, 16 Dec 2021 20:57:44 -0500 Subject: [PATCH 16/32] Remove fast mode and update accordingly --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0344d4b..e693947 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

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

    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 algorithm 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

    @@ -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.
  • From 213ebd730a50bc0a74a51a3580b3f39345e7a05f Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Thu, 16 Dec 2021 21:06:46 -0500 Subject: [PATCH 17/32] Update description --- src/snapcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/snapcraft.yaml b/src/snapcraft.yaml index 8303e35..7ac0aea 100644 --- a/src/snapcraft.yaml +++ b/src/snapcraft.yaml @@ -1,6 +1,6 @@ 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. +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 From 9167817d22fa627b5977d86a9200bf2f6b859783 Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Thu, 16 Dec 2021 21:23:24 -0500 Subject: [PATCH 18/32] Improve wording --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e693947..71131e3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

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

    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 algorithm 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

    From f80a9f9236a465dd8eba60f9ac9a6326b45f832e Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Thu, 16 Dec 2021 21:36:53 -0500 Subject: [PATCH 19/32] Update to latest parameters and functions --- Internals.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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... From bb9cac7f578a95ec5cc96b470e814c65e4a42ad0 Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Mon, 20 Dec 2021 12:54:41 -0500 Subject: [PATCH 20/32] Testing CodeQL --- .github/workflows/codeql-analysis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8f0987f..6afcd21 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,6 +1,7 @@ name: "CodeQL" on: push: + branches: [ main ] paths: - "src/Picocrypt.go" - "src/go.mod" From f3a5634b0ad2cc47888febc8b485f4b3a59b5e2f Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Wed, 22 Dec 2021 11:30:11 -0500 Subject: [PATCH 21/32] Add ETA, move things around --- Changelog.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Changelog.md b/Changelog.md index 6bf271d..6416465 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,14 +10,14 @@
  • Remove EXIF data from keyfiles
  • Customizable Argon2 parameters
  • Finish adding tooltips
  • +
  • Improve Internals documentation (header format, etc.)
  • -# v1.22 (ETA unknown for now) +# v1.22 (ETA 1 week) # v1.21 (Released 11/19/2021) From bdca4f57c472aecb68cd52d164deb6015b26c08d Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Wed, 22 Dec 2021 11:30:41 -0500 Subject: [PATCH 22/32] Picocrypt is stable, so deleting unstable folder --- src/unstable/Picocrypt.go | 2214 ------------------------------------- src/unstable/README.md | 1 - 2 files changed, 2215 deletions(-) delete mode 100644 src/unstable/Picocrypt.go delete mode 100644 src/unstable/README.md 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. From e3fbf25adbc06c70d3eb7309e30320edcd2bd783 Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Wed, 22 Dec 2021 11:31:32 -0500 Subject: [PATCH 23/32] Update codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 6afcd21..8f0987f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,7 +1,6 @@ name: "CodeQL" on: push: - branches: [ main ] paths: - "src/Picocrypt.go" - "src/go.mod" From 8f183b6f95d6f1afebba633b0c3f68ea734de647 Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Wed, 22 Dec 2021 11:33:48 -0500 Subject: [PATCH 24/32] Bump to v1.22 --- src/snap/gui/picocrypt.desktop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 82c21b298611c626a1edfdbbd8226297467155d4 Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Wed, 22 Dec 2021 11:56:33 -0500 Subject: [PATCH 25/32] Finalize v1.22 --- src/Picocrypt.go | 101 +++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 60 deletions(-) diff --git a/src/Picocrypt.go b/src/Picocrypt.go index 8a88ffb..c47e770 100644 --- a/src/Picocrypt.go +++ b/src/Picocrypt.go @@ -1,8 +1,8 @@ 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() }), @@ -1047,23 +1042,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 +1240,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 +1294,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 +1310,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 +1369,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 +1425,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 +1509,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 +1568,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 +1739,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 +2014,6 @@ func resetUI() { split = false splitSize = "" splitSelected = 1 - fast = false deleteWhenDone = false paranoid = false compress = false From 64a032e63fd5e828d20fb4cb741422e5809cb1a1 Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Wed, 22 Dec 2021 12:03:38 -0500 Subject: [PATCH 26/32] Check file version --- src/Picocrypt.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Picocrypt.go b/src/Picocrypt.go index c47e770..2ab7563 100644 --- a/src/Picocrypt.go +++ b/src/Picocrypt.go @@ -1020,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) From 22da08c01b22b924a6f5b67b8ebb1c468d33c000 Mon Sep 17 00:00:00 2001 From: Evan Su <48808396+HACKERALERT@users.noreply.github.com> Date: Wed, 22 Dec 2021 12:04:08 -0500 Subject: [PATCH 27/32] Release v1.22 --- Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 6416465..a218d13 100644 --- a/Changelog.md +++ b/Changelog.md @@ -13,7 +13,7 @@
  • Improve Internals documentation (header format, etc.)
  • -# v1.22 (ETA 1 week) +# v1.22 (Released 12/22/2021)