Crypto++
cmac.cpp
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 
9 NAMESPACE_BEGIN(CryptoPP)
10 
11 static 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 
43 void CMAC_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params)
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 
58 void 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 
99 void 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 
120 NAMESPACE_END
121 
122 #endif