2 gohpenc -- Go high-performance encryption utility
3 Copyright (C) 2017-2019 Sergey Matveev <stargrave@stargrave.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 // Go high-performance encryption utility
32 "golang.org/x/crypto/blake2b"
33 "golang.org/x/crypto/chacha20poly1305"
41 type WorkerTask struct {
55 func (w *Worker) Thread(doDecrypt bool) {
57 nonce := make([]byte, chacha20poly1305.NonceSize)
62 aead, err := chacha20poly1305.New(task.key)
67 done, err = aead.Open(w.buf[:0], nonce, w.buf[LenSize:LenSize+task.n], w.buf[:LenSize])
72 binary.BigEndian.PutUint32(w.buf, uint32(task.n))
73 done = aead.Seal(w.buf[:LenSize], nonce, w.buf[LenSize:LenSize+task.n], w.buf[:LenSize])
83 doPSK = flag.Bool("psk", false, "Generate PSK")
84 key = flag.String("k", "", "Encryption key")
85 doDecrypt = flag.Bool("d", false, "Decrypt, instead of encrypt")
86 blockSize = flag.Int("b", 1<<10, "Blocksize, in KiB")
87 threads = flag.Int("c", runtime.NumCPU(), "Number of threads")
90 bs := *blockSize * 1 << 10
93 key := make([]byte, 32)
94 if _, err := rand.Read(key); err != nil {
97 fmt.Println(ToBase32(key))
102 panic("Invalid key size")
104 keyDecoded, err := FromBase32(*key)
108 tmpAEAD, err := chacha20poly1305.New(make([]byte, chacha20poly1305.KeySize))
112 keys, err := blake2b.NewXOF(blake2b.OutputLengthUnknown, keyDecoded)
117 var wg sync.WaitGroup
118 workers := make([]*Worker, 0, *threads)
119 for i := 0; i < *threads; i++ {
122 buf: make([]byte, LenSize+bs+tmpAEAD.Overhead()),
123 ready: make(chan struct{}),
124 task: make(chan WorkerTask),
125 done: make(chan []byte),
126 written: make(chan struct{}),
128 go w.Thread(*doDecrypt)
129 workers = append(workers, &w)
135 w = workers[i%len(workers)]
136 if _, err = os.Stdout.Write(<-w.done); err != nil {
139 w.written <- struct{}{}
144 stdin := bufio.NewReaderSize(os.Stdin, LenSize+bs)
146 if _, err = io.CopyN(keys, stdin, SaltSize); err != nil {
150 salt := make([]byte, SaltSize)
151 if _, err = rand.Read(salt); err != nil {
154 if _, err = keys.Write(salt); err != nil {
157 if _, err = os.Stdout.Write(salt); err != nil {
166 key := make([]byte, chacha20poly1305.KeySize)
167 if _, err = io.ReadFull(keys, key); err != nil {
170 w = workers[i%len(workers)]
173 _, err = io.ReadFull(stdin, w.buf[:LenSize])
180 n = int(binary.BigEndian.Uint32(w.buf[:LenSize]))
181 if n, err = io.ReadFull(stdin, w.buf[LenSize:LenSize+n+tmpAEAD.Overhead()]); err != nil {
185 n, err = stdin.Read(w.buf[LenSize : LenSize+bs])
194 w.task <- WorkerTask{key, n}