Crypto++
|
00001 // cmac.cpp - written and placed in the public domain by Wei Dai 00002 00003 #include "pch.h" 00004 00005 #ifndef CRYPTOPP_IMPORTS 00006 00007 #include "cmac.h" 00008 00009 NAMESPACE_BEGIN(CryptoPP) 00010 00011 static void MulU(byte *k, unsigned int length) 00012 { 00013 byte carry = 0; 00014 00015 for (int i=length-1; i>=1; i-=2) 00016 { 00017 byte carry2 = k[i] >> 7; 00018 k[i] += k[i] + carry; 00019 carry = k[i-1] >> 7; 00020 k[i-1] += k[i-1] + carry2; 00021 } 00022 00023 if (carry) 00024 { 00025 switch (length) 00026 { 00027 case 8: 00028 k[7] ^= 0x1b; 00029 break; 00030 case 16: 00031 k[15] ^= 0x87; 00032 break; 00033 case 32: 00034 k[30] ^= 4; 00035 k[31] ^= 0x23; 00036 break; 00037 default: 00038 throw InvalidArgument("CMAC: " + IntToString(length) + " is not a supported cipher block size"); 00039 } 00040 } 00041 } 00042 00043 void CMAC_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) 00044 { 00045 BlockCipher &cipher = AccessCipher(); 00046 unsigned int blockSize = cipher.BlockSize(); 00047 00048 cipher.SetKey(key, length, params); 00049 m_reg.CleanNew(3*blockSize); 00050 m_counter = 0; 00051 00052 cipher.ProcessBlock(m_reg, m_reg+blockSize); 00053 MulU(m_reg+blockSize, blockSize); 00054 memcpy(m_reg+2*blockSize, m_reg+blockSize, blockSize); 00055 MulU(m_reg+2*blockSize, blockSize); 00056 } 00057 00058 void CMAC_Base::Update(const byte *input, size_t length) 00059 { 00060 if (!length) 00061 return; 00062 00063 BlockCipher &cipher = AccessCipher(); 00064 unsigned int blockSize = cipher.BlockSize(); 00065 00066 if (m_counter > 0) 00067 { 00068 unsigned int len = UnsignedMin(blockSize - m_counter, length); 00069 xorbuf(m_reg+m_counter, input, len); 00070 length -= len; 00071 input += len; 00072 m_counter += len; 00073 00074 if (m_counter == blockSize && length > 0) 00075 { 00076 cipher.ProcessBlock(m_reg); 00077 m_counter = 0; 00078 } 00079 } 00080 00081 if (length > blockSize) 00082 { 00083 assert(m_counter == 0); 00084 size_t leftOver = 1 + cipher.AdvancedProcessBlocks(m_reg, input, m_reg, length-1, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput); 00085 input += (length - leftOver); 00086 length = leftOver; 00087 } 00088 00089 if (length > 0) 00090 { 00091 assert(m_counter + length <= blockSize); 00092 xorbuf(m_reg+m_counter, input, length); 00093 m_counter += (unsigned int)length; 00094 } 00095 00096 assert(m_counter > 0); 00097 } 00098 00099 void CMAC_Base::TruncatedFinal(byte *mac, size_t size) 00100 { 00101 ThrowIfInvalidTruncatedSize(size); 00102 00103 BlockCipher &cipher = AccessCipher(); 00104 unsigned int blockSize = cipher.BlockSize(); 00105 00106 if (m_counter < blockSize) 00107 { 00108 m_reg[m_counter] ^= 0x80; 00109 cipher.AdvancedProcessBlocks(m_reg, m_reg+2*blockSize, m_reg, blockSize, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput); 00110 } 00111 else 00112 cipher.AdvancedProcessBlocks(m_reg, m_reg+blockSize, m_reg, blockSize, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput); 00113 00114 memcpy(mac, m_reg, size); 00115 00116 m_counter = 0; 00117 memset(m_reg, 0, blockSize); 00118 } 00119 00120 NAMESPACE_END 00121 00122 #endif