package md5
import (
"crypto"
"encoding/binary"
"errors"
"hash"
)
func init () {
crypto .RegisterHash (crypto .MD5 , New )
}
const Size = 16
const BlockSize = 64
const (
init0 = 0x67452301
init1 = 0xEFCDAB89
init2 = 0x98BADCFE
init3 = 0x10325476
)
type digest struct {
s [4 ]uint32
x [BlockSize ]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
}
const (
magic = "md5\x01"
marshaledSize = len (magic ) + 4 *4 + BlockSize + 8
)
func (d *digest ) MarshalBinary () ([]byte , error ) {
b := make ([]byte , 0 , marshaledSize )
b = append (b , magic ...)
b = binary .BigEndian .AppendUint32 (b , d .s [0 ])
b = binary .BigEndian .AppendUint32 (b , d .s [1 ])
b = binary .BigEndian .AppendUint32 (b , d .s [2 ])
b = binary .BigEndian .AppendUint32 (b , d .s [3 ])
b = append (b , d .x [:d .nx ]...)
b = b [:len (b )+len (d .x )-d .nx ]
b = binary .BigEndian .AppendUint64 (b , d .len )
return b , nil
}
func (d *digest ) UnmarshalBinary (b []byte ) error {
if len (b ) < len (magic ) || string (b [:len (magic )]) != magic {
return errors .New ("crypto/md5: invalid hash state identifier" )
}
if len (b ) != marshaledSize {
return errors .New ("crypto/md5: invalid hash state size" )
}
b = b [len (magic ):]
b , d .s [0 ] = consumeUint32 (b )
b , d .s [1 ] = consumeUint32 (b )
b , d .s [2 ] = consumeUint32 (b )
b , d .s [3 ] = consumeUint32 (b )
b = b [copy (d .x [:], b ):]
b , d .len = consumeUint64 (b )
d .nx = int (d .len % BlockSize )
return nil
}
func consumeUint64 (b []byte ) ([]byte , uint64 ) {
return b [8 :], binary .BigEndian .Uint64 (b [0 :8 ])
}
func consumeUint32 (b []byte ) ([]byte , uint32 ) {
return b [4 :], binary .BigEndian .Uint32 (b [0 :4 ])
}
func New () hash .Hash {
d := new (digest )
d .Reset ()
return d
}
func (d *digest ) Size () int { return Size }
func (d *digest ) BlockSize () int { return BlockSize }
func (d *digest ) Write (p []byte ) (nn int , err error ) {
nn = len (p )
d .len += uint64 (nn )
if d .nx > 0 {
n := copy (d .x [d .nx :], p )
d .nx += n
if d .nx == BlockSize {
if haveAsm {
block (d , d .x [:])
} else {
blockGeneric (d , d .x [:])
}
d .nx = 0
}
p = p [n :]
}
if len (p ) >= BlockSize {
n := len (p ) &^ (BlockSize - 1 )
if haveAsm {
block (d , p [:n ])
} else {
blockGeneric (d , p [:n ])
}
p = p [n :]
}
if len (p ) > 0 {
d .nx = copy (d .x [:], p )
}
return
}
func (d *digest ) Sum (in []byte ) []byte {
d0 := *d
hash := d0 .checkSum ()
return append (in , hash [:]...)
}
func (d *digest ) checkSum () [Size ]byte {
tmp := [1 + 63 + 8 ]byte {0x80 }
pad := (55 - d .len ) % 64
binary .LittleEndian .PutUint64 (tmp [1 +pad :], d .len <<3 )
d .Write (tmp [:1 +pad +8 ])
if d .nx != 0 {
panic ("d.nx != 0" )
}
var digest [Size ]byte
binary .LittleEndian .PutUint32 (digest [0 :], d .s [0 ])
binary .LittleEndian .PutUint32 (digest [4 :], d .s [1 ])
binary .LittleEndian .PutUint32 (digest [8 :], d .s [2 ])
binary .LittleEndian .PutUint32 (digest [12 :], d .s [3 ])
return digest
}
func Sum (data []byte ) [Size ]byte {
var d digest
d .Reset ()
d .Write (data )
return d .checkSum ()
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .