]> Sergey Matveev's repositories - meta4ra.git/blob - hasher.go
OpenSSH signatures inclusion support
[meta4ra.git] / hasher.go
1 package meta4ra
2
3 import (
4         "bytes"
5         "io"
6         "log"
7         "os/exec"
8         "strings"
9         "sync"
10 )
11
12 // Sorted by preference order.
13 var HashesDefault = []string{
14         "blake3-256:b3sum",
15         "skein-512:skein512",
16         "skein-256:skein256",
17         "shake128:goshake128",
18         "shake256:goshake256",
19         "sha-512:sha512",
20         "sha-256:sha256",
21         "streebog-256:streebog256sum",
22         "streebog-512:streebog512sum",
23 }
24
25 type Hasher struct {
26         Names []string
27         Cmds  []*exec.Cmd
28         Ins   []io.WriteCloser
29         Outs  []io.ReadCloser
30         wg    sync.WaitGroup
31 }
32
33 func NewHasher(hashes string) *Hasher {
34         h := Hasher{}
35         for _, hc := range strings.Split(hashes, ",") {
36                 cols := strings.SplitN(hc, ":", 2)
37                 name, cmdline := cols[0], cols[1]
38                 cmd := exec.Command(cmdline)
39                 in, err := cmd.StdinPipe()
40                 if err != nil {
41                         log.Fatalln(err)
42                 }
43                 out, err := cmd.StdoutPipe()
44                 if err != nil {
45                         log.Fatalln(err)
46                 }
47                 h.Names = append(h.Names, name)
48                 h.Ins = append(h.Ins, in)
49                 h.Outs = append(h.Outs, out)
50                 h.Cmds = append(h.Cmds, cmd)
51         }
52         return &h
53 }
54
55 func (h *Hasher) Start() {
56         for _, cmd := range h.Cmds {
57                 if err := cmd.Start(); err != nil {
58                         log.Fatalln(err)
59                 }
60         }
61 }
62
63 func (h *Hasher) Write(p []byte) (n int, err error) {
64         h.wg.Add(len(h.Names))
65         for _, in := range h.Ins {
66                 go func(in io.WriteCloser) {
67                         if _, err := io.Copy(in, bytes.NewReader(p)); err != nil {
68                                 log.Fatalln(err)
69                         }
70                         h.wg.Done()
71                 }(in)
72         }
73         h.wg.Wait()
74         return len(p), nil
75 }
76
77 func (h *Hasher) Sums() []Hash {
78         sums := make([]Hash, 0, len(h.Names))
79         for i, name := range h.Names {
80                 if err := h.Ins[i].Close(); err != nil {
81                         log.Fatalln(err)
82                 }
83                 dgst, err := io.ReadAll(h.Outs[i])
84                 if err != nil {
85                         log.Fatalln(err)
86                 }
87                 sums = append(sums, Hash{Type: name, Hash: string(dgst[:len(dgst)-1])})
88                 if err = h.Cmds[i].Wait(); err != nil {
89                         log.Fatalln(err)
90                 }
91         }
92         return sums
93 }