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 sha512 implements the SHA-384, SHA-512, SHA-512/224, and SHA-512/256
6// hash algorithms as defined in FIPS 180-4.
7package sha512
8
9import (
10	"crypto"
11	"hash"
12)
13
14func init() {
15	crypto.RegisterHash(crypto.SHA384, New384)
16	crypto.RegisterHash(crypto.SHA512, New)
17	crypto.RegisterHash(crypto.SHA512_224, New512_224)
18	crypto.RegisterHash(crypto.SHA512_256, New512_256)
19}
20
21const (
22	// Size is the size, in bytes, of a SHA-512 checksum.
23	Size = 64
24
25	// Size224 is the size, in bytes, of a SHA-512/224 checksum.
26	Size224 = 28
27
28	// Size256 is the size, in bytes, of a SHA-512/256 checksum.
29	Size256 = 32
30
31	// Size384 is the size, in bytes, of a SHA-384 checksum.
32	Size384 = 48
33
34	// BlockSize is the block size, in bytes, of the SHA-512/224,
35	// SHA-512/256, SHA-384 and SHA-512 hash functions.
36	BlockSize = 128
37)
38
39const (
40	chunk     = 128
41	init0     = 0x6a09e667f3bcc908
42	init1     = 0xbb67ae8584caa73b
43	init2     = 0x3c6ef372fe94f82b
44	init3     = 0xa54ff53a5f1d36f1
45	init4     = 0x510e527fade682d1
46	init5     = 0x9b05688c2b3e6c1f
47	init6     = 0x1f83d9abfb41bd6b
48	init7     = 0x5be0cd19137e2179
49	init0_224 = 0x8c3d37c819544da2
50	init1_224 = 0x73e1996689dcd4d6
51	init2_224 = 0x1dfab7ae32ff9c82
52	init3_224 = 0x679dd514582f9fcf
53	init4_224 = 0x0f6d2b697bd44da8
54	init5_224 = 0x77e36f7304c48942
55	init6_224 = 0x3f9d85a86a1d36c8
56	init7_224 = 0x1112e6ad91d692a1
57	init0_256 = 0x22312194fc2bf72c
58	init1_256 = 0x9f555fa3c84c64c2
59	init2_256 = 0x2393b86b6f53b151
60	init3_256 = 0x963877195940eabd
61	init4_256 = 0x96283ee2a88effe3
62	init5_256 = 0xbe5e1e2553863992
63	init6_256 = 0x2b0199fc2c85b8aa
64	init7_256 = 0x0eb72ddc81c52ca2
65	init0_384 = 0xcbbb9d5dc1059ed8
66	init1_384 = 0x629a292a367cd507
67	init2_384 = 0x9159015a3070dd17
68	init3_384 = 0x152fecd8f70e5939
69	init4_384 = 0x67332667ffc00b31
70	init5_384 = 0x8eb44a8768581511
71	init6_384 = 0xdb0c2e0d64f98fa7
72	init7_384 = 0x47b5481dbefa4fa4
73)
74
75// digest represents the partial evaluation of a checksum.
76type digest struct {
77	h        [8]uint64
78	x        [chunk]byte
79	nx       int
80	len      uint64
81	function crypto.Hash
82}
83
84func (d *digest) Reset() {
85	switch d.function {
86	case crypto.SHA384:
87		d.h[0] = init0_384
88		d.h[1] = init1_384
89		d.h[2] = init2_384
90		d.h[3] = init3_384
91		d.h[4] = init4_384
92		d.h[5] = init5_384
93		d.h[6] = init6_384
94		d.h[7] = init7_384
95	case crypto.SHA512_224:
96		d.h[0] = init0_224
97		d.h[1] = init1_224
98		d.h[2] = init2_224
99		d.h[3] = init3_224
100		d.h[4] = init4_224
101		d.h[5] = init5_224
102		d.h[6] = init6_224
103		d.h[7] = init7_224
104	case crypto.SHA512_256:
105		d.h[0] = init0_256
106		d.h[1] = init1_256
107		d.h[2] = init2_256
108		d.h[3] = init3_256
109		d.h[4] = init4_256
110		d.h[5] = init5_256
111		d.h[6] = init6_256
112		d.h[7] = init7_256
113	default:
114		d.h[0] = init0
115		d.h[1] = init1
116		d.h[2] = init2
117		d.h[3] = init3
118		d.h[4] = init4
119		d.h[5] = init5
120		d.h[6] = init6
121		d.h[7] = init7
122	}
123	d.nx = 0
124	d.len = 0
125}
126
127// New returns a new hash.Hash computing the SHA-512 checksum.
128func New() hash.Hash {
129	d := &digest{function: crypto.SHA512}
130	d.Reset()
131	return d
132}
133
134// New512_224 returns a new hash.Hash computing the SHA-512/224 checksum.
135func New512_224() hash.Hash {
136	d := &digest{function: crypto.SHA512_224}
137	d.Reset()
138	return d
139}
140
141// New512_256 returns a new hash.Hash computing the SHA-512/256 checksum.
142func New512_256() hash.Hash {
143	d := &digest{function: crypto.SHA512_256}
144	d.Reset()
145	return d
146}
147
148// New384 returns a new hash.Hash computing the SHA-384 checksum.
149func New384() hash.Hash {
150	d := &digest{function: crypto.SHA384}
151	d.Reset()
152	return d
153}
154
155func (d *digest) Size() int {
156	switch d.function {
157	case crypto.SHA512_224:
158		return Size224
159	case crypto.SHA512_256:
160		return Size256
161	case crypto.SHA384:
162		return Size384
163	default:
164		return Size
165	}
166}
167
168func (d *digest) BlockSize() int { return BlockSize }
169
170func (d *digest) Write(p []byte) (nn int, err error) {
171	nn = len(p)
172	d.len += uint64(nn)
173	if d.nx > 0 {
174		n := copy(d.x[d.nx:], p)
175		d.nx += n
176		if d.nx == chunk {
177			block(d, d.x[:])
178			d.nx = 0
179		}
180		p = p[n:]
181	}
182	if len(p) >= chunk {
183		n := len(p) &^ (chunk - 1)
184		block(d, p[:n])
185		p = p[n:]
186	}
187	if len(p) > 0 {
188		d.nx = copy(d.x[:], p)
189	}
190	return
191}
192
193func (d0 *digest) Sum(in []byte) []byte {
194	// Make a copy of d0 so that caller can keep writing and summing.
195	d := new(digest)
196	*d = *d0
197	hash := d.checkSum()
198	switch d.function {
199	case crypto.SHA384:
200		return append(in, hash[:Size384]...)
201	case crypto.SHA512_224:
202		return append(in, hash[:Size224]...)
203	case crypto.SHA512_256:
204		return append(in, hash[:Size256]...)
205	default:
206		return append(in, hash[:]...)
207	}
208}
209
210func (d *digest) checkSum() [Size]byte {
211	// Padding.  Add a 1 bit and 0 bits until 112 bytes mod 128.
212	len := d.len
213	var tmp [128]byte
214	tmp[0] = 0x80
215	if len%128 < 112 {
216		d.Write(tmp[0 : 112-len%128])
217	} else {
218		d.Write(tmp[0 : 128+112-len%128])
219	}
220
221	// Length in bits.
222	len <<= 3
223	for i := uint(0); i < 16; i++ {
224		tmp[i] = byte(len >> (120 - 8*i))
225	}
226	d.Write(tmp[0:16])
227
228	if d.nx != 0 {
229		panic("d.nx != 0")
230	}
231
232	h := d.h[:]
233	if d.function == crypto.SHA384 {
234		h = d.h[:6]
235	}
236
237	var digest [Size]byte
238	for i, s := range h {
239		digest[i*8] = byte(s >> 56)
240		digest[i*8+1] = byte(s >> 48)
241		digest[i*8+2] = byte(s >> 40)
242		digest[i*8+3] = byte(s >> 32)
243		digest[i*8+4] = byte(s >> 24)
244		digest[i*8+5] = byte(s >> 16)
245		digest[i*8+6] = byte(s >> 8)
246		digest[i*8+7] = byte(s)
247	}
248
249	return digest
250}
251
252// Sum512 returns the SHA512 checksum of the data.
253func Sum512(data []byte) [Size]byte {
254	d := digest{function: crypto.SHA512}
255	d.Reset()
256	d.Write(data)
257	return d.checkSum()
258}
259
260// Sum384 returns the SHA384 checksum of the data.
261func Sum384(data []byte) (sum384 [Size384]byte) {
262	d := digest{function: crypto.SHA384}
263	d.Reset()
264	d.Write(data)
265	sum := d.checkSum()
266	copy(sum384[:], sum[:Size384])
267	return
268}
269
270// Sum512_224 returns the Sum512/224 checksum of the data.
271func Sum512_224(data []byte) (sum224 [Size224]byte) {
272	d := digest{function: crypto.SHA512_224}
273	d.Reset()
274	d.Write(data)
275	sum := d.checkSum()
276	copy(sum224[:], sum[:Size224])
277	return
278}
279
280// Sum512_256 returns the Sum512/256 checksum of the data.
281func Sum512_256(data []byte) (sum256 [Size256]byte) {
282	d := digest{function: crypto.SHA512_256}
283	d.Reset()
284	d.Write(data)
285	sum := d.checkSum()
286	copy(sum256[:], sum[:Size256])
287	return
288}
289