QCA

aes-cmac.cpp
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{
34 Q_OBJECT
35public:
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
174protected:
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
185
186 // partial block that we can't do yet
187 QCA::SecureArray m_residual;
188};
189
190class ClientSideProvider : public QCA::Provider
191{
192public:
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"
225class AES_CMAC : public QCA::MessageAuthenticationCode
226{
227public:
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
234int 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
266 QCA::SecureArray message =
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"
Provider * provider() const
The name of the provider.
MemoryRegion process(const MemoryRegion &a)
Perform an "all in one" update, returning the result.
General class for cipher (encryption / decryption) algorithms.
Definition qca_basic.h:582
@ ECB
operate in Electronic Code Book mode
Definition qca_basic.h:595
@ DefaultPadding
Default for cipher-mode.
Definition qca_basic.h:610
Convenience method for initialising and cleaning up QCA.
Definition qca_core.h:660
Simple container for acceptable key lengths.
Definition qca_core.h:701
Message authentication code provider.
MACContext(Provider *p, const QString &type)
Standard constructor.
Array of bytes that may be optionally secured.
Definition qca_tools.h:91
QByteArray toByteArray() const
Convert this memory region to a byte array.
General class for message authentication code (MAC) algorithms.
Definition qca_basic.h:828
MessageAuthenticationCode(const QString &type, const SymmetricKey &key, const QString &provider=QString())
Standard constructor.
void setup(const SymmetricKey &key)
Initialise the MAC algorithm.
void clear() override
Reset a MessageAuthenticationCode, dumping all previous parts of the message.
Internal context class used for the plugin.
Algorithm provider.
Definition qca_core.h:765
QString type() const
The type of context, as passed to the constructor.
Secure array of bytes.
Definition qca_tools.h:317
int size() const
Returns the number of bytes in the array.
bool resize(int size)
Change the length of this array If the new length is less than the old length, the extra information ...
Container for keys for symmetric encryption algorithms.
Definition qca_core.h:1264
void init(KXmlGuiWindow *window, KGameDifficulty *difficulty=nullptr)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
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 bool insertProvider(Provider *p, int priority=0)
Add a provider to the current list of providers.
QCA_EXPORT bool isSupported(const char *features, const QString &provider=QString())
Test if a capability (algorithm) is available.
QCA_EXPORT QByteArray hexToArray(const QString &hexString)
Convert a QString containing a hexadecimal representation of a byte array into a QByteArray.
@ Encode
Operate in the "forward" direction; for example, encrypting.
Definition qca_core.h:142
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:26 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.