1
2
3
4
5 package cryptotest
6
7 import (
8 "bytes"
9 "hash"
10 "io"
11 "math/rand"
12 "testing"
13 "time"
14 )
15
16 type MakeHash func() hash.Hash
17
18
19
20 func TestHash(t *testing.T, mh MakeHash) {
21
22
23 t.Run("SumAppend", func(t *testing.T) {
24 h := mh()
25 rng := newRandReader(t)
26
27 emptyBuff := []byte("")
28 shortBuff := []byte("a")
29 longBuff := make([]byte, h.BlockSize()+1)
30 rng.Read(longBuff)
31
32
33 prefixes := [][]byte{nil, emptyBuff, shortBuff, longBuff}
34
35
36 for _, prefix := range prefixes {
37 h.Reset()
38
39 sum := getSum(t, h, prefix)
40
41
42 if !bytes.Equal(sum[:len(prefix)], prefix) {
43 t.Errorf("Sum alters passed buffer instead of appending; got %x, want %x", sum[:len(prefix)], prefix)
44 }
45
46
47 if expectedSum := getSum(t, h, nil); !bytes.Equal(sum[len(prefix):], expectedSum) {
48 t.Errorf("Sum behavior affected by data in the input buffer; got %x, want %x", sum[len(prefix):], expectedSum)
49 }
50
51
52 if got, want := len(sum)-len(prefix), h.Size(); got != want {
53 t.Errorf("Sum appends number of bytes != Size; got %v , want %v", got, want)
54 }
55 }
56 })
57
58
59 t.Run("WriteWithoutError", func(t *testing.T) {
60 h := mh()
61 rng := newRandReader(t)
62
63 emptySlice := []byte("")
64 shortSlice := []byte("a")
65 longSlice := make([]byte, h.BlockSize()+1)
66 rng.Read(longSlice)
67
68
69 slices := [][]byte{emptySlice, shortSlice, longSlice}
70
71 for _, slice := range slices {
72 writeToHash(t, h, slice)
73 }
74 })
75
76 t.Run("ResetState", func(t *testing.T) {
77 h := mh()
78 rng := newRandReader(t)
79
80 emptySum := getSum(t, h, nil)
81
82
83 writeEx := make([]byte, h.BlockSize())
84 rng.Read(writeEx)
85 writeToHash(t, h, writeEx)
86 h.Reset()
87 resetSum := getSum(t, h, nil)
88
89 if !bytes.Equal(emptySum, resetSum) {
90 t.Errorf("Reset hash yields different Sum than new hash; got %x, want %x", emptySum, resetSum)
91 }
92 })
93
94
95 t.Run("OutOfBoundsRead", func(t *testing.T) {
96 h := mh()
97 blockSize := h.BlockSize()
98 rng := newRandReader(t)
99
100 msg := make([]byte, blockSize)
101 rng.Read(msg)
102 writeToHash(t, h, msg)
103 expectedDigest := getSum(t, h, nil)
104
105 h.Reset()
106
107
108 buff := make([]byte, blockSize*3)
109 endOfPrefix, startOfSuffix := blockSize, blockSize*2
110
111 copy(buff[endOfPrefix:startOfSuffix], msg)
112 rng.Read(buff[:endOfPrefix])
113 rng.Read(buff[startOfSuffix:])
114
115 writeToHash(t, h, buff[endOfPrefix:startOfSuffix])
116 testDigest := getSum(t, h, nil)
117
118 if !bytes.Equal(testDigest, expectedDigest) {
119 t.Errorf("Write affected by data outside of input slice bounds; got %x, want %x", testDigest, expectedDigest)
120 }
121 })
122
123
124 t.Run("StatefulWrite", func(t *testing.T) {
125 h := mh()
126 rng := newRandReader(t)
127
128 prefix, suffix := make([]byte, h.BlockSize()), make([]byte, h.BlockSize())
129 rng.Read(prefix)
130 rng.Read(suffix)
131
132
133 writeToHash(t, h, prefix)
134 writeToHash(t, h, suffix)
135 serialSum := getSum(t, h, nil)
136
137 h.Reset()
138
139
140 writeToHash(t, h, append(prefix, suffix...))
141 compositeSum := getSum(t, h, nil)
142
143
144 if !bytes.Equal(compositeSum, serialSum) {
145 t.Errorf("two successive Write calls resulted in a different Sum than a single one; got %x, want %x", compositeSum, serialSum)
146 }
147 })
148 }
149
150
151 func writeToHash(t *testing.T, h hash.Hash, p []byte) {
152 t.Helper()
153
154 before := make([]byte, len(p))
155 copy(before, p)
156
157 n, err := h.Write(p)
158 if err != nil || n != len(p) {
159 t.Errorf("Write returned error; got (%v, %v), want (nil, %v)", err, n, len(p))
160 }
161
162 if !bytes.Equal(p, before) {
163 t.Errorf("Write modified input slice; got %x, want %x", p, before)
164 }
165 }
166
167
168 func getSum(t *testing.T, h hash.Hash, buff []byte) []byte {
169 t.Helper()
170
171 testBuff := make([]byte, len(buff))
172 copy(testBuff, buff)
173
174 sum := h.Sum(buff)
175 testSum := h.Sum(testBuff)
176
177
178 if !bytes.Equal(sum, testSum) {
179 t.Errorf("successive calls to Sum yield different results; got %x, want %x", sum, testSum)
180 }
181
182 return sum
183 }
184
185 func newRandReader(t *testing.T) io.Reader {
186 seed := time.Now().UnixNano()
187 t.Logf("Deterministic RNG seed: 0x%x", seed)
188 return rand.New(rand.NewSource(seed))
189 }
190
View as plain text