| 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 | |