Go Home Page
The Go Programming Language

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

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package implements the MD5 hash algorithm as defined in RFC 1321.
package md5

import (
    "hash"
    "os"
)

// The size of an MD5 checksum in bytes.
const Size = 16

const (
    _Chunk = 64
    _Init0 = 0x67452301
    _Init1 = 0xEFCDAB89
    _Init2 = 0x98BADCFE
    _Init3 = 0x10325476
)

// digest represents the partial evaluation of a checksum.
type digest struct {
    s   [4]uint32
    x   [_Chunk]byte
    nx  int
    len uint64
}

func (d *digest) Reset() {
    d.s[0] = _Init0
    d.s[1] = _Init1
    d.s[2] = _Init2
    d.s[3] = _Init3
    d.nx = 0
    d.len = 0
}

// New returns a new hash.Hash computing the MD5 checksum.
func New() hash.Hash {
    d := new(digest)
    d.Reset()
    return d
}

func (d *digest) Size() int { return Size }

func (d *digest) Write(p []byte) (nn int, err os.Error) {
    nn = len(p)
    d.len += uint64(nn)
    if d.nx > 0 {
        n := len(p)
        if n > _Chunk-d.nx {
            n = _Chunk - d.nx
        }
        for i := 0; i < n; i++ {
            d.x[d.nx+i] = p[i]
        }
        d.nx += n
        if d.nx == _Chunk {
            _Block(d, d.x[0:])
            d.nx = 0
        }
        p = p[n:]
    }
    n := _Block(d, p)
    p = p[n:]
    if len(p) > 0 {
        for i, x := range p {
            d.x[i] = x
        }
        d.nx = len(p)
    }
    return
}

func (d0 *digest) Sum() []byte {
    // Make a copy of d0 so that caller can keep writing and summing.
    d := new(digest)
    *d = *d0

    // Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
    len := d.len
    var tmp [64]byte
    tmp[0] = 0x80
    if len%64 < 56 {
        d.Write(tmp[0 : 56-len%64])
    } else {
        d.Write(tmp[0 : 64+56-len%64])
    }

    // Length in bits.
    len <<= 3
    for i := uint(0); i < 8; i++ {
        tmp[i] = byte(len >> (8 * i))
    }
    d.Write(tmp[0:8])

    if d.nx != 0 {
        panic("d.nx != 0")
    }

    p := make([]byte, 16)
    j := 0
    for _, s := range d.s {
        p[j+0] = byte(s >> 0)
        p[j+1] = byte(s >> 8)
        p[j+2] = byte(s >> 16)
        p[j+3] = byte(s >> 24)
        j += 4
    }
    return p
}