1/*
2 Copyright (C) 2006 Brad Hards <bradh@frogmouth.net>
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
32class AESCMACContext : public QCA::MACContext
33{
34public:
35 AESCMACContext(QCA::Provider *p) : QCA::MACContext(p, "cmac(aes)")
36 {
37 }
38
39 ~AESCMACContext()
40 {
41 }
42
43
44 // Helper to left shift an arbitrary length array
45 // This is heavily based on the example in the I-D.
46 QCA::SecureArray leftShift(const QCA::SecureArray &array)
47 {
48 // We create an output of the same size as the input
49 QCA::SecureArray out(array.size());
50 // We handle one byte at a time - this is the high bit
51 // from the previous byte.
52 int overflow = 0;
53
54 // work through each byte.
55 for (int i = array.size() -1; i >= 0; --i) {
56 // do the left shift on this byte.
57 out[i] = array[i] << 1;
58 // make the low bit on this byte be the high bit
59 // from the previous byte.
60 out[i] |= overflow;
61 // save the high bit for next time
62 overflow = (array[i] & 0x80) ? 1 : 0;
63 }
64 return out;
65 }
66
67
68 // Helper to XOR two arrays - must be same length
69 QCA::SecureArray xorArray(const QCA::SecureArray &array1,
70 const QCA::SecureArray &array2)
71 {
72 if (array1.size() != array2.size())
73 // empty array
74 return QCA::SecureArray();
75
76 QCA::SecureArray result(array1.size());
77
78 for (int i = 0; i < array1.size(); ++i)
79 result[i] = array1[i] ^ array2[i];
80
81 return result;
82 }
83
84
85 void setup(const QCA::SymmetricKey &key)
86 {
87 // We might not have a real key, since this can get called
88 // from the constructor.
89 if (key.size() == 0)
90 return;
91
92 m_key = key;
93 // Generate the subkeys
94 QCA::SecureArray const_Zero(16);
95 QCA::SecureArray const_Rb(16);
96 const_Rb[15] = (char)0x87;
97
98 m_X = const_Zero;
99 m_residual = QCA::SecureArray();
100
101 // Figure 2.2, step 1.
102 QCA::Cipher aesObj(QString("aes128"),
103 QCA::Cipher::ECB, QCA::Cipher::DefaultPadding,
104 QCA::Encode, key);
105 QCA::SecureArray L = aesObj.process(const_Zero);
106
107 // Figure 2.2, step 2
108 if (0 == (L[0] & 0x80))
109 m_k1 = leftShift(L);
110 else
111 m_k1 = xorArray(leftShift(L), const_Rb);
112
113 // Figure 2.2, step 3
114 if (0 == (m_k1[0] & 0x80))
115 m_k2 = leftShift(m_k1);
116 else
117 m_k2 = xorArray(leftShift(m_k1), const_Rb);
118 }
119
120 QCA::Provider::Context *clone() const
121 {
122 return new AESCMACContext(*this);
123 }
124
125 void clear()
126 {
127 setup(m_key);
128 }
129
130 QCA::KeyLength keyLength() const
131 {
132 return QCA::KeyLength(16, 16, 1);
133 }
134
135 // This is a bit different to the way the I-D does it,
136 // to allow for multiple update() calls.
137 void update(const QCA::MemoryRegion &a)
138 {
139 QCA::SecureArray bytesToProcess = m_residual + a;
140 int blockNum;
141 // note that we don't want to do the last full block here, because
142 // it needs special treatment in final().
143 for (blockNum = 0; blockNum < ((bytesToProcess.size()-1)/16); ++blockNum) {
144 // copy a block of data
145 QCA::SecureArray thisBlock(16);
146 for (int yalv = 0; yalv < 16; ++yalv)
147 thisBlock[yalv] = bytesToProcess[blockNum*16 + yalv];
148
149 m_Y = xorArray(m_X, thisBlock);
150
151 QCA::Cipher aesObj(QString("aes128"),
152 QCA::Cipher::ECB, QCA::Cipher::DefaultPadding,
153 QCA::Encode, m_key);
154 m_X = aesObj.process(m_Y);
155 }
156 // This can be between 1 and 16
157 int numBytesLeft = bytesToProcess.size() - 16*blockNum;
158 // we copy the left over part
159 m_residual.resize(numBytesLeft);
160 for(int yalv = 0; yalv < numBytesLeft; ++yalv)
161 m_residual[yalv] = bytesToProcess[blockNum*16 + yalv];
162 }
163
164 void final( QCA::MemoryRegion *out)
165 {
166 QCA::SecureArray lastBlock;
167 int numBytesLeft = m_residual.size();
168
169 if ( numBytesLeft != 16 ) {
170 // no full block, so we have to pad.
171 m_residual.resize(16);
172 m_residual[numBytesLeft] = (char)0x80;
173 lastBlock = xorArray(m_residual, m_k2);
174 } else {
175 // this is a full block - no padding
176 lastBlock = xorArray(m_residual, m_k1);
177 }
178 m_Y = xorArray(m_X, lastBlock);
179 QCA::Cipher aesObj(QString("aes128"),
180 QCA::Cipher::ECB, QCA::Cipher::DefaultPadding,
181 QCA::Encode, m_key);
182 *out = aesObj.process(m_Y);
183
184 }
185
186protected:
187 // first subkey
188 QCA::SecureArray m_k1;
189 // second subkey
190 QCA::SecureArray m_k2;
191 // main key
192 QCA::SecureArray m_key;
193
194 // state
195 QCA::SecureArray m_X;
196 QCA::SecureArray m_Y;
197
198 // partial block that we can't do yet
199 QCA::SecureArray m_residual;
200};
201
202class ClientSideProvider : public QCA::Provider
203{
204public:
205 int qcaVersion() const
206 {
207 return QCA_VERSION;
208 }
209
210 QString name() const
211 {
212 return "exampleClientSideProvider";
213 }
214
215 QStringList features() const
216 {
217 QStringList list;
218 list += "cmac(aes)";
219 // you can add more features in here, if you have some.
220 return list;
221 }
222
223 Provider::Context *createContext(const QString &type)
224 {
225 if(type == "cmac(aes)")
226 return new AESCMACContext(this);
227 // else if (type == some other feature)
228 // return some other context.
229 else
230 return 0;
231 }
232};
233
234
235// AES CMAC is a Message Authentication Code based on a block cipher
236// instead of the more normal keyed hash.
237// See RFC 4493 "The AES-CMAC Algorithm"
238class AES_CMAC: public QCA::MessageAuthenticationCode
239{
240public:
241 AES_CMAC(const QCA::SymmetricKey &key = QCA::SymmetricKey(),
242 const QString &provider = QString()):
243 QCA::MessageAuthenticationCode( "cmac(aes)", key, provider)
244 {}
245};
246
247
248int main(int argc, char **argv)
249{
250 // the Initializer object sets things up, and
251 // also does cleanup when it goes out of scope
252 QCA::Initializer init;
253
254 qDebug() << "This example shows AES CMAC";
255
256 QCoreApplication app(argc, argv);
257
258 if( ! QCA::isSupported("aes128-ecb") ) {
259 qDebug() << "AES not supported!";
260 }
261
262 if ( QCA::insertProvider(new ClientSideProvider, 0) )
263 qDebug() << "Inserted our provider";
264 else
265 qDebug() << "our provider could not be added";
266
267 // We should check AES CMAC is supported before using it.
268 if( ! QCA::isSupported("cmac(aes)") ) {
269 qDebug() << "AES CMAC not supported!";
270 } else {
271 // create the required object
272 AES_CMAC cmacObject;
273
274 // create the key
275 QCA::SymmetricKey key(QCA::hexToArray("2b7e151628aed2a6abf7158809cf4f3c"));
276
277 // set the MAC to use the key
278 cmacObject.setup(key);
279
280 QCA::SecureArray message = QCA::hexToArray("6bc1bee22e409f96e93d7e117393172a"
281 "ae2d8a571e03ac9c9eb76fac45af8e51"
282 "30c81c46a35ce411e5fbc1191a0a52ef"
283 "f69f2445df4f9b17ad2b417be66c3710");
284 QCA::SecureArray message1(message);
285 message1.resize(0);
286 qDebug();
287 qDebug() << "Message1: " << QCA::arrayToHex(message1.toByteArray());
288 qDebug() << "Expecting: bb1d6929e95937287fa37d129b756746";
289 qDebug() << "AES-CMAC: " << QCA::arrayToHex(cmacObject.process(message1).toByteArray());
290
291 cmacObject.clear();
292 QCA::SecureArray message2(message);
293 message2.resize(16);
294 qDebug();
295 qDebug() << "Message2: " << QCA::arrayToHex(message2.toByteArray());
296 qDebug() << "Expecting: 070a16b46b4d4144f79bdd9dd04a287c";
297 qDebug() << "AES-CMAC: " << QCA::arrayToHex(cmacObject.process(message2).toByteArray());
298
299 cmacObject.clear();
300 QCA::SecureArray message3(message);
301 message3.resize(40);
302 qDebug();
303 qDebug() << "Message3: " << QCA::arrayToHex(message3.toByteArray());
304 qDebug() << "Expecting: dfa66747de9ae63030ca32611497c827";
305 qDebug() << "AES-CMAC " << QCA::arrayToHex(cmacObject.process(message3).toByteArray());
306
307 cmacObject.clear();
308 QCA::SecureArray message4(message);
309 message4.resize(64);
310 qDebug();
311 qDebug() << "Message4: " << QCA::arrayToHex(message4.toByteArray());
312 qDebug() << "Expecting: 51f0bebf7e3b9d92fc49741779363cfe";
313 qDebug() << "AES-CMAC: " << QCA::arrayToHex(cmacObject.process(message4).toByteArray());
314 }
315
316 return 0;
317}
318
319