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