1 /** 2 * MDx Hash Function 3 * 4 * Copyright: 5 * (C) 1999-2008 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.mdx_hash; 12 13 public import botan.hash.hash; 14 import botan.utils.exceptn; 15 import botan.utils.loadstor; 16 import botan.utils.types; 17 import botan.utils.mem_ops; 18 19 /** 20 * MDx Hash Function Base Class 21 */ 22 class MDxHashFunction : HashFunction 23 { 24 public: 25 /** 26 * Params: 27 * block_len = is the number of bytes per block 28 * byte_end = specifies if the hash uses big-endian bytes 29 * bit_end = specifies if the hash uses big-endian bits 30 * cnt_size = specifies the size of the counter var in bytes 31 */ 32 this(size_t block_len, bool byte_end, bool bit_end, size_t cnt_size = 8) 33 { 34 m_buffer.length = block_len; 35 m_BIG_BYTE_ENDIAN = byte_end; 36 m_BIG_BIT_ENDIAN = bit_end; 37 m_COUNT_SIZE = cnt_size; 38 m_count = m_position = 0; 39 } 40 41 override @property size_t hashBlockSize() const { return m_buffer.length; } 42 protected: 43 /* 44 * Update the hash 45 */ 46 override final void addData(const(ubyte)* input, size_t length) 47 { 48 m_count += length; 49 if (m_position > 0) 50 { 51 bufferInsert(m_buffer, m_position, input, length); 52 53 if (m_position + length >= m_buffer.length) 54 { 55 input += (m_buffer.length - m_position); 56 length -= (m_buffer.length - m_position); 57 m_position = 0; 58 compressN(m_buffer.ptr, 1); 59 } 60 } 61 import std.exception : enforce; 62 enforce(length < size_t.max/2, "Integer overflow"); 63 64 const size_t full_blocks = length / m_buffer.length; 65 const size_t remaining = length % m_buffer.length; 66 67 if (full_blocks) { 68 compressN(input, full_blocks); 69 } 70 bufferInsert(m_buffer, m_position, input + full_blocks * m_buffer.length, remaining); 71 m_position += remaining; 72 } 73 74 75 /* 76 * Finalize a hash 77 */ 78 override final void finalResult(ubyte* output) 79 { 80 if (m_buffer.length <= m_position) return; 81 m_buffer[m_position] = (m_BIG_BIT_ENDIAN ? 0x80 : 0x01); 82 if (m_buffer.length > m_position + 1) 83 foreach (size_t i; (m_position+1) .. m_buffer.length) 84 m_buffer[i] = 0; 85 86 if (m_position >= m_buffer.length - m_COUNT_SIZE) 87 { 88 compressN(m_buffer.ptr, 1); 89 zeroise(m_buffer); 90 } 91 writeCount(&m_buffer[m_buffer.length - m_COUNT_SIZE]); 92 compressN(m_buffer.ptr, 1); 93 copyOut(output); 94 clear(); 95 } 96 97 /** 98 * Run the hash's compression function over a set of blocks 99 * Params: 100 * blocks = the input 101 * block_n = the number of blocks 102 */ 103 abstract void compressN(const(ubyte)* blocks, size_t block_n); 104 105 /* 106 * Clear memory of sensitive data 107 */ 108 override void clear() 109 { 110 zeroise(m_buffer); 111 m_count = m_position = 0; 112 } 113 114 /** 115 * Copy the output to the buffer 116 * Params: 117 * buffer = to put the output into 118 */ 119 abstract void copyOut(ubyte* buffer); 120 121 /** 122 * Write the count, if used, to this spot 123 * Params: 124 * output = where to write the counter to 125 */ 126 final void writeCount(ubyte* output) 127 { 128 if (m_COUNT_SIZE < 8) 129 throw new InvalidState("MDxHashFunction.writeCount: COUNT_SIZE < 8"); 130 if (m_COUNT_SIZE >= outputLength() || m_COUNT_SIZE >= hashBlockSize) 131 throw new InvalidArgument("MDxHashFunction: COUNT_SIZE is too big"); 132 133 const ulong bit_count = m_count * 8; 134 if (m_BIG_BYTE_ENDIAN) 135 storeBigEndian(bit_count, output + m_COUNT_SIZE - 8); 136 else 137 storeLittleEndian(bit_count, output + m_COUNT_SIZE - 8); 138 } 139 private: 140 SecureVector!ubyte m_buffer; 141 ulong m_count; 142 size_t m_position; 143 144 const bool m_BIG_BYTE_ENDIAN, m_BIG_BIT_ENDIAN; 145 const size_t m_COUNT_SIZE; 146 }