00001
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 assert((input && length) || !(input || length));
00061 if (!length)
00062 return;
00063
00064 BlockCipher &cipher = AccessCipher();
00065 unsigned int blockSize = cipher.BlockSize();
00066
00067 if (m_counter > 0)
00068 {
00069 const unsigned int len = UnsignedMin(blockSize - m_counter, length);
00070 if (len)
00071 {
00072 xorbuf(m_reg+m_counter, input, len);
00073 length -= len;
00074 input += len;
00075 m_counter += len;
00076 }
00077
00078 if (m_counter == blockSize && length > 0)
00079 {
00080 cipher.ProcessBlock(m_reg);
00081 m_counter = 0;
00082 }
00083 }
00084
00085 if (length > blockSize)
00086 {
00087 assert(m_counter == 0);
00088 size_t leftOver = 1 + cipher.AdvancedProcessBlocks(m_reg, input, m_reg, length-1, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput);
00089 input += (length - leftOver);
00090 length = leftOver;
00091 }
00092
00093 if (length > 0)
00094 {
00095 assert(m_counter + length <= blockSize);
00096 xorbuf(m_reg+m_counter, input, length);
00097 m_counter += (unsigned int)length;
00098 }
00099
00100 assert(m_counter > 0);
00101 }
00102
00103 void CMAC_Base::TruncatedFinal(byte *mac, size_t size)
00104 {
00105 ThrowIfInvalidTruncatedSize(size);
00106
00107 BlockCipher &cipher = AccessCipher();
00108 unsigned int blockSize = cipher.BlockSize();
00109
00110 if (m_counter < blockSize)
00111 {
00112 m_reg[m_counter] ^= 0x80;
00113 cipher.AdvancedProcessBlocks(m_reg, m_reg+2*blockSize, m_reg, blockSize, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput);
00114 }
00115 else
00116 cipher.AdvancedProcessBlocks(m_reg, m_reg+blockSize, m_reg, blockSize, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput);
00117
00118 memcpy(mac, m_reg, size);
00119
00120 m_counter = 0;
00121 memset(m_reg, 0, blockSize);
00122 }
00123
00124 NAMESPACE_END
00125
00126 #endif