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 | |
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(a: const_Zero); |
98 | |
99 | // Figure 2.2, step 2 |
100 | if (0 == (L[0] & 0x80)) |
101 | m_k1 = leftShift(array: L); |
102 | else |
103 | m_k1 = xorArray(array1: leftShift(array: L), array2: const_Rb); |
104 | |
105 | // Figure 2.2, step 3 |
106 | if (0 == (m_k1[0] & 0x80)) |
107 | m_k2 = leftShift(array: m_k1); |
108 | else |
109 | m_k2 = xorArray(array1: leftShift(array: m_k1), array2: 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(array1: m_X, array2: thisBlock); |
142 | |
143 | QCA::Cipher aesObj( |
144 | QStringLiteral("aes128" ), QCA::Cipher::ECB, QCA::Cipher::DefaultPadding, QCA::Encode, m_key); |
145 | m_X = aesObj.process(a: 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(size: 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(size: 16); |
163 | m_residual[numBytesLeft] = (char)0x80; |
164 | lastBlock = xorArray(array1: m_residual, array2: m_k2); |
165 | } else { |
166 | // this is a full block - no padding |
167 | lastBlock = xorArray(array1: m_residual, array2: m_k1); |
168 | } |
169 | m_Y = xorArray(array1: m_X, array2: lastBlock); |
170 | QCA::Cipher aesObj(QStringLiteral("aes128" ), QCA::Cipher::ECB, QCA::Cipher::DefaultPadding, QCA::Encode, m_key); |
171 | *out = aesObj.process(a: 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 | { |
205 | QStringList list; |
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 |
238 | QCA::Initializer init; |
239 | |
240 | qDebug() << "This example shows AES CMAC" ; |
241 | |
242 | QCoreApplication app(argc, argv); |
243 | |
244 | if (!QCA::isSupported(features: "aes128-ecb" )) { |
245 | qDebug() << "AES not supported!" ; |
246 | } |
247 | |
248 | if (QCA::insertProvider(p: new ClientSideProvider, priority: 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(features: "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(size: 0); |
273 | qDebug(); |
274 | qDebug() << "Message1: " << QCA::arrayToHex(array: message1.toByteArray()); |
275 | qDebug() << "Expecting: bb1d6929e95937287fa37d129b756746" ; |
276 | qDebug() << "AES-CMAC: " << QCA::arrayToHex(array: cmacObject.process(a: message1).toByteArray()); |
277 | |
278 | cmacObject.clear(); |
279 | QCA::SecureArray message2(message); |
280 | message2.resize(size: 16); |
281 | qDebug(); |
282 | qDebug() << "Message2: " << QCA::arrayToHex(array: message2.toByteArray()); |
283 | qDebug() << "Expecting: 070a16b46b4d4144f79bdd9dd04a287c" ; |
284 | qDebug() << "AES-CMAC: " << QCA::arrayToHex(array: cmacObject.process(a: message2).toByteArray()); |
285 | |
286 | cmacObject.clear(); |
287 | QCA::SecureArray message3(message); |
288 | message3.resize(size: 40); |
289 | qDebug(); |
290 | qDebug() << "Message3: " << QCA::arrayToHex(array: message3.toByteArray()); |
291 | qDebug() << "Expecting: dfa66747de9ae63030ca32611497c827" ; |
292 | qDebug() << "AES-CMAC " << QCA::arrayToHex(array: cmacObject.process(a: message3).toByteArray()); |
293 | |
294 | cmacObject.clear(); |
295 | QCA::SecureArray message4(message); |
296 | message4.resize(size: 64); |
297 | qDebug(); |
298 | qDebug() << "Message4: " << QCA::arrayToHex(array: message4.toByteArray()); |
299 | qDebug() << "Expecting: 51f0bebf7e3b9d92fc49741779363cfe" ; |
300 | qDebug() << "AES-CMAC: " << QCA::arrayToHex(array: cmacObject.process(a: message4).toByteArray()); |
301 | } |
302 | |
303 | return 0; |
304 | } |
305 | |
306 | #include "aes-cmac.moc" |
307 | |