Botan  1.11.15
src/lib/mac/cmac/cmac.cpp
Go to the documentation of this file.
00001 /*
00002 * CMAC
00003 * (C) 1999-2007,2014 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/internal/mac_utils.h>
00009 #include <botan/cmac.h>
00010 
00011 namespace Botan {
00012 
00013 CMAC* CMAC::make(const Spec& spec)
00014    {
00015    if(spec.arg_count() == 1)
00016       return new CMAC(Algo_Registry<BlockCipher>::global_registry().make(spec.arg(0)));
00017    return nullptr;
00018    }
00019 
00020 BOTAN_REGISTER_NAMED_T(MessageAuthenticationCode, "CMAC", CMAC, CMAC::make);
00021 
00022 /*
00023 * Perform CMAC's multiplication in GF(2^n)
00024 */
00025 secure_vector<byte> CMAC::poly_double(const secure_vector<byte>& in)
00026    {
00027    const bool top_carry = (in[0] & 0x80);
00028 
00029    secure_vector<byte> out = in;
00030 
00031    byte carry = 0;
00032    for(size_t i = out.size(); i != 0; --i)
00033       {
00034       byte temp = out[i-1];
00035       out[i-1] = (temp << 1) | carry;
00036       carry = (temp >> 7);
00037       }
00038 
00039    if(top_carry)
00040       {
00041       switch(in.size())
00042          {
00043          case 8:
00044             out[out.size()-1] ^= 0x1B;
00045             break;
00046          case 16:
00047             out[out.size()-1] ^= 0x87;
00048             break;
00049          case 32:
00050             out[out.size()-2] ^= 0x4;
00051             out[out.size()-1] ^= 0x25;
00052             break;
00053          case 64:
00054             out[out.size()-2] ^= 0x1;
00055             out[out.size()-1] ^= 0x25;
00056             break;
00057          default:
00058             throw std::runtime_error("Unsupported CMAC size " + std::to_string(in.size()));
00059          }
00060       }
00061 
00062    return out;
00063    }
00064 
00065 /*
00066 * Update an CMAC Calculation
00067 */
00068 void CMAC::add_data(const byte input[], size_t length)
00069    {
00070    buffer_insert(m_buffer, m_position, input, length);
00071    if(m_position + length > output_length())
00072       {
00073       xor_buf(m_state, m_buffer, output_length());
00074       m_cipher->encrypt(m_state);
00075       input += (output_length() - m_position);
00076       length -= (output_length() - m_position);
00077       while(length > output_length())
00078          {
00079          xor_buf(m_state, input, output_length());
00080          m_cipher->encrypt(m_state);
00081          input += output_length();
00082          length -= output_length();
00083          }
00084       copy_mem(&m_buffer[0], input, length);
00085       m_position = 0;
00086       }
00087    m_position += length;
00088    }
00089 
00090 /*
00091 * Finalize an CMAC Calculation
00092 */
00093 void CMAC::final_result(byte mac[])
00094    {
00095    xor_buf(m_state, m_buffer, m_position);
00096 
00097    if(m_position == output_length())
00098       {
00099       xor_buf(m_state, m_B, output_length());
00100       }
00101    else
00102       {
00103       m_state[m_position] ^= 0x80;
00104       xor_buf(m_state, m_P, output_length());
00105       }
00106 
00107    m_cipher->encrypt(m_state);
00108 
00109    for(size_t i = 0; i != output_length(); ++i)
00110       mac[i] = m_state[i];
00111 
00112    zeroise(m_state);
00113    zeroise(m_buffer);
00114    m_position = 0;
00115    }
00116 
00117 /*
00118 * CMAC Key Schedule
00119 */
00120 void CMAC::key_schedule(const byte key[], size_t length)
00121    {
00122    clear();
00123    m_cipher->set_key(key, length);
00124    m_cipher->encrypt(m_B);
00125    m_B = poly_double(m_B);
00126    m_P = poly_double(m_B);
00127    }
00128 
00129 /*
00130 * Clear memory of sensitive data
00131 */
00132 void CMAC::clear()
00133    {
00134    m_cipher->clear();
00135    zeroise(m_state);
00136    zeroise(m_buffer);
00137    zeroise(m_B);
00138    zeroise(m_P);
00139    m_position = 0;
00140    }
00141 
00142 /*
00143 * Return the name of this type
00144 */
00145 std::string CMAC::name() const
00146    {
00147    return "CMAC(" + m_cipher->name() + ")";
00148    }
00149 
00150 /*
00151 * Return a clone of this object
00152 */
00153 MessageAuthenticationCode* CMAC::clone() const
00154    {
00155    return new CMAC(m_cipher->clone());
00156    }
00157 
00158 /*
00159 * CMAC Constructor
00160 */
00161 CMAC::CMAC(BlockCipher* cipher) : m_cipher(cipher)
00162    {
00163    if(m_cipher->block_size() !=  8 && m_cipher->block_size() != 16 &&
00164       m_cipher->block_size() != 32 && m_cipher->block_size() != 64)
00165       {
00166       throw Invalid_Argument("CMAC cannot use the " +
00167                              std::to_string(m_cipher->block_size() * 8) +
00168                              " bit cipher " + m_cipher->name());
00169       }
00170 
00171    m_state.resize(output_length());
00172    m_buffer.resize(output_length());
00173    m_B.resize(output_length());
00174    m_P.resize(output_length());
00175    m_position = 0;
00176    }
00177 
00178 }