...

Source file src/crypto/md5/md5.go

Documentation: crypto/md5

		 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 -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  	"encoding/binary"
		16  	"errors"
		17  	"hash"
		18  )
		19  
		20  func init() {
		21  	crypto.RegisterHash(crypto.MD5, New)
		22  }
		23  
		24  // The size of an MD5 checksum in bytes.
		25  const Size = 16
		26  
		27  // The blocksize of MD5 in bytes.
		28  const BlockSize = 64
		29  
		30  const (
		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	 [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] // already zero
		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  // New returns a new hash.Hash computing the MD5 checksum. The Hash also
	 111  // implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to
	 112  // marshal and unmarshal the internal state of the hash.
	 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  	// Note that we currently call block or blockGeneric
	 125  	// directly (guarded using haveAsm) because this allows
	 126  	// escape analysis to see that p and d don't escape.
	 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  	// Make a copy of d so that caller can keep writing and summing.
	 159  	d0 := *d
	 160  	hash := d0.checkSum()
	 161  	return append(in, hash[:]...)
	 162  }
	 163  
	 164  func (d *digest) checkSum() [Size]byte {
	 165  	// Append 0x80 to the end of the message and then append zeros
	 166  	// until the length is a multiple of 56 bytes. Finally append
	 167  	// 8 bytes representing the message length in bits.
	 168  	//
	 169  	// 1 byte end marker :: 0-63 padding bytes :: 8 byte length
	 170  	tmp := [1 + 63 + 8]byte{0x80}
	 171  	pad := (55 - d.len) % 64														 // calculate number of padding bytes
	 172  	binary.LittleEndian.PutUint64(tmp[1+pad:], d.len<<3) // append length in bits
	 173  	d.Write(tmp[:1+pad+8])
	 174  
	 175  	// The previous write ensures that a whole number of
	 176  	// blocks (i.e. a multiple of 64 bytes) have been hashed.
	 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  // Sum returns the MD5 checksum of the data.
	 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