1
2
3
4
5
6
7
8
9
10
11 package md5
12
13 import (
14 "crypto"
15 "errors"
16 "hash"
17 )
18
19 func init() {
20 crypto.RegisterHash(crypto.MD5, New)
21 }
22
23
24 const Size = 16
25
26
27 const BlockSize = 64
28
29 const (
30 chunk = 64
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 [chunk]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 + chunk + 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)-int(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) % chunk
87 return nil
88 }
89
90 func appendUint64(b []byte, x uint64) []byte {
91 a := [8]byte{
92 byte(x >> 56),
93 byte(x >> 48),
94 byte(x >> 40),
95 byte(x >> 32),
96 byte(x >> 24),
97 byte(x >> 16),
98 byte(x >> 8),
99 byte(x),
100 }
101 return append(b, a[:]...)
102 }
103
104 func appendUint32(b []byte, x uint32) []byte {
105 a := [4]byte{
106 byte(x >> 24),
107 byte(x >> 16),
108 byte(x >> 8),
109 byte(x),
110 }
111 return append(b, a[:]...)
112 }
113
114 func consumeUint64(b []byte) ([]byte, uint64) {
115 _ = b[7]
116 x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
117 uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
118 return b[8:], x
119 }
120
121 func consumeUint32(b []byte) ([]byte, uint32) {
122 _ = b[3]
123 x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
124 return b[4:], x
125 }
126
127
128
129
130 func New() hash.Hash {
131 d := new(digest)
132 d.Reset()
133 return d
134 }
135
136 func (d *digest) Size() int { return Size }
137
138 func (d *digest) BlockSize() int { return BlockSize }
139
140 func (d *digest) Write(p []byte) (nn int, err error) {
141 nn = len(p)
142 d.len += uint64(nn)
143 if d.nx > 0 {
144 n := copy(d.x[d.nx:], p)
145 d.nx += n
146 if d.nx == chunk {
147 block(d, d.x[:])
148 d.nx = 0
149 }
150 p = p[n:]
151 }
152 if len(p) >= chunk {
153 n := len(p) &^ (chunk - 1)
154 block(d, p[:n])
155 p = p[n:]
156 }
157 if len(p) > 0 {
158 d.nx = copy(d.x[:], p)
159 }
160 return
161 }
162
163 func (d0 *digest) Sum(in []byte) []byte {
164
165 d := *d0
166 hash := d.checkSum()
167 return append(in, hash[:]...)
168 }
169
170 func (d *digest) checkSum() [Size]byte {
171
172 len := d.len
173 var tmp [64]byte
174 tmp[0] = 0x80
175 if len%64 < 56 {
176 d.Write(tmp[0 : 56-len%64])
177 } else {
178 d.Write(tmp[0 : 64+56-len%64])
179 }
180
181
182 len <<= 3
183 for i := uint(0); i < 8; i++ {
184 tmp[i] = byte(len >> (8 * i))
185 }
186 d.Write(tmp[0:8])
187
188 if d.nx != 0 {
189 panic("d.nx != 0")
190 }
191
192 var digest [Size]byte
193 for i, s := range d.s {
194 digest[i*4] = byte(s)
195 digest[i*4+1] = byte(s >> 8)
196 digest[i*4+2] = byte(s >> 16)
197 digest[i*4+3] = byte(s >> 24)
198 }
199
200 return digest
201 }
202
203
204 func Sum(data []byte) [Size]byte {
205 var d digest
206 d.Reset()
207 d.Write(data)
208 return d.checkSum()
209 }
210
View as plain text