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 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
// Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package hash
import (
"encoding/base64"
"encoding/hex"
"hash"
"io"
"github.com/juju/errors"
)
// Fingerprint represents the checksum for some data.
type Fingerprint struct {
sum []byte
}
// NewFingerprint returns wraps the provided raw hash sum. This function
// roundtrips with Fingerprint.Bytes().
func NewFingerprint(sum []byte, validate func([]byte) error) (Fingerprint, error) {
if validate == nil {
return Fingerprint{}, errors.New("missing validate func")
}
if err := validate(sum); err != nil {
return Fingerprint{}, errors.Trace(err)
}
return newFingerprint(sum), nil
}
// NewValidFingerprint returns a Fingerprint corresponding
// to the current of the provided hash.
func NewValidFingerprint(hash hash.Hash) Fingerprint {
sum := hash.Sum(nil)
return newFingerprint(sum)
}
func newFingerprint(sum []byte) Fingerprint {
return Fingerprint{
sum: append([]byte{}, sum...), // Use an isolated copy.
}
}
// GenerateFingerprint returns the fingerprint for the provided data.
func GenerateFingerprint(reader io.Reader, newHash func() hash.Hash) (Fingerprint, error) {
var fp Fingerprint
if reader == nil {
return fp, errors.New("missing reader")
}
if newHash == nil {
return fp, errors.New("missing new hash func")
}
hash := newHash()
if _, err := io.Copy(hash, reader); err != nil {
return fp, errors.Trace(err)
}
fp.sum = hash.Sum(nil)
return fp, nil
}
// ParseHexFingerprint returns wraps the provided raw fingerprint string.
// This function roundtrips with Fingerprint.Hex().
func ParseHexFingerprint(hexSum string, validate func([]byte) error) (Fingerprint, error) {
if validate == nil {
return Fingerprint{}, errors.New("missing validate func")
}
sum, err := hex.DecodeString(hexSum)
if err != nil {
return Fingerprint{}, errors.Trace(err)
}
fp, err := NewFingerprint(sum, validate)
if err != nil {
return Fingerprint{}, errors.Trace(err)
}
return fp, nil
}
// ParseBase64Fingerprint returns wraps the provided raw fingerprint string.
// This function roundtrips with Fingerprint.Base64().
func ParseBase64Fingerprint(b64Sum string, validate func([]byte) error) (Fingerprint, error) {
if validate == nil {
return Fingerprint{}, errors.New("missing validate func")
}
sum, err := base64.StdEncoding.DecodeString(b64Sum)
if err != nil {
return Fingerprint{}, errors.Trace(err)
}
fp, err := NewFingerprint(sum, validate)
if err != nil {
return Fingerprint{}, errors.Trace(err)
}
return fp, nil
}
// String implements fmt.Stringer.
func (fp Fingerprint) String() string {
return fp.Hex()
}
// Hex returns the hex string representation of the fingerprint.
func (fp Fingerprint) Hex() string {
return hex.EncodeToString(fp.sum)
}
// Base64 returns the base64 encoded fingerprint.
func (fp Fingerprint) Base64() string {
return base64.StdEncoding.EncodeToString(fp.sum)
}
// Bytes returns the raw (sum) bytes of the fingerprint.
func (fp Fingerprint) Bytes() []byte {
return append([]byte{}, fp.sum...)
}
// IsZero returns whether or not the fingerprint is the zero value.
func (fp Fingerprint) IsZero() bool {
return len(fp.sum) == 0
}
// Validate returns an error if the fingerprint is invalid.
func (fp Fingerprint) Validate() error {
if fp.IsZero() {
return errors.NotValidf("zero-value fingerprint")
}
return nil
}
|