Botan  1.11.15
src/lib/hash/comb4p/comb4p.cpp
Go to the documentation of this file.
00001 /*
00002 * Comb4P hash combiner
00003 * (C) 2010 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/internal/hash_utils.h>
00009 #include <botan/comb4p.h>
00010 #include <botan/internal/xor_buf.h>
00011 #include <stdexcept>
00012 
00013 namespace Botan {
00014 
00015 BOTAN_REGISTER_NAMED_T(HashFunction, "Comb4P", Comb4P, Comb4P::make);
00016 
00017 namespace {
00018 
00019 void comb4p_round(secure_vector<byte>& out,
00020                   const secure_vector<byte>& in,
00021                   byte round_no,
00022                   HashFunction& h1,
00023                   HashFunction& h2)
00024    {
00025    h1.update(round_no);
00026    h2.update(round_no);
00027 
00028    h1.update(&in[0], in.size());
00029    h2.update(&in[0], in.size());
00030 
00031    secure_vector<byte> h_buf = h1.final();
00032    xor_buf(&out[0], &h_buf[0], std::min(out.size(), h_buf.size()));
00033 
00034    h_buf = h2.final();
00035    xor_buf(&out[0], &h_buf[0], std::min(out.size(), h_buf.size()));
00036    }
00037 
00038 }
00039 
00040 Comb4P* Comb4P::make(const Spec& spec)
00041    {
00042    if(spec.arg_count() == 2)
00043       {
00044       auto& hashes = Algo_Registry<HashFunction>::global_registry();
00045       std::unique_ptr<HashFunction> h1(hashes.make(spec.arg(0)));
00046       std::unique_ptr<HashFunction> h2(hashes.make(spec.arg(1)));
00047 
00048       if(h1 && h2)
00049          return new Comb4P(h1.release(), h2.release());
00050       }
00051    return nullptr;
00052    }
00053 
00054 Comb4P::Comb4P(HashFunction* h1, HashFunction* h2) :
00055    m_hash1(h1), m_hash2(h2)
00056    {
00057    if(m_hash1->name() == m_hash2->name())
00058       throw std::invalid_argument("Comb4P: Must use two distinct hashes");
00059 
00060    if(m_hash1->output_length() != m_hash2->output_length())
00061       throw std::invalid_argument("Comb4P: Incompatible hashes " +
00062                                   m_hash1->name() + " and " +
00063                                   m_hash2->name());
00064 
00065    clear();
00066    }
00067 
00068 size_t Comb4P::hash_block_size() const
00069    {
00070    if(m_hash1->hash_block_size() == m_hash2->hash_block_size())
00071       return m_hash1->hash_block_size();
00072 
00073    /*
00074    * Return LCM of the block sizes? This would probably be OK for
00075    * HMAC, which is the main thing relying on knowing the block size.
00076    */
00077    return 0;
00078    }
00079 
00080 void Comb4P::clear()
00081    {
00082    m_hash1->clear();
00083    m_hash2->clear();
00084 
00085    // Prep for processing next message, if any
00086    m_hash1->update(0);
00087    m_hash2->update(0);
00088    }
00089 
00090 void Comb4P::add_data(const byte input[], size_t length)
00091    {
00092    m_hash1->update(input, length);
00093    m_hash2->update(input, length);
00094    }
00095 
00096 void Comb4P::final_result(byte out[])
00097    {
00098    secure_vector<byte> h1 = m_hash1->final();
00099    secure_vector<byte> h2 = m_hash2->final();
00100 
00101    // First round
00102    xor_buf(&h1[0], &h2[0], std::min(h1.size(), h2.size()));
00103 
00104    // Second round
00105    comb4p_round(h2, h1, 1, *m_hash1, *m_hash2);
00106 
00107    // Third round
00108    comb4p_round(h1, h2, 2, *m_hash1, *m_hash2);
00109 
00110    copy_mem(out            , &h1[0], h1.size());
00111    copy_mem(out + h1.size(), &h2[0], h2.size());
00112 
00113    // Prep for processing next message, if any
00114    m_hash1->update(0);
00115    m_hash2->update(0);
00116    }
00117 
00118 }
00119