1 /*
2 * Comb4P hash combiner
3 * (C) 2010 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/comb4p.h>
9 #include <botan/exceptn.h>
10 
11 namespace Botan {
12 
13 namespace {
14 
comb4p_round(secure_vector<uint8_t> & out,const secure_vector<uint8_t> & in,uint8_t round_no,HashFunction & h1,HashFunction & h2)15 void comb4p_round(secure_vector<uint8_t>& out,
16                   const secure_vector<uint8_t>& in,
17                   uint8_t round_no,
18                   HashFunction& h1,
19                   HashFunction& h2)
20    {
21    h1.update(round_no);
22    h2.update(round_no);
23 
24    h1.update(in.data(), in.size());
25    h2.update(in.data(), in.size());
26 
27    secure_vector<uint8_t> h_buf = h1.final();
28    xor_buf(out.data(), h_buf.data(), std::min(out.size(), h_buf.size()));
29 
30    h_buf = h2.final();
31    xor_buf(out.data(), h_buf.data(), std::min(out.size(), h_buf.size()));
32    }
33 
34 }
35 
Comb4P(HashFunction * h1,HashFunction * h2)36 Comb4P::Comb4P(HashFunction* h1, HashFunction* h2) :
37    m_hash1(h1), m_hash2(h2)
38    {
39    if(m_hash1->name() == m_hash2->name())
40       throw Invalid_Argument("Comb4P: Must use two distinct hashes");
41 
42    if(m_hash1->output_length() != m_hash2->output_length())
43       throw Invalid_Argument("Comb4P: Incompatible hashes " +
44                                   m_hash1->name() + " and " +
45                                   m_hash2->name());
46 
47    clear();
48    }
49 
hash_block_size() const50 size_t Comb4P::hash_block_size() const
51    {
52    if(m_hash1->hash_block_size() == m_hash2->hash_block_size())
53       return m_hash1->hash_block_size();
54 
55    /*
56    * Return LCM of the block sizes? This would probably be OK for
57    * HMAC, which is the main thing relying on knowing the block size.
58    */
59    return 0;
60    }
61 
clear()62 void Comb4P::clear()
63    {
64    m_hash1->clear();
65    m_hash2->clear();
66 
67    // Prep for processing next message, if any
68    m_hash1->update(0);
69    m_hash2->update(0);
70    }
71 
copy_state() const72 std::unique_ptr<HashFunction> Comb4P::copy_state() const
73    {
74    std::unique_ptr<Comb4P> copy(new Comb4P);
75    copy->m_hash1 = m_hash1->copy_state();
76    copy->m_hash2 = m_hash2->copy_state();
77    // work around GCC 4.8 bug
78    return std::unique_ptr<HashFunction>(copy.release());
79    }
80 
add_data(const uint8_t input[],size_t length)81 void Comb4P::add_data(const uint8_t input[], size_t length)
82    {
83    m_hash1->update(input, length);
84    m_hash2->update(input, length);
85    }
86 
final_result(uint8_t out[])87 void Comb4P::final_result(uint8_t out[])
88    {
89    secure_vector<uint8_t> h1 = m_hash1->final();
90    secure_vector<uint8_t> h2 = m_hash2->final();
91 
92    // First round
93    xor_buf(h1.data(), h2.data(), std::min(h1.size(), h2.size()));
94 
95    // Second round
96    comb4p_round(h2, h1, 1, *m_hash1, *m_hash2);
97 
98    // Third round
99    comb4p_round(h1, h2, 2, *m_hash1, *m_hash2);
100 
101    copy_mem(out            , h1.data(), h1.size());
102    copy_mem(out + h1.size(), h2.data(), h2.size());
103 
104    // Prep for processing next message, if any
105    m_hash1->update(0);
106    m_hash2->update(0);
107    }
108 
109 }
110 
111