md5.mx raw

   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  	"crypto/internal/fips140only"
  16  	"errors"
  17  	"hash"
  18  	"internal/byteorder"
  19  )
  20  
  21  func init() {
  22  	crypto.RegisterHash(crypto.MD5, New)
  23  }
  24  
  25  // The size of an MD5 checksum in bytes.
  26  const Size = 16
  27  
  28  // The blocksize of MD5 in bytes.
  29  const BlockSize = 64
  30  
  31  // The maximum number of bytes that can be passed to block(). The limit exists
  32  // because implementations that rely on assembly routines are not preemptible.
  33  const maxAsmIters = 1024
  34  const maxAsmSize = BlockSize * maxAsmIters // 64KiB
  35  
  36  const (
  37  	init0 = 0x67452301
  38  	init1 = 0xEFCDAB89
  39  	init2 = 0x98BADCFE
  40  	init3 = 0x10325476
  41  )
  42  
  43  // digest represents the partial evaluation of a checksum.
  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([]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, []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) || 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  // New returns a new [hash.Hash] computing the MD5 checksum. The Hash
 113  // also implements [encoding.BinaryMarshaler], [encoding.BinaryAppender] and
 114  // [encoding.BinaryUnmarshaler] to marshal and unmarshal the internal
 115  // state of the hash.
 116  func New() hash.Hash {
 117  	d := &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  	// Note that we currently call block or blockGeneric
 131  	// directly (guarded using haveAsm) because this allows
 132  	// escape analysis to see that p and d don't escape.
 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  	// Make a copy of d so that caller can keep writing and summing.
 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  	// Append 0x80 to the end of the message and then append zeros
 181  	// until the length is a multiple of 56 bytes. Finally append
 182  	// 8 bytes representing the message length in bits.
 183  	//
 184  	// 1 byte end marker :: 0-63 padding bytes :: 8 byte length
 185  	tmp := [1 + 63 + 8]byte{0x80}
 186  	pad := (55 - d.len) % 64                     // calculate number of padding bytes
 187  	byteorder.LEPutUint64(tmp[1+pad:], d.len<<3) // append length in bits
 188  	d.Write(tmp[:1+pad+8])
 189  
 190  	// The previous write ensures that a whole number of
 191  	// blocks (i.e. a multiple of 64 bytes) have been hashed.
 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  // Sum returns the MD5 checksum of the data.
 205  func Sum(data []byte) [Size]byte {
 206  	var d digest
 207  	d.Reset()
 208  	d.Write(data)
 209  	return d.checkSum()
 210  }
 211