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 sha256 implements the SHA224 and SHA256 hash algorithms as defined
6// in FIPS 180-4.
7package sha256
8
9import (
10	"crypto"
11	"encoding/binary"
12	"errors"
13	"hash"
14)
15
16func init() {
17	crypto.RegisterHash(crypto.SHA224, New224)
18	crypto.RegisterHash(crypto.SHA256, New)
19}
20
21// The size of a SHA256 checksum in bytes.
22const Size = 32
23
24// The size of a SHA224 checksum in bytes.
25const Size224 = 28
26
27// The blocksize of SHA256 and SHA224 in bytes.
28const BlockSize = 64
29
30const (
31	chunk     = 64
32	init0     = 0x6A09E667
33	init1     = 0xBB67AE85
34	init2     = 0x3C6EF372
35	init3     = 0xA54FF53A
36	init4     = 0x510E527F
37	init5     = 0x9B05688C
38	init6     = 0x1F83D9AB
39	init7     = 0x5BE0CD19
40	init0_224 = 0xC1059ED8
41	init1_224 = 0x367CD507
42	init2_224 = 0x3070DD17
43	init3_224 = 0xF70E5939
44	init4_224 = 0xFFC00B31
45	init5_224 = 0x68581511
46	init6_224 = 0x64F98FA7
47	init7_224 = 0xBEFA4FA4
48)
49
50// digest represents the partial evaluation of a checksum.
51type digest struct {
52	h     [8]uint32
53	x     [chunk]byte
54	nx    int
55	len   uint64
56	is224 bool // mark if this digest is SHA-224
57}
58
59const (
60	magic224      = "sha\x02"
61	magic256      = "sha\x03"
62	marshaledSize = len(magic256) + 8*4 + chunk + 8
63)
64
65func (d *digest) MarshalBinary() ([]byte, error) {
66	b := make([]byte, 0, marshaledSize)
67	if d.is224 {
68		b = append(b, magic224...)
69	} else {
70		b = append(b, magic256...)
71	}
72	b = appendUint32(b, d.h[0])
73	b = appendUint32(b, d.h[1])
74	b = appendUint32(b, d.h[2])
75	b = appendUint32(b, d.h[3])
76	b = appendUint32(b, d.h[4])
77	b = appendUint32(b, d.h[5])
78	b = appendUint32(b, d.h[6])
79	b = appendUint32(b, d.h[7])
80	b = append(b, d.x[:d.nx]...)
81	b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
82	b = appendUint64(b, d.len)
83	return b, nil
84}
85
86func (d *digest) UnmarshalBinary(b []byte) error {
87	if len(b) < len(magic224) || (d.is224 && string(b[:len(magic224)]) != magic224) || (!d.is224 && string(b[:len(magic256)]) != magic256) {
88		return errors.New("crypto/sha256: invalid hash state identifier")
89	}
90	if len(b) != marshaledSize {
91		return errors.New("crypto/sha256: invalid hash state size")
92	}
93	b = b[len(magic224):]
94	b, d.h[0] = consumeUint32(b)
95	b, d.h[1] = consumeUint32(b)
96	b, d.h[2] = consumeUint32(b)
97	b, d.h[3] = consumeUint32(b)
98	b, d.h[4] = consumeUint32(b)
99	b, d.h[5] = consumeUint32(b)
100	b, d.h[6] = consumeUint32(b)
101	b, d.h[7] = consumeUint32(b)
102	b = b[copy(d.x[:], b):]
103	b, d.len = consumeUint64(b)
104	d.nx = int(d.len % chunk)
105	return nil
106}
107
108func appendUint64(b []byte, x uint64) []byte {
109	var a [8]byte
110	binary.BigEndian.PutUint64(a[:], x)
111	return append(b, a[:]...)
112}
113
114func appendUint32(b []byte, x uint32) []byte {
115	var a [4]byte
116	binary.BigEndian.PutUint32(a[:], x)
117	return append(b, a[:]...)
118}
119
120func consumeUint64(b []byte) ([]byte, uint64) {
121	_ = b[7]
122	x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
123		uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
124	return b[8:], x
125}
126
127func consumeUint32(b []byte) ([]byte, uint32) {
128	_ = b[3]
129	x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
130	return b[4:], x
131}
132
133func (d *digest) Reset() {
134	if !d.is224 {
135		d.h[0] = init0
136		d.h[1] = init1
137		d.h[2] = init2
138		d.h[3] = init3
139		d.h[4] = init4
140		d.h[5] = init5
141		d.h[6] = init6
142		d.h[7] = init7
143	} else {
144		d.h[0] = init0_224
145		d.h[1] = init1_224
146		d.h[2] = init2_224
147		d.h[3] = init3_224
148		d.h[4] = init4_224
149		d.h[5] = init5_224
150		d.h[6] = init6_224
151		d.h[7] = init7_224
152	}
153	d.nx = 0
154	d.len = 0
155}
156
157// New returns a new hash.Hash computing the SHA256 checksum. The Hash
158// also implements encoding.BinaryMarshaler and
159// encoding.BinaryUnmarshaler to marshal and unmarshal the internal
160// state of the hash.
161func New() hash.Hash {
162	d := new(digest)
163	d.Reset()
164	return d
165}
166
167// New224 returns a new hash.Hash computing the SHA224 checksum.
168func New224() hash.Hash {
169	d := new(digest)
170	d.is224 = true
171	d.Reset()
172	return d
173}
174
175func (d *digest) Size() int {
176	if !d.is224 {
177		return Size
178	}
179	return Size224
180}
181
182func (d *digest) BlockSize() int { return BlockSize }
183
184func (d *digest) Write(p []byte) (nn int, err error) {
185	nn = len(p)
186	d.len += uint64(nn)
187	if d.nx > 0 {
188		n := copy(d.x[d.nx:], p)
189		d.nx += n
190		if d.nx == chunk {
191			block(d, d.x[:])
192			d.nx = 0
193		}
194		p = p[n:]
195	}
196	if len(p) >= chunk {
197		n := len(p) &^ (chunk - 1)
198		block(d, p[:n])
199		p = p[n:]
200	}
201	if len(p) > 0 {
202		d.nx = copy(d.x[:], p)
203	}
204	return
205}
206
207func (d *digest) Sum(in []byte) []byte {
208	// Make a copy of d so that caller can keep writing and summing.
209	d0 := *d
210	hash := d0.checkSum()
211	if d0.is224 {
212		return append(in, hash[:Size224]...)
213	}
214	return append(in, hash[:]...)
215}
216
217func (d *digest) checkSum() [Size]byte {
218	len := d.len
219	// Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
220	var tmp [64]byte
221	tmp[0] = 0x80
222	if len%64 < 56 {
223		d.Write(tmp[0 : 56-len%64])
224	} else {
225		d.Write(tmp[0 : 64+56-len%64])
226	}
227
228	// Length in bits.
229	len <<= 3
230	binary.BigEndian.PutUint64(tmp[:], len)
231	d.Write(tmp[0:8])
232
233	if d.nx != 0 {
234		panic("d.nx != 0")
235	}
236
237	var digest [Size]byte
238
239	binary.BigEndian.PutUint32(digest[0:], d.h[0])
240	binary.BigEndian.PutUint32(digest[4:], d.h[1])
241	binary.BigEndian.PutUint32(digest[8:], d.h[2])
242	binary.BigEndian.PutUint32(digest[12:], d.h[3])
243	binary.BigEndian.PutUint32(digest[16:], d.h[4])
244	binary.BigEndian.PutUint32(digest[20:], d.h[5])
245	binary.BigEndian.PutUint32(digest[24:], d.h[6])
246	if !d.is224 {
247		binary.BigEndian.PutUint32(digest[28:], d.h[7])
248	}
249
250	return digest
251}
252
253// Sum256 returns the SHA256 checksum of the data.
254func Sum256(data []byte) [Size]byte {
255	var d digest
256	d.Reset()
257	d.Write(data)
258	return d.checkSum()
259}
260
261// Sum224 returns the SHA224 checksum of the data.
262func Sum224(data []byte) (sum224 [Size224]byte) {
263	var d digest
264	d.is224 = true
265	d.Reset()
266	d.Write(data)
267	sum := d.checkSum()
268	copy(sum224[:], sum[:Size224])
269	return
270}
271