1
2
3
4
5
6
7
8
9 package sha1
10
11 import (
12 "crypto"
13 "encoding/binary"
14 "errors"
15 "hash"
16 )
17
18 func init() {
19 crypto.RegisterHash(crypto.SHA1, New)
20 }
21
22
23 const Size = 20
24
25
26 const BlockSize = 64
27
28 const (
29 chunk = 64
30 init0 = 0x67452301
31 init1 = 0xEFCDAB89
32 init2 = 0x98BADCFE
33 init3 = 0x10325476
34 init4 = 0xC3D2E1F0
35 )
36
37
38 type digest struct {
39 h [5]uint32
40 x [chunk]byte
41 nx int
42 len uint64
43 }
44
45 const (
46 magic = "sha\x01"
47 marshaledSize = len(magic) + 5*4 + chunk + 8
48 )
49
50 func (d *digest) MarshalBinary() ([]byte, error) {
51 b := make([]byte, 0, marshaledSize)
52 b = append(b, magic...)
53 b = binary.BigEndian.AppendUint32(b, d.h[0])
54 b = binary.BigEndian.AppendUint32(b, d.h[1])
55 b = binary.BigEndian.AppendUint32(b, d.h[2])
56 b = binary.BigEndian.AppendUint32(b, d.h[3])
57 b = binary.BigEndian.AppendUint32(b, d.h[4])
58 b = append(b, d.x[:d.nx]...)
59 b = b[:len(b)+len(d.x)-d.nx]
60 b = binary.BigEndian.AppendUint64(b, d.len)
61 return b, nil
62 }
63
64 func (d *digest) UnmarshalBinary(b []byte) error {
65 if len(b) < len(magic) || string(b[:len(magic)]) != magic {
66 return errors.New("crypto/sha1: invalid hash state identifier")
67 }
68 if len(b) != marshaledSize {
69 return errors.New("crypto/sha1: invalid hash state size")
70 }
71 b = b[len(magic):]
72 b, d.h[0] = consumeUint32(b)
73 b, d.h[1] = consumeUint32(b)
74 b, d.h[2] = consumeUint32(b)
75 b, d.h[3] = consumeUint32(b)
76 b, d.h[4] = consumeUint32(b)
77 b = b[copy(d.x[:], b):]
78 b, d.len = consumeUint64(b)
79 d.nx = int(d.len % chunk)
80 return nil
81 }
82
83 func consumeUint64(b []byte) ([]byte, uint64) {
84 _ = b[7]
85 x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
86 uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
87 return b[8:], x
88 }
89
90 func consumeUint32(b []byte) ([]byte, uint32) {
91 _ = b[3]
92 x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
93 return b[4:], x
94 }
95
96 func (d *digest) Reset() {
97 d.h[0] = init0
98 d.h[1] = init1
99 d.h[2] = init2
100 d.h[3] = init3
101 d.h[4] = init4
102 d.nx = 0
103 d.len = 0
104 }
105
106
107
108
109 func New() hash.Hash {
110 if boringEnabled {
111 return boringNewSHA1()
112 }
113 d := new(digest)
114 d.Reset()
115 return d
116 }
117
118 func (d *digest) Size() int { return Size }
119
120 func (d *digest) BlockSize() int { return BlockSize }
121
122 func (d *digest) Write(p []byte) (nn int, err error) {
123 boringUnreachable()
124 nn = len(p)
125 d.len += uint64(nn)
126 if d.nx > 0 {
127 n := copy(d.x[d.nx:], p)
128 d.nx += n
129 if d.nx == chunk {
130 block(d, d.x[:])
131 d.nx = 0
132 }
133 p = p[n:]
134 }
135 if len(p) >= chunk {
136 n := len(p) &^ (chunk - 1)
137 block(d, p[:n])
138 p = p[n:]
139 }
140 if len(p) > 0 {
141 d.nx = copy(d.x[:], p)
142 }
143 return
144 }
145
146 func (d *digest) Sum(in []byte) []byte {
147 boringUnreachable()
148
149 d0 := *d
150 hash := d0.checkSum()
151 return append(in, hash[:]...)
152 }
153
154 func (d *digest) checkSum() [Size]byte {
155 len := d.len
156
157 var tmp [64 + 8]byte
158 tmp[0] = 0x80
159 var t uint64
160 if len%64 < 56 {
161 t = 56 - len%64
162 } else {
163 t = 64 + 56 - len%64
164 }
165
166
167 len <<= 3
168 padlen := tmp[:t+8]
169 binary.BigEndian.PutUint64(padlen[t:], len)
170 d.Write(padlen)
171
172 if d.nx != 0 {
173 panic("d.nx != 0")
174 }
175
176 var digest [Size]byte
177
178 binary.BigEndian.PutUint32(digest[0:], d.h[0])
179 binary.BigEndian.PutUint32(digest[4:], d.h[1])
180 binary.BigEndian.PutUint32(digest[8:], d.h[2])
181 binary.BigEndian.PutUint32(digest[12:], d.h[3])
182 binary.BigEndian.PutUint32(digest[16:], d.h[4])
183
184 return digest
185 }
186
187
188 func (d *digest) ConstantTimeSum(in []byte) []byte {
189 d0 := *d
190 hash := d0.constSum()
191 return append(in, hash[:]...)
192 }
193
194 func (d *digest) constSum() [Size]byte {
195 var length [8]byte
196 l := d.len << 3
197 for i := uint(0); i < 8; i++ {
198 length[i] = byte(l >> (56 - 8*i))
199 }
200
201 nx := byte(d.nx)
202 t := nx - 56
203 mask1b := byte(int8(t) >> 7)
204
205 separator := byte(0x80)
206 for i := byte(0); i < chunk; i++ {
207 mask := byte(int8(i-nx) >> 7)
208
209
210 d.x[i] = (^mask & separator) | (mask & d.x[i])
211
212
213 separator &= mask
214
215 if i >= 56 {
216
217 d.x[i] |= mask1b & length[i-56]
218 }
219 }
220
221
222 block(d, d.x[:])
223
224 var digest [Size]byte
225 for i, s := range d.h {
226 digest[i*4] = mask1b & byte(s>>24)
227 digest[i*4+1] = mask1b & byte(s>>16)
228 digest[i*4+2] = mask1b & byte(s>>8)
229 digest[i*4+3] = mask1b & byte(s)
230 }
231
232 for i := byte(0); i < chunk; i++ {
233
234 if i < 56 {
235 d.x[i] = separator
236 separator = 0
237 } else {
238 d.x[i] = length[i-56]
239 }
240 }
241
242
243 block(d, d.x[:])
244
245 for i, s := range d.h {
246 digest[i*4] |= ^mask1b & byte(s>>24)
247 digest[i*4+1] |= ^mask1b & byte(s>>16)
248 digest[i*4+2] |= ^mask1b & byte(s>>8)
249 digest[i*4+3] |= ^mask1b & byte(s)
250 }
251
252 return digest
253 }
254
255
256 func Sum(data []byte) [Size]byte {
257 if boringEnabled {
258 return boringSHA1(data)
259 }
260 var d digest
261 d.Reset()
262 d.Write(data)
263 return d.checkSum()
264 }
265
View as plain text