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 }