/* * CMAC * (C) 1999-2007 Jack Lloyd * * Distributed under the terms of the Botan license */ #include #include namespace Botan { /* * Perform CMAC's multiplication in GF(2^n) */ SecureVector CMAC::poly_double(const MemoryRegion& in, byte polynomial) { const bool do_xor = (in[0] & 0x80) ? true : false; SecureVector out = in; byte carry = 0; for(u32bit j = out.size(); j != 0; --j) { byte temp = out[j-1]; out[j-1] = (temp << 1) | carry; carry = (temp >> 7); } if(do_xor) out[out.size()-1] ^= polynomial; return out; } /* * Update an CMAC Calculation */ void CMAC::add_data(const byte input[], u32bit length) { buffer.copy(position, input, length); if(position + length > OUTPUT_LENGTH) { xor_buf(state, buffer, OUTPUT_LENGTH); e->encrypt(state); input += (OUTPUT_LENGTH - position); length -= (OUTPUT_LENGTH - position); while(length > OUTPUT_LENGTH) { xor_buf(state, input, OUTPUT_LENGTH); e->encrypt(state); input += OUTPUT_LENGTH; length -= OUTPUT_LENGTH; } buffer.copy(input, length); position = 0; } position += length; } /* * Finalize an CMAC Calculation */ void CMAC::final_result(byte mac[]) { xor_buf(state, buffer, position); if(position == OUTPUT_LENGTH) { xor_buf(state, B, OUTPUT_LENGTH); } else { state[position] ^= 0x80; xor_buf(state, P, OUTPUT_LENGTH); } e->encrypt(state); for(u32bit j = 0; j != OUTPUT_LENGTH; ++j) mac[j] = state[j]; zeroise(state); zeroise(buffer); position = 0; } /* * CMAC Key Schedule */ void CMAC::key_schedule(const byte key[], u32bit length) { clear(); e->set_key(key, length); e->encrypt(B); B = poly_double(B, polynomial); P = poly_double(B, polynomial); } /* * Clear memory of sensitive data */ void CMAC::clear() { e->clear(); zeroise(state); zeroise(buffer); zeroise(B); zeroise(P); position = 0; } /* * Return the name of this type */ std::string CMAC::name() const { return "CMAC(" + e->name() + ")"; } /* * Return a clone of this object */ MessageAuthenticationCode* CMAC::clone() const { return new CMAC(e->clone()); } /* * CMAC Constructor */ CMAC::CMAC(BlockCipher* e_in) : MessageAuthenticationCode(e_in->BLOCK_SIZE, e_in->MINIMUM_KEYLENGTH, e_in->MAXIMUM_KEYLENGTH, e_in->KEYLENGTH_MULTIPLE), e(e_in) { if(e->BLOCK_SIZE == 16) polynomial = 0x87; else if(e->BLOCK_SIZE == 8) polynomial = 0x1B; else throw Invalid_Argument("CMAC cannot use the cipher " + e->name()); state.resize(OUTPUT_LENGTH); buffer.resize(OUTPUT_LENGTH); B.resize(OUTPUT_LENGTH); P.resize(OUTPUT_LENGTH); position = 0; } /* * CMAC Destructor */ CMAC::~CMAC() { delete e; } }