Source file src/pkg/crypto/sha256/sha256.go
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-2.
7 package sha256
8
9 import (
10 "crypto"
11 "hash"
12 )
13
14 func init() {
15 crypto.RegisterHash(crypto.SHA224, New224)
16 crypto.RegisterHash(crypto.SHA256, New)
17 }
18
19 // The size of a SHA256 checksum in bytes.
20 const Size = 32
21
22 // The size of a SHA224 checksum in bytes.
23 const Size224 = 28
24
25 // The blocksize of SHA256 and SHA224 in bytes.
26 const BlockSize = 64
27
28 const (
29 _Chunk = 64
30 _Init0 = 0x6A09E667
31 _Init1 = 0xBB67AE85
32 _Init2 = 0x3C6EF372
33 _Init3 = 0xA54FF53A
34 _Init4 = 0x510E527F
35 _Init5 = 0x9B05688C
36 _Init6 = 0x1F83D9AB
37 _Init7 = 0x5BE0CD19
38 _Init0_224 = 0xC1059ED8
39 _Init1_224 = 0x367CD507
40 _Init2_224 = 0x3070DD17
41 _Init3_224 = 0xF70E5939
42 _Init4_224 = 0xFFC00B31
43 _Init5_224 = 0x68581511
44 _Init6_224 = 0x64F98FA7
45 _Init7_224 = 0xBEFA4FA4
46 )
47
48 // digest represents the partial evaluation of a checksum.
49 type digest struct {
50 h [8]uint32
51 x [_Chunk]byte
52 nx int
53 len uint64
54 is224 bool // mark if this digest is SHA-224
55 }
56
57 func (d *digest) Reset() {
58 if !d.is224 {
59 d.h[0] = _Init0
60 d.h[1] = _Init1
61 d.h[2] = _Init2
62 d.h[3] = _Init3
63 d.h[4] = _Init4
64 d.h[5] = _Init5
65 d.h[6] = _Init6
66 d.h[7] = _Init7
67 } else {
68 d.h[0] = _Init0_224
69 d.h[1] = _Init1_224
70 d.h[2] = _Init2_224
71 d.h[3] = _Init3_224
72 d.h[4] = _Init4_224
73 d.h[5] = _Init5_224
74 d.h[6] = _Init6_224
75 d.h[7] = _Init7_224
76 }
77 d.nx = 0
78 d.len = 0
79 }
80
81 // New returns a new hash.Hash computing the SHA256 checksum.
82 func New() hash.Hash {
83 d := new(digest)
84 d.Reset()
85 return d
86 }
87
88 // New224 returns a new hash.Hash computing the SHA224 checksum.
89 func New224() hash.Hash {
90 d := new(digest)
91 d.is224 = true
92 d.Reset()
93 return d
94 }
95
96 func (d *digest) Size() int {
97 if !d.is224 {
98 return Size
99 }
100 return Size224
101 }
102
103 func (d *digest) BlockSize() int { return BlockSize }
104
105 func (d *digest) Write(p []byte) (nn int, err error) {
106 nn = len(p)
107 d.len += uint64(nn)
108 if d.nx > 0 {
109 n := len(p)
110 if n > _Chunk-d.nx {
111 n = _Chunk - d.nx
112 }
113 for i := 0; i < n; i++ {
114 d.x[d.nx+i] = p[i]
115 }
116 d.nx += n
117 if d.nx == _Chunk {
118 _Block(d, d.x[0:])
119 d.nx = 0
120 }
121 p = p[n:]
122 }
123 n := _Block(d, p)
124 p = p[n:]
125 if len(p) > 0 {
126 d.nx = copy(d.x[:], p)
127 }
128 return
129 }
130
131 func (d0 *digest) Sum(in []byte) []byte {
132 // Make a copy of d0 so that caller can keep writing and summing.
133 d := *d0
134
135 // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
136 len := d.len
137 var tmp [64]byte
138 tmp[0] = 0x80
139 if len%64 < 56 {
140 d.Write(tmp[0 : 56-len%64])
141 } else {
142 d.Write(tmp[0 : 64+56-len%64])
143 }
144
145 // Length in bits.
146 len <<= 3
147 for i := uint(0); i < 8; i++ {
148 tmp[i] = byte(len >> (56 - 8*i))
149 }
150 d.Write(tmp[0:8])
151
152 if d.nx != 0 {
153 panic("d.nx != 0")
154 }
155
156 h := d.h[:]
157 size := Size
158 if d.is224 {
159 h = d.h[:7]
160 size = Size224
161 }
162
163 var digest [Size]byte
164 for i, s := range h {
165 digest[i*4] = byte(s >> 24)
166 digest[i*4+1] = byte(s >> 16)
167 digest[i*4+2] = byte(s >> 8)
168 digest[i*4+3] = byte(s)
169 }
170
171 return append(in, digest[:size]...)
172 }