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 | public: |
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 | |
186 | protected: |
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 | |
202 | class ClientSideProvider : public QCA::Provider |
203 | { |
204 | public: |
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" |
238 | class AES_CMAC: public QCA::MessageAuthenticationCode |
239 | { |
240 | public: |
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 | |
248 | int 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 | |