1
2
3
4
5
6
7
8
9
10
11 package md5
12
13 import (
14 "crypto"
15 "encoding/binary"
16 "errors"
17 "hash"
18 )
19
20 func init() {
21 crypto.RegisterHash(crypto.MD5, New)
22 }
23
24
25 const Size = 16
26
27
28 const BlockSize = 64
29
30 const (
31 init0 = 0x67452301
32 init1 = 0xEFCDAB89
33 init2 = 0x98BADCFE
34 init3 = 0x10325476
35 )
36
37
38 type digest struct {
39 s [4]uint32
40 x [BlockSize]byte
41 nx int
42 len uint64
43 }
44
45 func (d *digest) Reset() {
46 d.s[0] = init0
47 d.s[1] = init1
48 d.s[2] = init2
49 d.s[3] = init3
50 d.nx = 0
51 d.len = 0
52 }
53
54 const (
55 magic = "md5\x01"
56 marshaledSize = len(magic) + 4*4 + BlockSize + 8
57 )
58
59 func (d *digest) MarshalBinary() ([]byte, error) {
60 b := make([]byte, 0, marshaledSize)
61 b = append(b, magic...)
62 b = appendUint32(b, d.s[0])
63 b = appendUint32(b, d.s[1])
64 b = appendUint32(b, d.s[2])
65 b = appendUint32(b, d.s[3])
66 b = append(b, d.x[:d.nx]...)
67 b = b[:len(b)+len(d.x)-d.nx]
68 b = appendUint64(b, d.len)
69 return b, nil
70 }
71
72 func (d *digest) UnmarshalBinary(b []byte) error {
73 if len(b) < len(magic) || string(b[:len(magic)]) != magic {
74 return errors.New("crypto/md5: invalid hash state identifier")
75 }
76 if len(b) != marshaledSize {
77 return errors.New("crypto/md5: invalid hash state size")
78 }
79 b = b[len(magic):]
80 b, d.s[0] = consumeUint32(b)
81 b, d.s[1] = consumeUint32(b)
82 b, d.s[2] = consumeUint32(b)
83 b, d.s[3] = consumeUint32(b)
84 b = b[copy(d.x[:], b):]
85 b, d.len = consumeUint64(b)
86 d.nx = int(d.len % BlockSize)
87 return nil
88 }
89
90 func appendUint64(b []byte, x uint64) []byte {
91 var a [8]byte
92 binary.BigEndian.PutUint64(a[:], x)
93 return append(b, a[:]...)
94 }
95
96 func appendUint32(b []byte, x uint32) []byte {
97 var a [4]byte
98 binary.BigEndian.PutUint32(a[:], x)
99 return append(b, a[:]...)
100 }
101
102 func consumeUint64(b []byte) ([]byte, uint64) {
103 return b[8:], binary.BigEndian.Uint64(b[0:8])
104 }
105
106 func consumeUint32(b []byte) ([]byte, uint32) {
107 return b[4:], binary.BigEndian.Uint32(b[0:4])
108 }
109
110
111
112
113 func New() hash.Hash {
114 d := new(digest)
115 d.Reset()
116 return d
117 }
118
119 func (d *digest) Size() int { return Size }
120
121 func (d *digest) BlockSize() int { return BlockSize }
122
123 func (d *digest) Write(p []byte) (nn int, err error) {
124
125
126
127 nn = len(p)
128 d.len += uint64(nn)
129 if d.nx > 0 {
130 n := copy(d.x[d.nx:], p)
131 d.nx += n
132 if d.nx == BlockSize {
133 if haveAsm {
134 block(d, d.x[:])
135 } else {
136 blockGeneric(d, d.x[:])
137 }
138 d.nx = 0
139 }
140 p = p[n:]
141 }
142 if len(p) >= BlockSize {
143 n := len(p) &^ (BlockSize - 1)
144 if haveAsm {
145 block(d, p[:n])
146 } else {
147 blockGeneric(d, p[:n])
148 }
149 p = p[n:]
150 }
151 if len(p) > 0 {
152 d.nx = copy(d.x[:], p)
153 }
154 return
155 }
156
157 func (d *digest) Sum(in []byte) []byte {
158
159 d0 := *d
160 hash := d0.checkSum()
161 return append(in, hash[:]...)
162 }
163
164 func (d *digest) checkSum() [Size]byte {
165
166
167
168
169
170 tmp := [1 + 63 + 8]byte{0x80}
171 pad := (55 - d.len) % 64
172 binary.LittleEndian.PutUint64(tmp[1+pad:], d.len<<3)
173 d.Write(tmp[:1+pad+8])
174
175
176
177 if d.nx != 0 {
178 panic("d.nx != 0")
179 }
180
181 var digest [Size]byte
182 binary.LittleEndian.PutUint32(digest[0:], d.s[0])
183 binary.LittleEndian.PutUint32(digest[4:], d.s[1])
184 binary.LittleEndian.PutUint32(digest[8:], d.s[2])
185 binary.LittleEndian.PutUint32(digest[12:], d.s[3])
186 return digest
187 }
188
189
190 func Sum(data []byte) [Size]byte {
191 var d digest
192 d.Reset()
193 d.Write(data)
194 return d.checkSum()
195 }
196
View as plain text