1// cmac.cpp - written and placed in the public domain by Wei Dai 2 3#include "pch.h" 4 5#ifndef CRYPTOPP_IMPORTS 6 7#include "cmac.h" 8 9NAMESPACE_BEGIN(CryptoPP) 10 11static void MulU(byte *k, unsigned int length) 12{ 13 byte carry = 0; 14 15 for (int i=length-1; i>=1; i-=2) 16 { 17 byte carry2 = k[i] >> 7; 18 k[i] += k[i] + carry; 19 carry = k[i-1] >> 7; 20 k[i-1] += k[i-1] + carry2; 21 } 22 23 if (carry) 24 { 25 switch (length) 26 { 27 case 8: 28 k[7] ^= 0x1b; 29 break; 30 case 16: 31 k[15] ^= 0x87; 32 break; 33 case 32: 34 k[30] ^= 4; 35 k[31] ^= 0x23; 36 break; 37 default: 38 throw InvalidArgument("CMAC: " + IntToString(length) + " is not a supported cipher block size"); 39 } 40 } 41} 42 43void CMAC_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) 44{ 45 BlockCipher &cipher = AccessCipher(); 46 unsigned int blockSize = cipher.BlockSize(); 47 48 cipher.SetKey(key, length, params); 49 m_reg.CleanNew(3*blockSize); 50 m_counter = 0; 51 52 cipher.ProcessBlock(m_reg, m_reg+blockSize); 53 MulU(m_reg+blockSize, blockSize); 54 memcpy(m_reg+2*blockSize, m_reg+blockSize, blockSize); 55 MulU(m_reg+2*blockSize, blockSize); 56} 57 58void CMAC_Base::Update(const byte *input, size_t length) 59{ 60 if (!length) 61 return; 62 63 BlockCipher &cipher = AccessCipher(); 64 unsigned int blockSize = cipher.BlockSize(); 65 66 if (m_counter > 0) 67 { 68 unsigned int len = UnsignedMin(blockSize - m_counter, length); 69 xorbuf(m_reg+m_counter, input, len); 70 length -= len; 71 input += len; 72 m_counter += len; 73 74 if (m_counter == blockSize && length > 0) 75 { 76 cipher.ProcessBlock(m_reg); 77 m_counter = 0; 78 } 79 } 80 81 if (length > blockSize) 82 { 83 assert(m_counter == 0); 84 size_t leftOver = 1 + cipher.AdvancedProcessBlocks(m_reg, input, m_reg, length-1, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput); 85 input += (length - leftOver); 86 length = leftOver; 87 } 88 89 if (length > 0) 90 { 91 assert(m_counter + length <= blockSize); 92 xorbuf(m_reg+m_counter, input, length); 93 m_counter += (unsigned int)length; 94 } 95 96 assert(m_counter > 0); 97} 98 99void CMAC_Base::TruncatedFinal(byte *mac, size_t size) 100{ 101 ThrowIfInvalidTruncatedSize(size); 102 103 BlockCipher &cipher = AccessCipher(); 104 unsigned int blockSize = cipher.BlockSize(); 105 106 if (m_counter < blockSize) 107 { 108 m_reg[m_counter] ^= 0x80; 109 cipher.AdvancedProcessBlocks(m_reg, m_reg+2*blockSize, m_reg, blockSize, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput); 110 } 111 else 112 cipher.AdvancedProcessBlocks(m_reg, m_reg+blockSize, m_reg, blockSize, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput); 113 114 memcpy(mac, m_reg, size); 115 116 m_counter = 0; 117 memset(m_reg, 0, blockSize); 118} 119 120NAMESPACE_END 121 122#endif 123