1*993229b6Sjkunz /*
2*993229b6Sjkunz * File: RijndaelCBCMAC.cpp
3*993229b6Sjkunz *
4*993229b6Sjkunz * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5*993229b6Sjkunz * See included license file for license details.
6*993229b6Sjkunz */
7*993229b6Sjkunz
8*993229b6Sjkunz #include "RijndaelCBCMAC.h"
9*993229b6Sjkunz #include "rijndael.h"
10*993229b6Sjkunz #include <assert.h>
11*993229b6Sjkunz #include "Logging.h"
12*993229b6Sjkunz
13*993229b6Sjkunz void logHexArray(Logger::log_level_t level, const uint8_t * bytes, unsigned count);
14*993229b6Sjkunz
15*993229b6Sjkunz //! \param key The key to use as the CBC-MAC secret.
16*993229b6Sjkunz //! \param iv Initialization vector. Defaults to zero if not provided.
RijndaelCBCMAC(const AESKey<128> & key,const uint8_t * iv)17*993229b6Sjkunz RijndaelCBCMAC::RijndaelCBCMAC(const AESKey<128> & key, const uint8_t * iv)
18*993229b6Sjkunz : m_key(key)
19*993229b6Sjkunz {
20*993229b6Sjkunz if (iv)
21*993229b6Sjkunz {
22*993229b6Sjkunz memcpy(m_mac, iv, sizeof(m_mac));
23*993229b6Sjkunz }
24*993229b6Sjkunz else
25*993229b6Sjkunz {
26*993229b6Sjkunz memset(m_mac, 0, sizeof(m_mac));
27*993229b6Sjkunz }
28*993229b6Sjkunz }
29*993229b6Sjkunz
30*993229b6Sjkunz //! \param data Pointer to data to process.
31*993229b6Sjkunz //! \param length Number of bytes to process. Must be evenly divisible by #BLOCK_SIZE.
update(const uint8_t * data,unsigned length)32*993229b6Sjkunz void RijndaelCBCMAC::update(const uint8_t * data, unsigned length)
33*993229b6Sjkunz {
34*993229b6Sjkunz assert(length % BLOCK_SIZE == 0);
35*993229b6Sjkunz unsigned blocks = length / BLOCK_SIZE;
36*993229b6Sjkunz while (blocks--)
37*993229b6Sjkunz {
38*993229b6Sjkunz updateOneBlock(data);
39*993229b6Sjkunz data += BLOCK_SIZE;
40*993229b6Sjkunz }
41*993229b6Sjkunz }
42*993229b6Sjkunz
43*993229b6Sjkunz //! It appears that some forms of CBC-MAC encrypt the final output block again in
44*993229b6Sjkunz //! order to protect against a plaintext attack. This method is a placeholder for
45*993229b6Sjkunz //! such an operation, but it currently does nothing.
finalize()46*993229b6Sjkunz void RijndaelCBCMAC::finalize()
47*993229b6Sjkunz {
48*993229b6Sjkunz }
49*993229b6Sjkunz
50*993229b6Sjkunz //! On entry the current value of m_mac becomes the initialization vector
51*993229b6Sjkunz //! for the CBC encryption of this block. The output of the encryption then
52*993229b6Sjkunz //! becomes the new MAC, which is stored in m_mac.
updateOneBlock(const uint8_t * data)53*993229b6Sjkunz void RijndaelCBCMAC::updateOneBlock(const uint8_t * data)
54*993229b6Sjkunz {
55*993229b6Sjkunz Rijndael cipher;
56*993229b6Sjkunz cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_key, Rijndael::Key16Bytes, m_mac);
57*993229b6Sjkunz cipher.blockEncrypt(data, BLOCK_SIZE * 8, m_mac); // size is in bits
58*993229b6Sjkunz
59*993229b6Sjkunz // Log::log(Logger::DEBUG2, "CBC-MAC output block:\n");
60*993229b6Sjkunz // logHexArray(Logger::DEBUG2, (const uint8_t *)&m_mac, sizeof(m_mac));
61*993229b6Sjkunz }
62*993229b6Sjkunz
63*993229b6Sjkunz /*!
64*993229b6Sjkunz * \brief Log an array of bytes as hex.
65*993229b6Sjkunz */
logHexArray(Logger::log_level_t level,const uint8_t * bytes,unsigned count)66*993229b6Sjkunz void logHexArray(Logger::log_level_t level, const uint8_t * bytes, unsigned count)
67*993229b6Sjkunz {
68*993229b6Sjkunz Log::SetOutputLevel leveler(level);
69*993229b6Sjkunz // Log::log(" ");
70*993229b6Sjkunz unsigned i;
71*993229b6Sjkunz for (i = 0; i < count; ++i, ++bytes)
72*993229b6Sjkunz {
73*993229b6Sjkunz if ((i % 16 == 0) && (i < count - 1))
74*993229b6Sjkunz {
75*993229b6Sjkunz if (i != 0)
76*993229b6Sjkunz {
77*993229b6Sjkunz Log::log("\n");
78*993229b6Sjkunz }
79*993229b6Sjkunz Log::log(" 0x%04x: ", i);
80*993229b6Sjkunz }
81*993229b6Sjkunz Log::log("%02x ", *bytes & 0xff);
82*993229b6Sjkunz }
83*993229b6Sjkunz
84*993229b6Sjkunz Log::log("\n");
85*993229b6Sjkunz }
86*993229b6Sjkunz
87