1 /**
2 * MD4
3 * 
4 * Copyright:
5 * (C) 1999-2007 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.hash.md4;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_MD4):
15 
16 
17 import botan.hash.mdx_hash;
18 import botan.utils.loadstor;
19 import botan.utils.rotate;
20 import botan.utils.types;
21 import botan.utils.mem_ops;
22 
23 /**
24 * MD4
25 */
26 class MD4 : MDxHashFunction, HashFunction
27 {
28 public:
29     
30     override @property size_t hashBlockSize() const { return super.hashBlockSize(); }
31     override @property string name() const { return "MD4"; }
32     override @property size_t outputLength() const { return 16; }
33     override HashFunction clone() const { return new MD4; }
34 
35     /*
36     * Clear memory of sensitive data
37     */
38     override void clear()
39     {
40         super.clear();
41         zeroise(m_M);
42         m_digest[0] = 0x67452301;
43         m_digest[1] = 0xEFCDAB89;
44         m_digest[2] = 0x98BADCFE;
45         m_digest[3] = 0x10325476;
46     }
47 
48     this()
49     {  
50         super(64, false, true);
51         m_M = 16;
52         m_digest.length = 4;
53         clear(); 
54     }
55 protected:
56     /*
57     * MD4 Compression Function
58     */
59     override void compressN(const(ubyte)* input, size_t blocks)
60     {
61         uint A = m_digest[0], B = m_digest[1], C = m_digest[2], D = m_digest[3];
62         
63         foreach (size_t i; 0 .. blocks)
64         {
65             loadLittleEndian(m_M.ptr, input, m_M.length);
66             
67             FF(A,B,C,D,m_M[ 0], 3);    FF(D,A,B,C,m_M[ 1], 7);
68             FF(C,D,A,B,m_M[ 2],11);    FF(B,C,D,A,m_M[ 3],19);
69             FF(A,B,C,D,m_M[ 4], 3);    FF(D,A,B,C,m_M[ 5], 7);
70             FF(C,D,A,B,m_M[ 6],11);    FF(B,C,D,A,m_M[ 7],19);
71             FF(A,B,C,D,m_M[ 8], 3);    FF(D,A,B,C,m_M[ 9], 7);
72             FF(C,D,A,B,m_M[10],11);    FF(B,C,D,A,m_M[11],19);
73             FF(A,B,C,D,m_M[12], 3);    FF(D,A,B,C,m_M[13], 7);
74             FF(C,D,A,B,m_M[14],11);    FF(B,C,D,A,m_M[15],19);
75             
76             GG(A,B,C,D,m_M[ 0], 3);    GG(D,A,B,C,m_M[ 4], 5);
77             GG(C,D,A,B,m_M[ 8], 9);    GG(B,C,D,A,m_M[12],13);
78             GG(A,B,C,D,m_M[ 1], 3);    GG(D,A,B,C,m_M[ 5], 5);
79             GG(C,D,A,B,m_M[ 9], 9);    GG(B,C,D,A,m_M[13],13);
80             GG(A,B,C,D,m_M[ 2], 3);    GG(D,A,B,C,m_M[ 6], 5);
81             GG(C,D,A,B,m_M[10], 9);    GG(B,C,D,A,m_M[14],13);
82             GG(A,B,C,D,m_M[ 3], 3);    GG(D,A,B,C,m_M[ 7], 5);
83             GG(C,D,A,B,m_M[11], 9);    GG(B,C,D,A,m_M[15],13);
84             
85             HH(A,B,C,D,m_M[ 0], 3);    HH(D,A,B,C,m_M[ 8], 9);
86             HH(C,D,A,B,m_M[ 4],11);    HH(B,C,D,A,m_M[12],15);
87             HH(A,B,C,D,m_M[ 2], 3);    HH(D,A,B,C,m_M[10], 9);
88             HH(C,D,A,B,m_M[ 6],11);    HH(B,C,D,A,m_M[14],15);
89             HH(A,B,C,D,m_M[ 1], 3);    HH(D,A,B,C,m_M[ 9], 9);
90             HH(C,D,A,B,m_M[ 5],11);    HH(B,C,D,A,m_M[13],15);
91             HH(A,B,C,D,m_M[ 3], 3);    HH(D,A,B,C,m_M[11], 9);
92             HH(C,D,A,B,m_M[ 7],11);    HH(B,C,D,A,m_M[15],15);
93             
94             A = (m_digest[0] += A);
95             B = (m_digest[1] += B);
96             C = (m_digest[2] += C);
97             D = (m_digest[3] += D);
98             
99             input += hashBlockSize;
100         }
101     }
102 
103     /*
104     * Copy out the digest
105     */
106     override void copyOut(ubyte* output)
107     {
108         for (size_t i = 0; i != outputLength; i += 4)
109             storeLittleEndian(m_digest[i/4], output + i);
110     }
111 
112     /**
113     * The message buffer, exposed for use by subclasses (x86 asm)
114     */
115     SecureVector!uint m_M;
116 
117     /**
118     * The digest value, exposed for use by subclasses (x86 asm)
119     */
120     SecureVector!uint m_digest;
121 }
122 
123 private:
124 
125 /*
126 * MD4 FF Function
127 */
128 void FF(ref uint A, uint B, uint C, uint D, uint M, ubyte S)
129 {
130     A += (D ^ (B & (C ^ D))) + M;
131     A  = rotateLeft(A, S);
132 }
133 
134 /*
135 * MD4 GG Function
136 */
137 void GG(ref uint A, uint B, uint C, uint D, uint M, ubyte S)
138 {
139     A += ((B & C) | (D & (B | C))) + M + 0x5A827999;
140     A  = rotateLeft(A, S);
141 }
142 
143 /*
144 * MD4 HH Function
145 */
146 void HH(ref uint A, uint B, uint C, uint D, uint M, ubyte S)
147 {
148     A += (B ^ C ^ D) + M + 0x6ED9EBA1;
149     A  = rotateLeft(A, S);
150 }