File indexing completed on 2024-04-28 04:43:36

0001 /*
0002  Copyright (C) 2006 Brad Hards <bradh@frogmouth.net>
0003 
0004  Permission is hereby granted, free of charge, to any person obtaining a copy
0005  of this software and associated documentation files (the "Software"), to deal
0006  in the Software without restriction, including without limitation the rights
0007  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0008  copies of the Software, and to permit persons to whom the Software is
0009  furnished to do so, subject to the following conditions:
0010 
0011  The above copyright notice and this permission notice shall be included in
0012  all copies or substantial portions of the Software.
0013 
0014  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
0017  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
0018  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0019  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0020 */
0021 
0022 // QtCrypto has the declarations for all of QCA
0023 #include <QtCrypto>
0024 
0025 #include <QCoreApplication>
0026 #include <QDebug>
0027 
0028 #ifdef QT_STATICPLUGIN
0029 #include "import_plugins.h"
0030 #endif
0031 
0032 class AESCMACContext : public QCA::MACContext
0033 {
0034     Q_OBJECT
0035 public:
0036     AESCMACContext(QCA::Provider *p)
0037         : QCA::MACContext(p, QStringLiteral("cmac(aes)"))
0038     {
0039     }
0040 
0041     // Helper to left shift an arbitrary length array
0042     // This is heavily based on the example in the I-D.
0043     QCA::SecureArray leftShift(const QCA::SecureArray &array)
0044     {
0045         // We create an output of the same size as the input
0046         QCA::SecureArray out(array.size());
0047         // We handle one byte at a time - this is the high bit
0048         // from the previous byte.
0049         int overflow = 0;
0050 
0051         // work through each byte.
0052         for (int i = array.size() - 1; i >= 0; --i) {
0053             // do the left shift on this byte.
0054             out[i] = array[i] << 1;
0055             // make the low bit on this byte be the high bit
0056             // from the previous byte.
0057             out[i] |= overflow;
0058             // save the high bit for next time
0059             overflow = (array[i] & 0x80) ? 1 : 0;
0060         }
0061         return out;
0062     }
0063 
0064     // Helper to XOR two arrays - must be same length
0065     QCA::SecureArray xorArray(const QCA::SecureArray &array1, const QCA::SecureArray &array2)
0066     {
0067         if (array1.size() != array2.size())
0068             // empty array
0069             return QCA::SecureArray();
0070 
0071         QCA::SecureArray result(array1.size());
0072 
0073         for (int i = 0; i < array1.size(); ++i)
0074             result[i] = array1[i] ^ array2[i];
0075 
0076         return result;
0077     }
0078 
0079     void setup(const QCA::SymmetricKey &key) override
0080     {
0081         // We might not have a real key, since this can get called
0082         // from the constructor.
0083         if (key.size() == 0)
0084             return;
0085 
0086         m_key = key;
0087         // Generate the subkeys
0088         QCA::SecureArray const_Zero(16);
0089         QCA::SecureArray const_Rb(16);
0090         const_Rb[15] = (char)0x87;
0091 
0092         m_X        = const_Zero;
0093         m_residual = QCA::SecureArray();
0094 
0095         // Figure 2.2, step 1.
0096         QCA::Cipher aesObj(QStringLiteral("aes128"), QCA::Cipher::ECB, QCA::Cipher::DefaultPadding, QCA::Encode, key);
0097         QCA::SecureArray L = aesObj.process(const_Zero);
0098 
0099         // Figure 2.2, step 2
0100         if (0 == (L[0] & 0x80))
0101             m_k1 = leftShift(L);
0102         else
0103             m_k1 = xorArray(leftShift(L), const_Rb);
0104 
0105         // Figure 2.2, step 3
0106         if (0 == (m_k1[0] & 0x80))
0107             m_k2 = leftShift(m_k1);
0108         else
0109             m_k2 = xorArray(leftShift(m_k1), const_Rb);
0110     }
0111 
0112     QCA::Provider::Context *clone() const override
0113     {
0114         return new AESCMACContext(*this);
0115     }
0116 
0117     void clear()
0118     {
0119         setup(m_key);
0120     }
0121 
0122     QCA::KeyLength keyLength() const override
0123     {
0124         return QCA::KeyLength(16, 16, 1);
0125     }
0126 
0127     // This is a bit different to the way the I-D does it,
0128     // to allow for multiple update() calls.
0129     void update(const QCA::MemoryRegion &a) override
0130     {
0131         QCA::SecureArray bytesToProcess = m_residual + a;
0132         int              blockNum;
0133         // note that we don't want to do the last full block here, because
0134         // it needs special treatment in final().
0135         for (blockNum = 0; blockNum < ((bytesToProcess.size() - 1) / 16); ++blockNum) {
0136             // copy a block of data
0137             QCA::SecureArray thisBlock(16);
0138             for (int yalv = 0; yalv < 16; ++yalv)
0139                 thisBlock[yalv] = bytesToProcess[blockNum * 16 + yalv];
0140 
0141             m_Y = xorArray(m_X, thisBlock);
0142 
0143             QCA::Cipher aesObj(
0144                 QStringLiteral("aes128"), QCA::Cipher::ECB, QCA::Cipher::DefaultPadding, QCA::Encode, m_key);
0145             m_X = aesObj.process(m_Y);
0146         }
0147         // This can be between 1 and 16
0148         int numBytesLeft = bytesToProcess.size() - 16 * blockNum;
0149         // we copy the left over part
0150         m_residual.resize(numBytesLeft);
0151         for (int yalv = 0; yalv < numBytesLeft; ++yalv)
0152             m_residual[yalv] = bytesToProcess[blockNum * 16 + yalv];
0153     }
0154 
0155     void final(QCA::MemoryRegion *out) override
0156     {
0157         QCA::SecureArray lastBlock;
0158         int              numBytesLeft = m_residual.size();
0159 
0160         if (numBytesLeft != 16) {
0161             // no full block, so we have to pad.
0162             m_residual.resize(16);
0163             m_residual[numBytesLeft] = (char)0x80;
0164             lastBlock                = xorArray(m_residual, m_k2);
0165         } else {
0166             // this is a full block - no padding
0167             lastBlock = xorArray(m_residual, m_k1);
0168         }
0169         m_Y = xorArray(m_X, lastBlock);
0170         QCA::Cipher aesObj(QStringLiteral("aes128"), QCA::Cipher::ECB, QCA::Cipher::DefaultPadding, QCA::Encode, m_key);
0171         *out = aesObj.process(m_Y);
0172     }
0173 
0174 protected:
0175     // first subkey
0176     QCA::SecureArray m_k1;
0177     // second subkey
0178     QCA::SecureArray m_k2;
0179     // main key
0180     QCA::SecureArray m_key;
0181 
0182     // state
0183     QCA::SecureArray m_X;
0184     QCA::SecureArray m_Y;
0185 
0186     // partial block that we can't do yet
0187     QCA::SecureArray m_residual;
0188 };
0189 
0190 class ClientSideProvider : public QCA::Provider
0191 {
0192 public:
0193     int qcaVersion() const override
0194     {
0195         return QCA_VERSION;
0196     }
0197 
0198     QString name() const override
0199     {
0200         return QStringLiteral("exampleClientSideProvider");
0201     }
0202 
0203     QStringList features() const override
0204     {
0205         QStringList list;
0206         list += QStringLiteral("cmac(aes)");
0207         // you can add more features in here, if you have some.
0208         return list;
0209     }
0210 
0211     Provider::Context *createContext(const QString &type) override
0212     {
0213         if (type == QLatin1String("cmac(aes)"))
0214             return new AESCMACContext(this);
0215         // else if (type == some other feature)
0216         //  return some other context.
0217         else
0218             return nullptr;
0219     }
0220 };
0221 
0222 // AES CMAC is a Message Authentication Code based on a block cipher
0223 // instead of the more normal keyed hash.
0224 // See RFC 4493 "The AES-CMAC Algorithm"
0225 class AES_CMAC : public QCA::MessageAuthenticationCode
0226 {
0227 public:
0228     AES_CMAC(const QCA::SymmetricKey &key = QCA::SymmetricKey(), const QString &provider = QString())
0229         : QCA::MessageAuthenticationCode(QStringLiteral("cmac(aes)"), key, provider)
0230     {
0231     }
0232 };
0233 
0234 int main(int argc, char **argv)
0235 {
0236     // the Initializer object sets things up, and
0237     // also does cleanup when it goes out of scope
0238     QCA::Initializer init;
0239 
0240     qDebug() << "This example shows AES CMAC";
0241 
0242     QCoreApplication app(argc, argv);
0243 
0244     if (!QCA::isSupported("aes128-ecb")) {
0245         qDebug() << "AES not supported!";
0246     }
0247 
0248     if (QCA::insertProvider(new ClientSideProvider, 0))
0249         qDebug() << "Inserted our provider";
0250     else
0251         qDebug() << "our provider could not be added";
0252 
0253     // We should check AES CMAC is supported before using it.
0254     if (!QCA::isSupported("cmac(aes)")) {
0255         qDebug() << "AES CMAC not supported!";
0256     } else {
0257         // create the required object
0258         AES_CMAC cmacObject;
0259 
0260         // create the key
0261         QCA::SymmetricKey key(QCA::hexToArray(QStringLiteral("2b7e151628aed2a6abf7158809cf4f3c")));
0262 
0263         // set the MAC to use the key
0264         cmacObject.setup(key);
0265 
0266         QCA::SecureArray message =
0267             QCA::hexToArray(QStringLiteral("6bc1bee22e409f96e93d7e117393172a"
0268                                            "ae2d8a571e03ac9c9eb76fac45af8e51"
0269                                            "30c81c46a35ce411e5fbc1191a0a52ef"
0270                                            "f69f2445df4f9b17ad2b417be66c3710"));
0271         QCA::SecureArray message1(message);
0272         message1.resize(0);
0273         qDebug();
0274         qDebug() << "Message1: " << QCA::arrayToHex(message1.toByteArray());
0275         qDebug() << "Expecting:  bb1d6929e95937287fa37d129b756746";
0276         qDebug() << "AES-CMAC: " << QCA::arrayToHex(cmacObject.process(message1).toByteArray());
0277 
0278         cmacObject.clear();
0279         QCA::SecureArray message2(message);
0280         message2.resize(16);
0281         qDebug();
0282         qDebug() << "Message2: " << QCA::arrayToHex(message2.toByteArray());
0283         qDebug() << "Expecting:  070a16b46b4d4144f79bdd9dd04a287c";
0284         qDebug() << "AES-CMAC: " << QCA::arrayToHex(cmacObject.process(message2).toByteArray());
0285 
0286         cmacObject.clear();
0287         QCA::SecureArray message3(message);
0288         message3.resize(40);
0289         qDebug();
0290         qDebug() << "Message3: " << QCA::arrayToHex(message3.toByteArray());
0291         qDebug() << "Expecting:  dfa66747de9ae63030ca32611497c827";
0292         qDebug() << "AES-CMAC  " << QCA::arrayToHex(cmacObject.process(message3).toByteArray());
0293 
0294         cmacObject.clear();
0295         QCA::SecureArray message4(message);
0296         message4.resize(64);
0297         qDebug();
0298         qDebug() << "Message4: " << QCA::arrayToHex(message4.toByteArray());
0299         qDebug() << "Expecting:  51f0bebf7e3b9d92fc49741779363cfe";
0300         qDebug() << "AES-CMAC: " << QCA::arrayToHex(cmacObject.process(message4).toByteArray());
0301     }
0302 
0303     return 0;
0304 }
0305 
0306 #include "aes-cmac.moc"