Compare commits

...

7 Commits

Author SHA1 Message Date
Evan Su 5a5cc0ae6e
Update CLI README 2023-04-12 16:33:41 -04:00
Evan Su bb8663623f
Update CLI README 2023-04-11 22:10:24 -04:00
Evan Su d741adbcfc
Begin v1.32 2023-04-11 22:03:48 -04:00
Evan Su 198aa075d6
Add CLI, update donors 2023-04-11 22:01:47 -04:00
Evan Su 2de657299a
Update CLI README 2023-04-11 21:39:39 -04:00
Evan Su a89c2f9962
Add CLI 2023-04-11 21:36:02 -04:00
Evan Su 685ea33be9
Scan CLI source files 2023-04-11 21:35:25 -04:00
7 changed files with 278 additions and 5 deletions

View File

@ -5,6 +5,9 @@ on:
- "src/*.go"
- "src/go.mod"
- "src/go.sum"
- "cli/picocrypt/*.go"
- "cli/picocrypt/go.mod"
- "cli/picocrypt/go.sum"
pull_request:
branches: [ main ]
jobs:

View File

@ -1,3 +1,9 @@
# v1.32 (No ETA)
<ul>
<li>✓ Added a command-line interface</li>
<li>Use Debian 11 as the base for the AppImage instead of Debian 10</li>
</ul>
# v1.31 (Released 11/18/2022)
<ul>
<li>✓ Force software OpenGL rendering on macOS</li>

View File

@ -20,6 +20,9 @@ Picocrypt for macOS is very simple as well. Download Picocrypt <a href="https://
## Linux
To use Picocrypt on Linux, you can download the AppImage <a href="https://github.com/HACKERALERT/Picocrypt/releases/download/1.31/Picocrypt.AppImage">here</a>. While this AppImage should work on most systems, Linux is a mess when it comes to cross-distro and cross-release compatibility, so if the AppImage doesn't work, you can run Picocrypt through Wine or from source using the instructions in the `src/` directory.
## CLI
A command-line interface is available for Picocrypt <a href="/cli">here</a>. Keep in mind that the functionality is extremely limited and is not meant to replace the standard GUI app. Rather, it's best suited for environments where the GUI won't run or you need the ability to automate encryption workflows.
## Paranoid Pack
The Paranoid Pack is a compressed archive that contains executables for Windows, macOS, and Linux, including the source code and dependencies. As long as you have it stored in a place you can access, you'll be able to open it and use Picocrypt on any desktop operating system in case this repository mysteriously vanishes or the entire Internet burns down. Think of it as a seed vault for Picocrypt; as long as one person has the Paranoid Pack within reach, they can share it with the rest of the world and keep Picocrypt functional in case of catastrophic events. The best way to ensure Picocrypt is accessible many decades from now is to keep a Paranoid Pack in a safe place. Get your copy <a href="https://github.com/HACKERALERT/Picocrypt/releases/download/1.31/Paranoid.zip">here</a>.
@ -100,10 +103,6 @@ When I was actively developing Picocrypt, I accepted donations, but now that Pic
No, Picocrypt is considered feature-complete and won't be getting any new features. Unlike other tools which try to constantly add new features (which introduces new bugs and security holes), Picocrypt focuses on just a few core features but does each of them exceptionally well. Remember Picocrypt's ideology: small, simple, and secure.
**Is there a command-line interface?**
No, Picocrypt doesn't have a command-line interface because it's designed to appeal to the general public, most of which isn't very comfortable with a terminal. The UI is what makes Picocrypt powerful and unique, so adding a command-line interface wouldn't be of much benefit for most users.
**Will Android/iOS be supported?**
No, I don't plan on supporting Android or iOS because they are very different from traditional desktop operating systems and require different toolchains to develop apps for. Due to the nature of open-source software, however, a community-built version of Picocrypt for Android or iOS may appear in the future.
@ -144,8 +143,12 @@ A thank you from the bottom of my heart to the significant contributors on Open
<li>Cohen ($10)</li>
<li>EuA ($10)</li>
<li>geevade ($10)</li>
<li>Guest ($10)</li>
<li>Hilebrinest ($10)</li>
<li>gabu.gu ($10)</li>
<li>Boat ($10)</li>
</ul>
<!-- Last updated January 30, 2023 -->
<!-- Last updated April 11, 2023 -->
Also, a huge thanks to the following people who were the first to donate and support Picocrypt:
<ul>

16
cli/README.md Normal file
View File

@ -0,0 +1,16 @@
# CLI
Before you dive in, keep in mind that the CLI is limited in functionality and not meant to replace the GUI in any remote way. It only works with volumes that don't use any keyfiles or advanced features, and you will still need the GUI to do anything more than basic file encryption. You should only use the CLI when you are not able to run the GUI or need an automatable interface for encrypting and decrypting files.
# Installation
If you don't have Go installed, download it from <a href="https://go.dev/dl/">here</a> or install it from your package manager. Then, run the command below:
```bash
go install github.com/HACKERALERT/Picocrypt/cli/picocrypt@latest
```
You should now be able to run `picocrypt` in your terminal. If not, run `export PATH=$PATH:$(go env GOPATH)/bin` and try again.
# Usage
```
picocrypt -p password <file>
```
The CLI is designed to do one thing and one thing only: encrypt and decrypt a single file. Its goal isn't to be full-blown encryption tool, but to provide the basics of file encryption so that you can do the rest. This allows you to write custom scripts to encrypt your weekly backups, secure client files on a server, etc.

10
cli/picocrypt/go.mod Normal file
View File

@ -0,0 +1,10 @@
module github.com/HACKERALERT/Picocrypt/cli/picocrypt
go 1.17
require (
github.com/HACKERALERT/crypto v0.0.0-20220905152506-aa0dd62d8f67
github.com/HACKERALERT/infectious v0.0.0-20220905152109-2c37b99f37ff
)
require github.com/HACKERALERT/sys v0.0.0-20220905150735-46e319fb60c9 // indirect

6
cli/picocrypt/go.sum Normal file
View File

@ -0,0 +1,6 @@
github.com/HACKERALERT/crypto v0.0.0-20220905152506-aa0dd62d8f67 h1:4WfPIopYjvBjyDg0IET7mEj32kkihLmvFgwCOmldqK8=
github.com/HACKERALERT/crypto v0.0.0-20220905152506-aa0dd62d8f67/go.mod h1:qiHCxMDsCxX4QhXd3kDYWiNOR/DZQZ7nYO/f2OgWst0=
github.com/HACKERALERT/infectious v0.0.0-20220905152109-2c37b99f37ff h1:ertDhqhixxQJJPJIpn4wmSVs2fQ3tlSDNuiZ7jHCvEs=
github.com/HACKERALERT/infectious v0.0.0-20220905152109-2c37b99f37ff/go.mod h1:GwBVHbiXRUUciGfKWwm4GCL8FvMZBLHrQq23UXW/CU8=
github.com/HACKERALERT/sys v0.0.0-20220905150735-46e319fb60c9 h1:raqLJhvqDGk9L4dnJnO0tTV5Lyba2jhQcIHEle+o1dM=
github.com/HACKERALERT/sys v0.0.0-20220905150735-46e319fb60c9/go.mod h1:I4esFWbCYc37CXVb+3qJHJiU43NGkLf66kNV/NDnXcU=

229
cli/picocrypt/main.go Normal file
View File

@ -0,0 +1,229 @@
package main
import (
"bytes"
"crypto/rand"
"flag"
"fmt"
"os"
"strconv"
"strings"
"github.com/HACKERALERT/crypto/argon2"
"github.com/HACKERALERT/crypto/blake2b"
"github.com/HACKERALERT/crypto/chacha20"
"github.com/HACKERALERT/crypto/hkdf"
"github.com/HACKERALERT/crypto/sha3"
"github.com/HACKERALERT/infectious"
)
var MiB = 1 << 20
var GiB = 1 << 30
var rs5, _ = infectious.NewFEC(5, 15)
var rs16, _ = infectious.NewFEC(16, 48)
var rs24, _ = infectious.NewFEC(24, 72)
var rs32, _ = infectious.NewFEC(32, 96)
var rs64, _ = infectious.NewFEC(64, 192)
func work(filename string, password string) int {
var salt []byte
var hkdfSalt []byte
var nonce []byte
var keyHash []byte
var keyHashRef []byte
var authTag []byte
fin, err := os.Open(filename)
if err != nil {
fmt.Println("Couldn't open input file.")
return 1
}
defer fin.Close()
var fout *os.File
if strings.HasSuffix(filename, ".pcv") {
fout, err = os.Create(strings.TrimSuffix(filename, ".pcv"))
} else {
fout, err = os.Create(filename + ".pcv")
}
if err != nil {
fmt.Println("Couldn't create output file.")
return 1
}
defer fout.Close()
if !strings.HasSuffix(filename, ".pcv") {
salt = make([]byte, 16)
hkdfSalt = make([]byte, 32)
nonce = make([]byte, 24)
rand.Read(salt)
rand.Read(hkdfSalt)
rand.Read(nonce)
fout.Write(rsEncode(rs5, []byte("v1.32")))
fout.Write(rsEncode(rs5, []byte("00000")))
fout.Write(rsEncode(rs5, make([]byte, 5)))
fout.Write(rsEncode(rs16, salt))
fout.Write(rsEncode(rs32, hkdfSalt))
fout.Write(rsEncode(rs16, make([]byte, 16)))
fout.Write(rsEncode(rs24, nonce))
fout.Write(make([]byte, 480))
} else {
errs := make([]error, 7)
comments := make([]byte, 30)
fin.Read(comments)
comments, errs[0] = rsDecode(rs5, comments[15:])
length, _ := strconv.Atoi(string(comments))
fin.Read(make([]byte, length*3))
flags := make([]byte, 15)
fin.Read(flags)
flags, errs[1] = rsDecode(rs5, flags)
salt = make([]byte, 48)
fin.Read(salt)
salt, errs[2] = rsDecode(rs16, salt)
hkdfSalt = make([]byte, 96)
fin.Read(hkdfSalt)
hkdfSalt, errs[3] = rsDecode(rs32, hkdfSalt)
fin.Read(make([]byte, 48))
nonce = make([]byte, 72)
fin.Read(nonce)
nonce, errs[4] = rsDecode(rs24, nonce)
keyHashRef = make([]byte, 192)
fin.Read(keyHashRef)
keyHashRef, errs[5] = rsDecode(rs64, keyHashRef)
fin.Read(make([]byte, 96))
authTag = make([]byte, 192)
fin.Read(authTag)
authTag, errs[6] = rsDecode(rs64, authTag)
for _, err := range errs {
if err != nil {
fmt.Println("The header is corrupted.")
return 1
}
}
if flags[0]+flags[1]+flags[3] > 0 {
fmt.Println("Unsupported volume.")
return 1
}
}
key := argon2.IDKey([]byte(password), salt, 4, 1<<20, 4, 32)
tmp := sha3.New512()
tmp.Write(key)
keyHash = tmp.Sum(nil)
if strings.HasSuffix(filename, ".pcv") && !bytes.Equal(keyHash, keyHashRef) {
fmt.Println("Incorrect password.")
return 1
}
counter := 0
chacha, _ := chacha20.NewUnauthenticatedCipher(key, nonce)
subkey := make([]byte, 32)
hkdf := hkdf.New(sha3.New256, key, hkdfSalt, nil)
hkdf.Read(subkey)
mac, _ := blake2b.New512(subkey)
hkdf.Read(make([]byte, 32))
for {
src := make([]byte, MiB)
size, err := fin.Read(src)
if err != nil {
break
}
src = src[:size]
dst := make([]byte, len(src))
if !strings.HasSuffix(filename, ".pcv") {
chacha.XORKeyStream(dst, src)
mac.Write(dst)
} else {
mac.Write(src)
chacha.XORKeyStream(dst, src)
}
fout.Write(dst)
counter += MiB
if counter >= 60*GiB {
nonce = make([]byte, 24)
hkdf.Read(nonce)
chacha, _ = chacha20.NewUnauthenticatedCipher(key, nonce)
hkdf.Read(make([]byte, 16))
counter = 0
}
}
if !strings.HasSuffix(filename, ".pcv") {
fout.Seek(309, 0)
fout.Write(rsEncode(rs64, keyHash))
fout.Write(rsEncode(rs32, make([]byte, 32)))
fout.Write(rsEncode(rs64, mac.Sum(nil)))
} else {
if !bytes.Equal(mac.Sum(nil), authTag) {
fmt.Println("The file has been modified.")
return 1
}
}
fmt.Println("Operation successful.")
return 0
}
func rsEncode(rs *infectious.FEC, data []byte) []byte {
res := make([]byte, rs.Total())
rs.Encode(data, func(s infectious.Share) {
res[s.Number] = s.Data[0]
})
return res
}
func rsDecode(rs *infectious.FEC, data []byte) ([]byte, error) {
tmp := make([]infectious.Share, rs.Total())
for i := 0; i < rs.Total(); i++ {
tmp[i].Number = i
tmp[i].Data = []byte{data[i]}
}
res, err := rs.Decode(nil, tmp)
if err != nil {
return data[:rs.Total()/3], err
}
return res, nil
}
func main() {
flag.Usage = func() { fmt.Println("Usage: picocrypt -p password <file>") }
password := flag.String("p", "", "")
flag.Parse()
filename := flag.Arg(0)
if filename == "" || *password == "" || flag.Arg(1) != "" {
flag.Usage()
os.Exit(1)
}
if _, err := os.Stat(filename); err != nil {
fmt.Println("Input file not found.")
os.Exit(1)
}
if stat, _ := os.Stat(filename); stat.IsDir() {
fmt.Println("Directories are not supported.")
os.Exit(1)
}
if !strings.HasSuffix(filename, ".pcv") {
if _, err := os.Stat(filename + ".pcv"); err == nil {
fmt.Println("Output already exists.")
os.Exit(1)
}
} else {
if _, err := os.Stat(strings.TrimSuffix(filename, ".pcv")); err == nil {
fmt.Println("Output already exists.")
os.Exit(1)
}
}
if work(filename, *password) != 0 {
if !strings.HasSuffix(filename, ".pcv") {
os.Remove(filename + ".pcv")
} else {
os.Remove(strings.TrimSuffix(filename, ".pcv"))
}
os.Exit(1)
}
}