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