sha1.mx raw
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Package sha1 implements the SHA-1 hash algorithm as defined in RFC 3174.
6 //
7 // SHA-1 is cryptographically broken and should not be used for secure
8 // applications.
9 package sha1
10
11 import (
12 "crypto"
13 "crypto/internal/boring"
14 "crypto/internal/fips140only"
15 "errors"
16 "hash"
17 "internal/byteorder"
18 )
19
20 func init() {
21 crypto.RegisterHash(crypto.SHA1, New)
22 }
23
24 // The size of a SHA-1 checksum in bytes.
25 const Size = 20
26
27 // The blocksize of SHA-1 in bytes.
28 const BlockSize = 64
29
30 const (
31 chunk = 64
32 init0 = 0x67452301
33 init1 = 0xEFCDAB89
34 init2 = 0x98BADCFE
35 init3 = 0x10325476
36 init4 = 0xC3D2E1F0
37 )
38
39 // digest represents the partial evaluation of a checksum.
40 type digest struct {
41 h [5]uint32
42 x [chunk]byte
43 nx int
44 len uint64
45 }
46
47 const (
48 magic = "sha\x01"
49 marshaledSize = len(magic) + 5*4 + chunk + 8
50 )
51
52 func (d *digest) MarshalBinary() ([]byte, error) {
53 return d.AppendBinary([]byte{:0:marshaledSize})
54 }
55
56 func (d *digest) AppendBinary(b []byte) ([]byte, error) {
57 b = append(b, magic...)
58 b = byteorder.BEAppendUint32(b, d.h[0])
59 b = byteorder.BEAppendUint32(b, d.h[1])
60 b = byteorder.BEAppendUint32(b, d.h[2])
61 b = byteorder.BEAppendUint32(b, d.h[3])
62 b = byteorder.BEAppendUint32(b, d.h[4])
63 b = append(b, d.x[:d.nx]...)
64 b = append(b, []byte{:len(d.x)-d.nx}...)
65 b = byteorder.BEAppendUint64(b, d.len)
66 return b, nil
67 }
68
69 func (d *digest) UnmarshalBinary(b []byte) error {
70 if len(b) < len(magic) || b[:len(magic)] != magic {
71 return errors.New("crypto/sha1: invalid hash state identifier")
72 }
73 if len(b) != marshaledSize {
74 return errors.New("crypto/sha1: invalid hash state size")
75 }
76 b = b[len(magic):]
77 b, d.h[0] = consumeUint32(b)
78 b, d.h[1] = consumeUint32(b)
79 b, d.h[2] = consumeUint32(b)
80 b, d.h[3] = consumeUint32(b)
81 b, d.h[4] = consumeUint32(b)
82 b = b[copy(d.x[:], b):]
83 b, d.len = consumeUint64(b)
84 d.nx = int(d.len % chunk)
85 return nil
86 }
87
88 func consumeUint64(b []byte) ([]byte, uint64) {
89 return b[8:], byteorder.BEUint64(b)
90 }
91
92 func consumeUint32(b []byte) ([]byte, uint32) {
93 return b[4:], byteorder.BEUint32(b)
94 }
95
96 func (d *digest) Clone() (hash.Cloner, error) {
97 r := *d
98 return &r, nil
99 }
100
101 func (d *digest) Reset() {
102 d.h[0] = init0
103 d.h[1] = init1
104 d.h[2] = init2
105 d.h[3] = init3
106 d.h[4] = init4
107 d.nx = 0
108 d.len = 0
109 }
110
111 // New returns a new [hash.Hash] computing the SHA1 checksum. The Hash
112 // also implements [encoding.BinaryMarshaler], [encoding.BinaryAppender] and
113 // [encoding.BinaryUnmarshaler] to marshal and unmarshal the internal
114 // state of the hash.
115 func New() hash.Hash {
116 if boring.Enabled {
117 return boring.NewSHA1()
118 }
119 d := &digest{}
120 d.Reset()
121 return d
122 }
123
124 func (d *digest) Size() int { return Size }
125
126 func (d *digest) BlockSize() int { return BlockSize }
127
128 func (d *digest) Write(p []byte) (nn int, err error) {
129 if fips140only.Enabled {
130 return 0, errors.New("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode")
131 }
132 boring.Unreachable()
133 nn = len(p)
134 d.len += uint64(nn)
135 if d.nx > 0 {
136 n := copy(d.x[d.nx:], p)
137 d.nx += n
138 if d.nx == chunk {
139 block(d, d.x[:])
140 d.nx = 0
141 }
142 p = p[n:]
143 }
144 if len(p) >= chunk {
145 n := len(p) &^ (chunk - 1)
146 block(d, p[:n])
147 p = p[n:]
148 }
149 if len(p) > 0 {
150 d.nx = copy(d.x[:], p)
151 }
152 return
153 }
154
155 func (d *digest) Sum(in []byte) []byte {
156 boring.Unreachable()
157 // Make a copy of d so that caller can keep writing and summing.
158 d0 := *d
159 hash := d0.checkSum()
160 return append(in, hash[:]...)
161 }
162
163 func (d *digest) checkSum() [Size]byte {
164 if fips140only.Enabled {
165 panic("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode")
166 }
167
168 len := d.len
169 // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
170 var tmp [64 + 8]byte // padding + length buffer
171 tmp[0] = 0x80
172 var t uint64
173 if len%64 < 56 {
174 t = 56 - len%64
175 } else {
176 t = 64 + 56 - len%64
177 }
178
179 // Length in bits.
180 len <<= 3
181 padlen := tmp[:t+8]
182 byteorder.BEPutUint64(padlen[t:], len)
183 d.Write(padlen)
184
185 if d.nx != 0 {
186 panic("d.nx != 0")
187 }
188
189 var digest [Size]byte
190
191 byteorder.BEPutUint32(digest[0:], d.h[0])
192 byteorder.BEPutUint32(digest[4:], d.h[1])
193 byteorder.BEPutUint32(digest[8:], d.h[2])
194 byteorder.BEPutUint32(digest[12:], d.h[3])
195 byteorder.BEPutUint32(digest[16:], d.h[4])
196
197 return digest
198 }
199
200 // ConstantTimeSum computes the same result of [Sum] but in constant time
201 func (d *digest) ConstantTimeSum(in []byte) []byte {
202 d0 := *d
203 hash := d0.constSum()
204 return append(in, hash[:]...)
205 }
206
207 func (d *digest) constSum() [Size]byte {
208 if fips140only.Enabled {
209 panic("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode")
210 }
211
212 var length [8]byte
213 l := d.len << 3
214 for i := uint(0); i < 8; i++ {
215 length[i] = byte(l >> (56 - 8*i))
216 }
217
218 nx := byte(d.nx)
219 t := nx - 56 // if nx < 56 then the MSB of t is one
220 mask1b := byte(int8(t) >> 7) // mask1b is 0xFF iff one block is enough
221
222 separator := byte(0x80) // gets reset to 0x00 once used
223 for i := byte(0); i < chunk; i++ {
224 mask := byte(int8(i-nx) >> 7) // 0x00 after the end of data
225
226 // if we reached the end of the data, replace with 0x80 or 0x00
227 d.x[i] = (^mask & separator) | (mask & d.x[i])
228
229 // zero the separator once used
230 separator &= mask
231
232 if i >= 56 {
233 // we might have to write the length here if all fit in one block
234 d.x[i] |= mask1b & length[i-56]
235 }
236 }
237
238 // compress, and only keep the digest if all fit in one block
239 block(d, d.x[:])
240
241 var digest [Size]byte
242 for i, s := range d.h {
243 digest[i*4] = mask1b & byte(s>>24)
244 digest[i*4+1] = mask1b & byte(s>>16)
245 digest[i*4+2] = mask1b & byte(s>>8)
246 digest[i*4+3] = mask1b & byte(s)
247 }
248
249 for i := byte(0); i < chunk; i++ {
250 // second block, it's always past the end of data, might start with 0x80
251 if i < 56 {
252 d.x[i] = separator
253 separator = 0
254 } else {
255 d.x[i] = length[i-56]
256 }
257 }
258
259 // compress, and only keep the digest if we actually needed the second block
260 block(d, d.x[:])
261
262 for i, s := range d.h {
263 digest[i*4] |= ^mask1b & byte(s>>24)
264 digest[i*4+1] |= ^mask1b & byte(s>>16)
265 digest[i*4+2] |= ^mask1b & byte(s>>8)
266 digest[i*4+3] |= ^mask1b & byte(s)
267 }
268
269 return digest
270 }
271
272 // Sum returns the SHA-1 checksum of the data.
273 func Sum(data []byte) [Size]byte {
274 if boring.Enabled {
275 return boring.SHA1(data)
276 }
277 if fips140only.Enabled {
278 panic("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode")
279 }
280 var d digest
281 d.Reset()
282 d.Write(data)
283 return d.checkSum()
284 }
285