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, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 // Go high-performance encryption utility
33 "golang.org/x/crypto/blake2b"
34 "golang.org/x/crypto/chacha20poly1305"
42 type WorkerTask struct {
56 func (w *Worker) Thread(doDecrypt bool) {
58 nonce := make([]byte, chacha20poly1305.NonceSize)
63 aead, err := chacha20poly1305.New(task.key)
68 done, err = aead.Open(w.buf[:0], nonce, w.buf[LenSize:LenSize+task.n], w.buf[:LenSize])
73 binary.BigEndian.PutUint32(w.buf, uint32(task.n))
74 done = aead.Seal(w.buf[:LenSize], nonce, w.buf[LenSize:LenSize+task.n], w.buf[:LenSize])
84 doPSK = flag.Bool("psk", false, "Generate PSK")
85 key = flag.String("k", "", "Encryption key")
86 doDecrypt = flag.Bool("d", false, "Decrypt, instead of encrypt")
87 blockSize = flag.Int("b", 1<<10, "Blocksize, in KiB")
88 threads = flag.Int("c", runtime.NumCPU(), "Number of threads")
91 bs := *blockSize * 1 << 10
94 key := make([]byte, 32)
95 if _, err := rand.Read(key); err != nil {
98 fmt.Println(ToBase32(key))
103 panic("Invalid key size")
105 keyDecoded, err := FromBase32(*key)
109 tmpAEAD, err := chacha20poly1305.New(make([]byte, chacha20poly1305.KeySize))
113 keys, err := blake2b.NewXOF(blake2b.OutputLengthUnknown, keyDecoded)
118 var wg sync.WaitGroup
119 workers := make([]*Worker, 0, *threads)
120 for i := 0; i < *threads; i++ {
123 buf: make([]byte, LenSize+bs+tmpAEAD.Overhead()),
124 ready: make(chan struct{}),
125 task: make(chan WorkerTask),
126 done: make(chan []byte),
127 written: make(chan struct{}),
129 go w.Thread(*doDecrypt)
130 workers = append(workers, &w)
136 w = workers[i%len(workers)]
137 if _, err = os.Stdout.Write(<-w.done); err != nil {
140 w.written <- struct{}{}
145 stdin := bufio.NewReaderSize(os.Stdin, LenSize+bs)
147 if _, err = io.CopyN(keys, stdin, SaltSize); err != nil {
151 salt := make([]byte, SaltSize)
152 if _, err = rand.Read(salt); err != nil {
155 if _, err = keys.Write(salt); err != nil {
158 if _, err = os.Stdout.Write(salt); err != nil {
167 key := make([]byte, chacha20poly1305.KeySize)
168 if _, err = io.ReadFull(keys, key); err != nil {
171 w = workers[i%len(workers)]
174 _, err = io.ReadFull(stdin, w.buf[:LenSize])
181 n = int(binary.BigEndian.Uint32(w.buf[:LenSize]))
182 if n, err = io.ReadFull(stdin, w.buf[LenSize:LenSize+n+tmpAEAD.Overhead()]); err != nil {
186 n, err = stdin.Read(w.buf[LenSize : LenSize+bs])
195 w.task <- WorkerTask{key, n}