2 gohpenc -- Go high-performance encryption utility
3 Copyright (C) 2017 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
35 "golang.org/x/crypto/blake2b"
36 "golang.org/x/crypto/chacha20poly1305"
44 func ToBase32(data []byte) string {
45 return strings.TrimRight(base32.StdEncoding.EncodeToString(data), "=")
48 func FromBase32(data string) ([]byte, error) {
49 padSize := len(data) % 8
52 pad := make([]byte, 0, padSize)
53 for i := 0; i < padSize; i++ {
54 pad = append(pad, '=')
58 return base32.StdEncoding.DecodeString(data)
61 type WorkerTask struct {
75 func (w *Worker) Thread(doDecrypt bool) {
77 nonce := make([]byte, chacha20poly1305.NonceSize)
82 aead, err := chacha20poly1305.New(task.key)
87 done, err = aead.Open(w.buf[:0], nonce, w.buf[LenSize:LenSize+task.n], w.buf[:LenSize])
92 binary.BigEndian.PutUint32(w.buf, uint32(task.n))
93 done = aead.Seal(w.buf[:LenSize], nonce, w.buf[LenSize:LenSize+task.n], w.buf[:LenSize])
103 doPSK = flag.Bool("psk", false, "Generate PSK")
104 key = flag.String("k", "", "Encryption key")
105 doDecrypt = flag.Bool("d", false, "Decrypt, instead of encrypt")
106 blockSize = flag.Int("b", 1<<10, "Blocksize, in KiB")
107 threads = flag.Int("c", runtime.NumCPU(), "Number of threads")
110 bs := *blockSize * 1 << 10
113 key := make([]byte, 32)
114 if _, err := rand.Read(key); err != nil {
117 fmt.Println(ToBase32(key))
122 panic("Invalid key size")
124 keyDecoded, err := FromBase32(*key)
128 tmpAEAD, err := chacha20poly1305.New(make([]byte, chacha20poly1305.KeySize))
132 keys, err := blake2b.NewXOF(blake2b.OutputLengthUnknown, keyDecoded)
137 var wg sync.WaitGroup
138 workers := make([]*Worker, 0, *threads)
139 for i := 0; i < *threads; i++ {
142 buf: make([]byte, LenSize+bs+tmpAEAD.Overhead()),
143 ready: make(chan struct{}),
144 task: make(chan WorkerTask),
145 done: make(chan []byte),
146 written: make(chan struct{}),
148 go w.Thread(*doDecrypt)
149 workers = append(workers, &w)
155 w = workers[i%len(workers)]
156 if _, err = os.Stdout.Write(<-w.done); err != nil {
159 w.written <- struct{}{}
164 stdin := bufio.NewReaderSize(os.Stdin, LenSize+bs)
166 if _, err = io.CopyN(keys, stdin, SaltSize); err != nil {
170 salt := make([]byte, SaltSize)
171 if _, err = rand.Read(salt); err != nil {
174 if _, err = keys.Write(salt); err != nil {
177 if _, err = os.Stdout.Write(salt); err != nil {
186 key := make([]byte, chacha20poly1305.KeySize)
187 _, err = io.ReadFull(keys, key)
191 w = workers[i%len(workers)]
194 _, err = io.ReadFull(stdin, w.buf[:LenSize])
201 n = int(binary.BigEndian.Uint32(w.buf[:LenSize]))
202 n, err = io.ReadFull(stdin, w.buf[LenSize:LenSize+n+tmpAEAD.Overhead()])
207 n, err = stdin.Read(w.buf[LenSize : LenSize+bs])
216 w.task <- WorkerTask{key, n}