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 }