-
Notifications
You must be signed in to change notification settings - Fork 8
/
hash.go
148 lines (130 loc) · 3.82 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
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
* Copyright (C) 2020-2022 Arm Limited or its affiliates and Contributors. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package hashing
import (
"context"
"crypto/md5" //nolint:gosec
"crypto/sha1" //nolint:gosec
"crypto/sha256"
"encoding/hex"
"fmt"
"hash"
"io"
"math"
"strings"
"github.com/OneOfOne/xxhash"
"github.com/spaolacci/murmur3"
"golang.org/x/crypto/blake2b"
"github.com/ARM-software/golang-utils/utils/commonerrors"
"github.com/ARM-software/golang-utils/utils/reflection"
"github.com/ARM-software/golang-utils/utils/safeio"
strings2 "github.com/ARM-software/golang-utils/utils/strings"
)
const (
HashMd5 = "MD5"
HashSha256 = "SHA256"
HashSha1 = "SHA1"
HashMurmur = "Murmur"
HashXXHash = "xxhash" // https://github.com/OneOfOne/xxhash
HashBlake2256 = "blake2b256" // https://www.blake2.net/
)
type hashingAlgo struct {
Hash hash.Hash
Type string
}
func (h *hashingAlgo) CalculateWithContext(ctx context.Context, r io.Reader) (hashN string, err error) {
if r == nil {
err = commonerrors.ErrUndefined
return
}
_, err = safeio.CopyDataWithContext(ctx, r, h.Hash)
if err != nil {
return
}
hashN = hex.EncodeToString(h.Hash.Sum(nil))
h.Hash.Reset()
return
}
func (h *hashingAlgo) Calculate(r io.Reader) (string, error) {
return h.CalculateWithContext(context.Background(), r)
}
func (h *hashingAlgo) GetType() string {
return h.Type
}
// NewBespokeHashingAlgorithm defines a bespoke hashing algorithm
func NewBespokeHashingAlgorithm(algorithm hash.Hash) (IHash, error) {
return newHashingAlgorithm("bespoke", algorithm)
}
func newHashingAlgorithm(htype string, algorithm hash.Hash) (IHash, error) {
return &hashingAlgo{
Hash: algorithm,
Type: htype,
}, nil
}
func NewHashingAlgorithm(htype string) (IHash, error) {
var hash hash.Hash
var err error
switch htype {
case HashMd5:
hash = md5.New() //nolint:gosec
case HashSha1:
hash = sha1.New() //nolint:gosec
case HashSha256:
hash = sha256.New()
case HashMurmur:
hash = murmur3.New64()
case HashXXHash:
hash = xxhash.New64()
case HashBlake2256:
hash, err = blake2b.New256(nil)
}
if err != nil {
return nil, fmt.Errorf("%w: failed loading the hashing algorithm: %v", commonerrors.ErrUnexpected, err.Error())
}
if hash == nil {
return nil, fmt.Errorf("%w: could not find the corresponding hashing algorithm", commonerrors.ErrNotFound)
}
return newHashingAlgorithm(htype, hash)
}
func CalculateMD5Hash(text string) string {
return CalculateHash(text, HashMd5)
}
// CalculateStringHash returns the hash of some text using a particular hashing algorithm
func CalculateStringHash(hashingAlgo IHash, text string) string {
if hashingAlgo == nil {
return ""
}
hash, err := hashingAlgo.Calculate(strings.NewReader(text))
if err != nil {
return ""
}
return hash
}
// CalculateHash calculates the hash of some text using the requested htype hashing algorithm.
func CalculateHash(text, htype string) string {
hashing, err := NewHashingAlgorithm(htype)
if err != nil {
return ""
}
return CalculateStringHash(hashing, text)
}
// HasLikelyHexHashStringEntropy states whether a string has an entropy which may entail it is a hexadecimal hash
// This is based on the work done by `detect-secrets` https://github.com/Yelp/detect-secrets/blob/2fc0e31f067af98d97ad0f507dac032c9506f667/detect_secrets/plugins/high_entropy_strings.py#L150
func HasLikelyHexHashStringEntropy(str string) bool {
entropy := strings2.CalculateStringShannonEntropy(str)
entropy -= 1.2 / math.Log2(float64(len(str)))
return entropy > 3.0
}
// IsLikelyHexHashString determines whether the string is likely to be a hexadecimal hash or not.
func IsLikelyHexHashString(str string) bool {
if reflection.IsEmpty(str) {
return false
}
_, err := hex.DecodeString(str)
if err != nil {
return false
}
return HasLikelyHexHashStringEntropy(str)
}