QCA

aes-cmac.cpp
1 /*
2  Copyright (C) 2006 Brad Hards <[email protected]>
3 
4  Permission is hereby granted, free of charge, to any person obtaining a copy
5  of this software and associated documentation files (the "Software"), to deal
6  in the Software without restriction, including without limitation the rights
7  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  copies of the Software, and to permit persons to whom the Software is
9  furnished to do so, subject to the following conditions:
10 
11  The above copyright notice and this permission notice shall be included in
12  all copies or substantial portions of the Software.
13 
14  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21 
22 // QtCrypto has the declarations for all of QCA
23 #include <QtCrypto>
24 
25 #include <QCoreApplication>
26 #include <QDebug>
27 
28 #ifdef QT_STATICPLUGIN
29 #include "import_plugins.h"
30 #endif
31 
32 class AESCMACContext : public QCA::MACContext
33 {
34  Q_OBJECT
35 public:
36  AESCMACContext(QCA::Provider *p)
37  : QCA::MACContext(p, QStringLiteral("cmac(aes)"))
38  {
39  }
40 
41  // Helper to left shift an arbitrary length array
42  // This is heavily based on the example in the I-D.
43  QCA::SecureArray leftShift(const QCA::SecureArray &array)
44  {
45  // We create an output of the same size as the input
46  QCA::SecureArray out(array.size());
47  // We handle one byte at a time - this is the high bit
48  // from the previous byte.
49  int overflow = 0;
50 
51  // work through each byte.
52  for (int i = array.size() - 1; i >= 0; --i) {
53  // do the left shift on this byte.
54  out[i] = array[i] << 1;
55  // make the low bit on this byte be the high bit
56  // from the previous byte.
57  out[i] |= overflow;
58  // save the high bit for next time
59  overflow = (array[i] & 0x80) ? 1 : 0;
60  }
61  return out;
62  }
63 
64  // Helper to XOR two arrays - must be same length
65  QCA::SecureArray xorArray(const QCA::SecureArray &array1, const QCA::SecureArray &array2)
66  {
67  if (array1.size() != array2.size())
68  // empty array
69  return QCA::SecureArray();
70 
71  QCA::SecureArray result(array1.size());
72 
73  for (int i = 0; i < array1.size(); ++i)
74  result[i] = array1[i] ^ array2[i];
75 
76  return result;
77  }
78 
79  void setup(const QCA::SymmetricKey &key) override
80  {
81  // We might not have a real key, since this can get called
82  // from the constructor.
83  if (key.size() == 0)
84  return;
85 
86  m_key = key;
87  // Generate the subkeys
88  QCA::SecureArray const_Zero(16);
89  QCA::SecureArray const_Rb(16);
90  const_Rb[15] = (char)0x87;
91 
92  m_X = const_Zero;
93  m_residual = QCA::SecureArray();
94 
95  // Figure 2.2, step 1.
96  QCA::Cipher aesObj(QStringLiteral("aes128"), QCA::Cipher::ECB, QCA::Cipher::DefaultPadding, QCA::Encode, key);
97  QCA::SecureArray L = aesObj.process(const_Zero);
98 
99  // Figure 2.2, step 2
100  if (0 == (L[0] & 0x80))
101  m_k1 = leftShift(L);
102  else
103  m_k1 = xorArray(leftShift(L), const_Rb);
104 
105  // Figure 2.2, step 3
106  if (0 == (m_k1[0] & 0x80))
107  m_k2 = leftShift(m_k1);
108  else
109  m_k2 = xorArray(leftShift(m_k1), const_Rb);
110  }
111 
112  QCA::Provider::Context *clone() const override
113  {
114  return new AESCMACContext(*this);
115  }
116 
117  void clear()
118  {
119  setup(m_key);
120  }
121 
122  QCA::KeyLength keyLength() const override
123  {
124  return QCA::KeyLength(16, 16, 1);
125  }
126 
127  // This is a bit different to the way the I-D does it,
128  // to allow for multiple update() calls.
129  void update(const QCA::MemoryRegion &a) override
130  {
131  QCA::SecureArray bytesToProcess = m_residual + a;
132  int blockNum;
133  // note that we don't want to do the last full block here, because
134  // it needs special treatment in final().
135  for (blockNum = 0; blockNum < ((bytesToProcess.size() - 1) / 16); ++blockNum) {
136  // copy a block of data
137  QCA::SecureArray thisBlock(16);
138  for (int yalv = 0; yalv < 16; ++yalv)
139  thisBlock[yalv] = bytesToProcess[blockNum * 16 + yalv];
140 
141  m_Y = xorArray(m_X, thisBlock);
142 
143  QCA::Cipher aesObj(
144  QStringLiteral("aes128"), QCA::Cipher::ECB, QCA::Cipher::DefaultPadding, QCA::Encode, m_key);
145  m_X = aesObj.process(m_Y);
146  }
147  // This can be between 1 and 16
148  int numBytesLeft = bytesToProcess.size() - 16 * blockNum;
149  // we copy the left over part
150  m_residual.resize(numBytesLeft);
151  for (int yalv = 0; yalv < numBytesLeft; ++yalv)
152  m_residual[yalv] = bytesToProcess[blockNum * 16 + yalv];
153  }
154 
155  void final(QCA::MemoryRegion *out) override
156  {
157  QCA::SecureArray lastBlock;
158  int numBytesLeft = m_residual.size();
159 
160  if (numBytesLeft != 16) {
161  // no full block, so we have to pad.
162  m_residual.resize(16);
163  m_residual[numBytesLeft] = (char)0x80;
164  lastBlock = xorArray(m_residual, m_k2);
165  } else {
166  // this is a full block - no padding
167  lastBlock = xorArray(m_residual, m_k1);
168  }
169  m_Y = xorArray(m_X, lastBlock);
170  QCA::Cipher aesObj(QStringLiteral("aes128"), QCA::Cipher::ECB, QCA::Cipher::DefaultPadding, QCA::Encode, m_key);
171  *out = aesObj.process(m_Y);
172  }
173 
174 protected:
175  // first subkey
176  QCA::SecureArray m_k1;
177  // second subkey
178  QCA::SecureArray m_k2;
179  // main key
180  QCA::SecureArray m_key;
181 
182  // state
183  QCA::SecureArray m_X;
184  QCA::SecureArray m_Y;
185 
186  // partial block that we can't do yet
187  QCA::SecureArray m_residual;
188 };
189 
190 class ClientSideProvider : public QCA::Provider
191 {
192 public:
193  int qcaVersion() const override
194  {
195  return QCA_VERSION;
196  }
197 
198  QString name() const override
199  {
200  return QStringLiteral("exampleClientSideProvider");
201  }
202 
203  QStringList features() const override
204  {
206  list += QStringLiteral("cmac(aes)");
207  // you can add more features in here, if you have some.
208  return list;
209  }
210 
211  Provider::Context *createContext(const QString &type) override
212  {
213  if (type == QLatin1String("cmac(aes)"))
214  return new AESCMACContext(this);
215  // else if (type == some other feature)
216  // return some other context.
217  else
218  return nullptr;
219  }
220 };
221 
222 // AES CMAC is a Message Authentication Code based on a block cipher
223 // instead of the more normal keyed hash.
224 // See RFC 4493 "The AES-CMAC Algorithm"
225 class AES_CMAC : public QCA::MessageAuthenticationCode
226 {
227 public:
228  AES_CMAC(const QCA::SymmetricKey &key = QCA::SymmetricKey(), const QString &provider = QString())
229  : QCA::MessageAuthenticationCode(QStringLiteral("cmac(aes)"), key, provider)
230  {
231  }
232 };
233 
234 int main(int argc, char **argv)
235 {
236  // the Initializer object sets things up, and
237  // also does cleanup when it goes out of scope
239 
240  qDebug() << "This example shows AES CMAC";
241 
242  QCoreApplication app(argc, argv);
243 
244  if (!QCA::isSupported("aes128-ecb")) {
245  qDebug() << "AES not supported!";
246  }
247 
248  if (QCA::insertProvider(new ClientSideProvider, 0))
249  qDebug() << "Inserted our provider";
250  else
251  qDebug() << "our provider could not be added";
252 
253  // We should check AES CMAC is supported before using it.
254  if (!QCA::isSupported("cmac(aes)")) {
255  qDebug() << "AES CMAC not supported!";
256  } else {
257  // create the required object
258  AES_CMAC cmacObject;
259 
260  // create the key
261  QCA::SymmetricKey key(QCA::hexToArray(QStringLiteral("2b7e151628aed2a6abf7158809cf4f3c")));
262 
263  // set the MAC to use the key
264  cmacObject.setup(key);
265 
267  QCA::hexToArray(QStringLiteral("6bc1bee22e409f96e93d7e117393172a"
268  "ae2d8a571e03ac9c9eb76fac45af8e51"
269  "30c81c46a35ce411e5fbc1191a0a52ef"
270  "f69f2445df4f9b17ad2b417be66c3710"));
271  QCA::SecureArray message1(message);
272  message1.resize(0);
273  qDebug();
274  qDebug() << "Message1: " << QCA::arrayToHex(message1.toByteArray());
275  qDebug() << "Expecting: bb1d6929e95937287fa37d129b756746";
276  qDebug() << "AES-CMAC: " << QCA::arrayToHex(cmacObject.process(message1).toByteArray());
277 
278  cmacObject.clear();
279  QCA::SecureArray message2(message);
280  message2.resize(16);
281  qDebug();
282  qDebug() << "Message2: " << QCA::arrayToHex(message2.toByteArray());
283  qDebug() << "Expecting: 070a16b46b4d4144f79bdd9dd04a287c";
284  qDebug() << "AES-CMAC: " << QCA::arrayToHex(cmacObject.process(message2).toByteArray());
285 
286  cmacObject.clear();
287  QCA::SecureArray message3(message);
288  message3.resize(40);
289  qDebug();
290  qDebug() << "Message3: " << QCA::arrayToHex(message3.toByteArray());
291  qDebug() << "Expecting: dfa66747de9ae63030ca32611497c827";
292  qDebug() << "AES-CMAC " << QCA::arrayToHex(cmacObject.process(message3).toByteArray());
293 
294  cmacObject.clear();
295  QCA::SecureArray message4(message);
296  message4.resize(64);
297  qDebug();
298  qDebug() << "Message4: " << QCA::arrayToHex(message4.toByteArray());
299  qDebug() << "Expecting: 51f0bebf7e3b9d92fc49741779363cfe";
300  qDebug() << "AES-CMAC: " << QCA::arrayToHex(cmacObject.process(message4).toByteArray());
301  }
302 
303  return 0;
304 }
305 
306 #include "aes-cmac.moc"
KCOREADDONS_EXPORT void message(KMessage::MessageType messageType, const QString &text, const QString &caption=QString())
Message authentication code provider.
Definition: qcaprovider.h:297
QString name(const QVariant &location)
General class for cipher (encryption / decryption) algorithms.
Definition: qca_basic.h:581
Algorithm provider.
Definition: qca_core.h:764
Container for keys for symmetric encryption algorithms.
Definition: qca_core.h:1263
General class for message authentication code (MAC) algorithms.
Definition: qca_basic.h:827
Simple container for acceptable key lengths.
Definition: qca_core.h:700
QCA_EXPORT bool isSupported(const char *features, const QString &provider=QString())
Test if a capability (algorithm) is available.
Default for cipher-mode.
Definition: qca_basic.h:610
operate in Electronic Code Book mode
Definition: qca_basic.h:595
QCA_EXPORT bool insertProvider(Provider *p, int priority=0)
Add a provider to the current list of providers.
QCA - the Qt Cryptographic Architecture.
Definition: qca_basic.h:41
QCA_EXPORT QString arrayToHex(const QByteArray &array)
Convert a byte array to printable hexadecimal representation.
QCA_EXPORT void init()
Initialise QCA.
Secure array of bytes.
Definition: qca_tools.h:316
QCA_EXPORT QByteArray hexToArray(const QString &hexString)
Convert a QString containing a hexadecimal representation of a byte array into a QByteArray.
MACContext(Provider *p, const QString &type)
Standard constructor.
Definition: qcaprovider.h:306
virtual KeyLength keyLength() const =0
Returns the KeyLength for this MAC algorithm.
QCA_EXPORT int qcaVersion()
The current version of QCA.
Operate in the "forward" direction; for example, encrypting.
Definition: qca_core.h:142
virtual void setup(const SymmetricKey &key)=0
Set up the object for hashing.
Convenience method for initialising and cleaning up QCA.
Definition: qca_core.h:659
Internal context class used for the plugin.
virtual void update(const MemoryRegion &in)=0
Process a chunk of data.
int size() const
Returns the number of bytes in the array.
Array of bytes that may be optionally secured.
Definition: qca_tools.h:90
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Sep 25 2021 23:05:35 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.