1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
// cmac.cpp - originally written and placed in the public domain by Wei Dai
#include "pch.h"
#ifndef CRYPTOPP_IMPORTS
#include "cmac.h"
#include "misc.h"
ANONYMOUS_NAMESPACE_BEGIN
using CryptoPP::byte;
using CryptoPP::IsPowerOf2;
void MulU(byte *k, unsigned int len)
{
byte carry = 0;
for (int i=len-1; i>=1; i-=2)
{
byte carry2 = k[i] >> 7;
k[i] += k[i] + carry;
carry = k[i-1] >> 7;
k[i-1] += k[i-1] + carry2;
}
#ifndef CRYPTOPP_CMAC_WIDE_BLOCK_CIPHERS
CRYPTOPP_ASSERT(len == 16);
if (carry)
{
k[15] ^= 0x87;
return;
}
#else
CRYPTOPP_ASSERT(IsPowerOf2(len));
CRYPTOPP_ASSERT(len >= 8);
CRYPTOPP_ASSERT(len <= 128);
if (carry)
{
switch (len)
{
case 8:
k[7] ^= 0x1b;
break;
case 16:
k[15] ^= 0x87;
break;
case 32:
// https://crypto.stackexchange.com/q/9815/10496
// Polynomial x^256 + x^10 + x^5 + x^2 + 1
k[30] ^= 4;
k[31] ^= 0x25;
break;
case 64:
// https://crypto.stackexchange.com/q/9815/10496
// Polynomial x^512 + x^8 + x^5 + x^2 + 1
k[62] ^= 1;
k[63] ^= 0x25;
break;
case 128:
// https://crypto.stackexchange.com/q/9815/10496
// Polynomial x^1024 + x^19 + x^6 + x + 1
k[125] ^= 8;
k[126] ^= 0x00;
k[127] ^= 0x43;
break;
default:
CRYPTOPP_ASSERT(0);
}
}
#endif // CRYPTOPP_CMAC_WIDE_BLOCK_CIPHERS
}
ANONYMOUS_NAMESPACE_END
NAMESPACE_BEGIN(CryptoPP)
void CMAC_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms)
{
BlockCipher &cipher = AccessCipher();
cipher.SetKey(key, length, params);
unsigned int blockSize = cipher.BlockSize();
m_reg.CleanNew(3*blockSize);
m_counter = 0;
cipher.ProcessBlock(m_reg, m_reg+blockSize);
MulU(m_reg+blockSize, blockSize);
std::memcpy(m_reg+2*blockSize, m_reg+blockSize, blockSize);
MulU(m_reg+2*blockSize, blockSize);
}
void CMAC_Base::Update(const byte *input, size_t length)
{
CRYPTOPP_ASSERT((input && length) || !(input || length));
if (!length)
return;
BlockCipher &cipher = AccessCipher();
unsigned int blockSize = cipher.BlockSize();
if (m_counter > 0)
{
const unsigned int len = UnsignedMin(blockSize - m_counter, length);
if (len)
{
xorbuf(m_reg+m_counter, input, len);
length -= len;
input += len;
m_counter += len;
}
if (m_counter == blockSize && length > 0)
{
cipher.ProcessBlock(m_reg);
m_counter = 0;
}
}
if (length > blockSize)
{
CRYPTOPP_ASSERT(m_counter == 0);
size_t leftOver = 1 + cipher.AdvancedProcessBlocks(m_reg, input, m_reg, length-1, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput);
input += (length - leftOver);
length = leftOver;
}
if (length > 0)
{
CRYPTOPP_ASSERT(m_counter + length <= blockSize);
xorbuf(m_reg+m_counter, input, length);
m_counter += (unsigned int)length;
}
CRYPTOPP_ASSERT(m_counter > 0);
}
void CMAC_Base::TruncatedFinal(byte *mac, size_t size)
{
ThrowIfInvalidTruncatedSize(size);
BlockCipher &cipher = AccessCipher();
unsigned int blockSize = cipher.BlockSize();
if (m_counter < blockSize)
{
m_reg[m_counter] ^= 0x80;
cipher.AdvancedProcessBlocks(m_reg, m_reg+2*blockSize, m_reg, blockSize, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput);
}
else
cipher.AdvancedProcessBlocks(m_reg, m_reg+blockSize, m_reg, blockSize, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput);
// UBsan finding
if (mac)
std::memcpy(mac, m_reg, size);
m_counter = 0;
std::memset(m_reg, 0, blockSize);
}
NAMESPACE_END
#endif
|