github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/crypto/md5/md5.go (about) 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 //go:generate go run gen.go -full -output md5block.go 6 7 // Package md5 implements the MD5 hash algorithm as defined in RFC 1321. 8 // 9 // MD5 is cryptographically broken and should not be used for secure 10 // applications. 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 // The size of an MD5 checksum in bytes. 24 const Size = 16 25 26 // The blocksize of MD5 in bytes. 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 // digest represents the partial evaluation of a checksum. 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[:]...) 67 b = appendUint64(b, d.len) 68 return b, nil 69 } 70 71 func (d *digest) UnmarshalBinary(b []byte) error { 72 if len(b) < len(magic) || string(b[:len(magic)]) != magic { 73 return errors.New("crypto/md5: invalid hash state identifier") 74 } 75 if len(b) != marshaledSize { 76 return errors.New("crypto/md5: invalid hash state size") 77 } 78 b = b[len(magic):] 79 b, d.s[0] = consumeUint32(b) 80 b, d.s[1] = consumeUint32(b) 81 b, d.s[2] = consumeUint32(b) 82 b, d.s[3] = consumeUint32(b) 83 b = b[copy(d.x[:], b):] 84 b, d.len = consumeUint64(b) 85 d.nx = int(d.len) % chunk 86 return nil 87 } 88 89 func appendUint64(b []byte, x uint64) []byte { 90 a := [8]byte{ 91 byte(x >> 56), 92 byte(x >> 48), 93 byte(x >> 40), 94 byte(x >> 32), 95 byte(x >> 24), 96 byte(x >> 16), 97 byte(x >> 8), 98 byte(x), 99 } 100 return append(b, a[:]...) 101 } 102 103 func appendUint32(b []byte, x uint32) []byte { 104 a := [4]byte{ 105 byte(x >> 24), 106 byte(x >> 16), 107 byte(x >> 8), 108 byte(x), 109 } 110 return append(b, a[:]...) 111 } 112 113 func consumeUint64(b []byte) ([]byte, uint64) { 114 _ = b[7] 115 x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | 116 uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 117 return b[8:], x 118 } 119 120 func consumeUint32(b []byte) ([]byte, uint32) { 121 _ = b[3] 122 x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 123 return b[4:], x 124 } 125 126 // New returns a new hash.Hash computing the MD5 checksum. 127 func New() hash.Hash { 128 d := new(digest) 129 d.Reset() 130 return d 131 } 132 133 func (d *digest) Size() int { return Size } 134 135 func (d *digest) BlockSize() int { return BlockSize } 136 137 func (d *digest) Write(p []byte) (nn int, err error) { 138 nn = len(p) 139 d.len += uint64(nn) 140 if d.nx > 0 { 141 n := copy(d.x[d.nx:], p) 142 d.nx += n 143 if d.nx == chunk { 144 block(d, d.x[:]) 145 d.nx = 0 146 } 147 p = p[n:] 148 } 149 if len(p) >= chunk { 150 n := len(p) &^ (chunk - 1) 151 block(d, p[:n]) 152 p = p[n:] 153 } 154 if len(p) > 0 { 155 d.nx = copy(d.x[:], p) 156 } 157 return 158 } 159 160 func (d0 *digest) Sum(in []byte) []byte { 161 // Make a copy of d0 so that caller can keep writing and summing. 162 d := *d0 163 hash := d.checkSum() 164 return append(in, hash[:]...) 165 } 166 167 func (d *digest) checkSum() [Size]byte { 168 // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64. 169 len := d.len 170 var tmp [64]byte 171 tmp[0] = 0x80 172 if len%64 < 56 { 173 d.Write(tmp[0 : 56-len%64]) 174 } else { 175 d.Write(tmp[0 : 64+56-len%64]) 176 } 177 178 // Length in bits. 179 len <<= 3 180 for i := uint(0); i < 8; i++ { 181 tmp[i] = byte(len >> (8 * i)) 182 } 183 d.Write(tmp[0:8]) 184 185 if d.nx != 0 { 186 panic("d.nx != 0") 187 } 188 189 var digest [Size]byte 190 for i, s := range d.s { 191 digest[i*4] = byte(s) 192 digest[i*4+1] = byte(s >> 8) 193 digest[i*4+2] = byte(s >> 16) 194 digest[i*4+3] = byte(s >> 24) 195 } 196 197 return digest 198 } 199 200 // Sum returns the MD5 checksum of the data. 201 func Sum(data []byte) [Size]byte { 202 var d digest 203 d.Reset() 204 d.Write(data) 205 return d.checkSum() 206 }