src/pkg/crypto/md5/md5.go - The Go Programming Language

Golang

Source file src/pkg/crypto/md5/md5.go

     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	// Package md5 implements the MD5 hash algorithm as defined in RFC 1321.
     6	package md5
     7	
     8	import (
     9		"crypto"
    10		"hash"
    11	)
    12	
    13	func init() {
    14		crypto.RegisterHash(crypto.MD5, New)
    15	}
    16	
    17	// The size of an MD5 checksum in bytes.
    18	const Size = 16
    19	
    20	// The blocksize of MD5 in bytes.
    21	const BlockSize = 64
    22	
    23	const (
    24		_Chunk = 64
    25		_Init0 = 0x67452301
    26		_Init1 = 0xEFCDAB89
    27		_Init2 = 0x98BADCFE
    28		_Init3 = 0x10325476
    29	)
    30	
    31	// digest represents the partial evaluation of a checksum.
    32	type digest struct {
    33		s   [4]uint32
    34		x   [_Chunk]byte
    35		nx  int
    36		len uint64
    37	}
    38	
    39	func (d *digest) Reset() {
    40		d.s[0] = _Init0
    41		d.s[1] = _Init1
    42		d.s[2] = _Init2
    43		d.s[3] = _Init3
    44		d.nx = 0
    45		d.len = 0
    46	}
    47	
    48	// New returns a new hash.Hash computing the MD5 checksum.
    49	func New() hash.Hash {
    50		d := new(digest)
    51		d.Reset()
    52		return d
    53	}
    54	
    55	func (d *digest) Size() int { return Size }
    56	
    57	func (d *digest) BlockSize() int { return BlockSize }
    58	
    59	func (d *digest) Write(p []byte) (nn int, err error) {
    60		nn = len(p)
    61		d.len += uint64(nn)
    62		if d.nx > 0 {
    63			n := len(p)
    64			if n > _Chunk-d.nx {
    65				n = _Chunk - d.nx
    66			}
    67			for i := 0; i < n; i++ {
    68				d.x[d.nx+i] = p[i]
    69			}
    70			d.nx += n
    71			if d.nx == _Chunk {
    72				_Block(d, d.x[0:])
    73				d.nx = 0
    74			}
    75			p = p[n:]
    76		}
    77		n := _Block(d, p)
    78		p = p[n:]
    79		if len(p) > 0 {
    80			d.nx = copy(d.x[:], p)
    81		}
    82		return
    83	}
    84	
    85	func (d0 *digest) Sum(in []byte) []byte {
    86		// Make a copy of d0 so that caller can keep writing and summing.
    87		d := *d0
    88	
    89		// Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
    90		len := d.len
    91		var tmp [64]byte
    92		tmp[0] = 0x80
    93		if len%64 < 56 {
    94			d.Write(tmp[0 : 56-len%64])
    95		} else {
    96			d.Write(tmp[0 : 64+56-len%64])
    97		}
    98	
    99		// Length in bits.
   100		len <<= 3
   101		for i := uint(0); i < 8; i++ {
   102			tmp[i] = byte(len >> (8 * i))
   103		}
   104		d.Write(tmp[0:8])
   105	
   106		if d.nx != 0 {
   107			panic("d.nx != 0")
   108		}
   109	
   110		var digest [Size]byte
   111		for i, s := range d.s {
   112			digest[i*4] = byte(s)
   113			digest[i*4+1] = byte(s >> 8)
   114			digest[i*4+2] = byte(s >> 16)
   115			digest[i*4+3] = byte(s >> 24)
   116		}
   117	
   118		return append(in, digest[:]...)
   119	}