// 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.

//go:generate go run gen.go -output md5block.go

// Package md5 implements the MD5 hash algorithm as defined in RFC 1321. // // MD5 is cryptographically broken and should not be used for secure // applications.
package md5 import ( ) func init() { crypto.RegisterHash(crypto.MD5, New) } // The size of an MD5 checksum in bytes. const Size = 16 // The blocksize of MD5 in bytes. const BlockSize = 64 const ( init0 = 0x67452301 init1 = 0xEFCDAB89 init2 = 0x98BADCFE init3 = 0x10325476 ) // digest represents the partial evaluation of a checksum. type digest struct { s [4]uint32 x [BlockSize]byte nx int len uint64 } func ( *digest) () { .s[0] = init0 .s[1] = init1 .s[2] = init2 .s[3] = init3 .nx = 0 .len = 0 } const ( magic = "md5\x01" marshaledSize = len(magic) + 4*4 + BlockSize + 8 ) func ( *digest) () ([]byte, error) { := make([]byte, 0, marshaledSize) = append(, magic...) = binary.BigEndian.AppendUint32(, .s[0]) = binary.BigEndian.AppendUint32(, .s[1]) = binary.BigEndian.AppendUint32(, .s[2]) = binary.BigEndian.AppendUint32(, .s[3]) = append(, .x[:.nx]...) = [:len()+len(.x)-.nx] // already zero = binary.BigEndian.AppendUint64(, .len) return , nil } func ( *digest) ( []byte) error { if len() < len(magic) || string([:len(magic)]) != magic { return errors.New("crypto/md5: invalid hash state identifier") } if len() != marshaledSize { return errors.New("crypto/md5: invalid hash state size") } = [len(magic):] , .s[0] = consumeUint32() , .s[1] = consumeUint32() , .s[2] = consumeUint32() , .s[3] = consumeUint32() = [copy(.x[:], ):] , .len = consumeUint64() .nx = int(.len % BlockSize) return nil } func consumeUint64( []byte) ([]byte, uint64) { return [8:], binary.BigEndian.Uint64([0:8]) } func consumeUint32( []byte) ([]byte, uint32) { return [4:], binary.BigEndian.Uint32([0:4]) } // New returns a new hash.Hash computing the MD5 checksum. The Hash also // implements [encoding.BinaryMarshaler] and [encoding.BinaryUnmarshaler] to // marshal and unmarshal the internal state of the hash. func () hash.Hash { := new(digest) .Reset() return } func ( *digest) () int { return Size } func ( *digest) () int { return BlockSize } func ( *digest) ( []byte) ( int, error) { // Note that we currently call block or blockGeneric // directly (guarded using haveAsm) because this allows // escape analysis to see that p and d don't escape. = len() .len += uint64() if .nx > 0 { := copy(.x[.nx:], ) .nx += if .nx == BlockSize { if haveAsm { block(, .x[:]) } else { blockGeneric(, .x[:]) } .nx = 0 } = [:] } if len() >= BlockSize { := len() &^ (BlockSize - 1) if haveAsm { block(, [:]) } else { blockGeneric(, [:]) } = [:] } if len() > 0 { .nx = copy(.x[:], ) } return } func ( *digest) ( []byte) []byte { // Make a copy of d so that caller can keep writing and summing. := * := .checkSum() return append(, [:]...) } func ( *digest) () [Size]byte { // Append 0x80 to the end of the message and then append zeros // until the length is a multiple of 56 bytes. Finally append // 8 bytes representing the message length in bits. // // 1 byte end marker :: 0-63 padding bytes :: 8 byte length := [1 + 63 + 8]byte{0x80} := (55 - .len) % 64 // calculate number of padding bytes binary.LittleEndian.PutUint64([1+:], .len<<3) // append length in bits .Write([:1++8]) // The previous write ensures that a whole number of // blocks (i.e. a multiple of 64 bytes) have been hashed. if .nx != 0 { panic("d.nx != 0") } var [Size]byte binary.LittleEndian.PutUint32([0:], .s[0]) binary.LittleEndian.PutUint32([4:], .s[1]) binary.LittleEndian.PutUint32([8:], .s[2]) binary.LittleEndian.PutUint32([12:], .s[3]) return } // Sum returns the MD5 checksum of the data. func ( []byte) [Size]byte { var digest .Reset() .Write() return .checkSum() }