forked from juju/utils
/
hash.go
76 lines (70 loc) · 2.21 KB
/
hash.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
// The hash package provides utilities that support use of the stdlib
// hash.Hash. Most notably is the Fingerprint type that wraps the
// checksum of a hash.
//
// Conversion between checksums and strings are facailitated through
// Fingerprint.
//
// Here are some hash-related recipes that bring it all together:
//
// * Extract the SHA384 hash while writing to elsewhere, then get the
// raw checksum:
//
// newHash, _ := hash.SHA384()
// h := newHash()
// hashingWriter := io.MultiWriter(writer, h)
// if err := writeAll(hashingWriter); err != nil { ... }
// fp := hash.NewValidFingerprint(h)
// checksum := fp.Bytes()
//
// * Extract the SHA384 hash while reading from elsewhere, then get the
// hex-encoded checksum to send over the wire:
//
// newHash, _ := hash.SHA384()
// h := newHash()
// hashingReader := io.TeeReader(reader, h)
// if err := processStream(hashingReader); err != nil { ... }
// fp := hash.NewValidFingerprint(h)
// hexSum := fp.Hex()
// req.Header.Set("Content-Sha384", hexSum)
//
// * Turn a checksum sent over the wire back into a fingerprint:
//
// _, validate := hash.SHA384()
// hexSum := req.Header.Get("Content-Sha384")
// var fp hash.Fingerprint
// if len(hexSum) != 0 {
// fp, err = hash.ParseHexFingerprint(hexSum, validate)
// ...
// }
// if fp.IsZero() {
// ...
// }
package hash
import (
"crypto/sha512"
"hash"
"github.com/juju/errors"
"github.com/juju/loggo"
)
var logger = loggo.GetLogger("utils.hash")
// SHA384 returns the newHash and validate functions for use
// with SHA384 hashes. SHA384 is used in several key places in Juju.
func SHA384() (newHash func() hash.Hash, validate func([]byte) error) {
const digestLenBytes = 384 / 8
validate = newSizeChecker(digestLenBytes)
return sha512.New384, validate
}
func newSizeChecker(size int) func([]byte) error {
return func(sum []byte) error {
if len(sum) < size {
return errors.NewNotValid(nil, "invalid fingerprint (too small)")
}
if len(sum) > size {
return errors.NewNotValid(nil, "invalid fingerprint (too big)")
}
return nil
}
}