Crypto++  5.6.5
Free C++ class library of cryptographic schemes
cmac.cpp
1 // cmac.cpp - originally 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  // https://crypto.stackexchange.com/q/9815/10496
35  // Polynomial x^256 + x^10 + x^5 + x + 1
36  k[30] ^= 4;
37  k[31] ^= 0x23;
38  break;
39  case 64:
40  // https://crypto.stackexchange.com/q/9815/10496
41  // Polynomial x^512 + x^8 + x^5 + x^2 + 1
42  k[62] ^= 1;
43  k[63] ^= 0x25;
44  break;
45  case 128:
46  // https://crypto.stackexchange.com/q/9815/10496
47  // Polynomial x^1024 + x^19 + x^6 + x + 1
48  k[125] ^= 8;
49  k[126] ^= 0x00;
50  k[127] ^= 0x43;
51  break;
52  default:
53  throw InvalidArgument("CMAC: " + IntToString(length) + " is not a supported cipher block size");
54  }
55  }
56 }
57 
58 void CMAC_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params)
59 {
60  BlockCipher &cipher = AccessCipher();
61  cipher.SetKey(key, length, params);
62 
63  unsigned int blockSize = cipher.BlockSize();
64  m_reg.CleanNew(3*blockSize);
65  m_counter = 0;
66 
67  cipher.ProcessBlock(m_reg, m_reg+blockSize);
68  MulU(m_reg+blockSize, blockSize);
69  memcpy(m_reg+2*blockSize, m_reg+blockSize, blockSize);
70  MulU(m_reg+2*blockSize, blockSize);
71 }
72 
73 void CMAC_Base::Update(const byte *input, size_t length)
74 {
75  CRYPTOPP_ASSERT((input && length) || !(input || length));
76  if (!length)
77  return;
78 
79  BlockCipher &cipher = AccessCipher();
80  unsigned int blockSize = cipher.BlockSize();
81 
82  if (m_counter > 0)
83  {
84  const unsigned int len = UnsignedMin(blockSize - m_counter, length);
85  if (len)
86  {
87  xorbuf(m_reg+m_counter, input, len);
88  length -= len;
89  input += len;
90  m_counter += len;
91  }
92 
93  if (m_counter == blockSize && length > 0)
94  {
95  cipher.ProcessBlock(m_reg);
96  m_counter = 0;
97  }
98  }
99 
100  if (length > blockSize)
101  {
102  CRYPTOPP_ASSERT(m_counter == 0);
103  size_t leftOver = 1 + cipher.AdvancedProcessBlocks(m_reg, input, m_reg, length-1, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput);
104  input += (length - leftOver);
105  length = leftOver;
106  }
107 
108  if (length > 0)
109  {
110  CRYPTOPP_ASSERT(m_counter + length <= blockSize);
111  xorbuf(m_reg+m_counter, input, length);
112  m_counter += (unsigned int)length;
113  }
114 
115  CRYPTOPP_ASSERT(m_counter > 0);
116 }
117 
118 void CMAC_Base::TruncatedFinal(byte *mac, size_t size)
119 {
120  ThrowIfInvalidTruncatedSize(size);
121 
122  BlockCipher &cipher = AccessCipher();
123  unsigned int blockSize = cipher.BlockSize();
124 
125  if (m_counter < blockSize)
126  {
127  m_reg[m_counter] ^= 0x80;
128  cipher.AdvancedProcessBlocks(m_reg, m_reg+2*blockSize, m_reg, blockSize, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput);
129  }
130  else
131  cipher.AdvancedProcessBlocks(m_reg, m_reg+blockSize, m_reg, blockSize, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput);
132 
133  memcpy(mac, m_reg, size);
134 
135  m_counter = 0;
136  memset(m_reg, 0, blockSize);
137 }
138 
139 NAMESPACE_END
140 
141 #endif
An invalid argument was detected.
Definition: cryptlib.h:194
virtual void SetKey(const byte *key, size_t length, const NameValuePairs &params=g_nullNameValuePairs)
Sets or reset the key of this object.
Definition: cryptlib.cpp:71
void CleanNew(size_type newSize)
Change size without preserving contents.
Definition: secblock.h:732
should not modify block pointers
Definition: cryptlib.h:802
Classes for CMAC message authentication code.
Interface for one direction (encryption or decryption) of a block cipher.
Definition: cryptlib.h:1099
virtual unsigned int BlockSize() const =0
Provides the block size of the cipher.
virtual size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const
Encrypt and xor multiple blocks using additional flags.
Definition: cryptlib.cpp:152
void ProcessBlock(const byte *inBlock, byte *outBlock) const
Encrypt or decrypt a block.
Definition: cryptlib.h:764
void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params)
Sets the key for this object without performing parameter validation.
Definition: cmac.cpp:58
const T1 UnsignedMin(const T1 &a, const T2 &b)
Safe comparison of values that could be neagtive and incorrectly promoted.
Definition: misc.h:552
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:60
void xorbuf(byte *buf, const byte *mask, size_t count)
Performs an XOR of a buffer with a mask.
Definition: misc.cpp:28
std::string IntToString(T value, unsigned int base=10)
Converts a value to a string.
Definition: misc.h:582
void TruncatedFinal(byte *mac, size_t size)
Computes the hash of the current message.
Definition: cmac.cpp:118
Crypto++ library namespace.
void Update(const byte *input, size_t length)
Updates a hash with additional input.
Definition: cmac.cpp:73
Interface for retrieving values given their names.
Definition: cryptlib.h:285