aes-cmac.cpp

This example shows how to implement a client side "provider".

There are three important parts to this:

00001 /*
00002  Copyright (C) 2006 Brad Hards <bradh@frogmouth.net>
00003 
00004  Permission is hereby granted, free of charge, to any person obtaining a copy
00005  of this software and associated documentation files (the "Software"), to deal
00006  in the Software without restriction, including without limitation the rights
00007  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  copies of the Software, and to permit persons to whom the Software is
00009  furnished to do so, subject to the following conditions:
00010 
00011  The above copyright notice and this permission notice shall be included in
00012  all copies or substantial portions of the Software.
00013 
00014  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00017  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00018  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00019  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00020 */
00021 
00022 // QtCrypto has the declarations for all of QCA
00023 #include <QtCrypto>
00024 
00025 #include <QCoreApplication>
00026 #include <QDebug>
00027 
00028 class AESCMACContext : public QCA::MACContext
00029 {
00030 public:
00031     AESCMACContext(QCA::Provider *p) : QCA::MACContext(p, "cmac(aes)")
00032     {
00033     }
00034 
00035     ~AESCMACContext()
00036     {
00037     }
00038 
00039 
00040     // Helper to left shift an arbitrary length array
00041     // This is heavily based on the example in the I-D.
00042     QCA::SecureArray leftShift(const QCA::SecureArray &array)
00043     {
00044         // We create an output of the same size as the input
00045         QCA::SecureArray out(array.size());
00046         // We handle one byte at a time - this is the high bit
00047         // from the previous byte.
00048         int overflow = 0;
00049 
00050         // work through each byte.
00051         for (int i = array.size() -1; i >= 0; --i) {
00052             // do the left shift on this byte.
00053             out[i] = array[i] << 1;
00054             // make the low bit on this byte be the high bit
00055             // from the previous byte.
00056             out[i] |= overflow;
00057             // save the high bit for next time
00058             overflow = (array[i] & 0x80) ? 1 : 0;
00059         }
00060         return out;
00061     }
00062 
00063 
00064     // Helper to XOR two arrays - must be same length
00065     QCA::SecureArray xorArray(const QCA::SecureArray &array1,
00066                           const QCA::SecureArray &array2)
00067     {
00068         if (array1.size() != array2.size())
00069             // empty array
00070             return QCA::SecureArray();
00071 
00072         QCA::SecureArray result(array1.size());
00073 
00074         for (int i = 0; i < array1.size(); ++i)
00075             result[i] = array1[i] ^ array2[i];
00076 
00077         return result;
00078     }
00079 
00080 
00081     void setup(const QCA::SymmetricKey &key)
00082     {
00083         // We might not have a real key, since this can get called
00084         // from the constructor.
00085         if (key.size() == 0)
00086             return;
00087 
00088         m_key = key;
00089         // Generate the subkeys
00090         QCA::SecureArray const_Zero(16);
00091         QCA::SecureArray const_Rb(16);
00092         const_Rb[15] = (char)0x87;
00093 
00094         m_X = const_Zero;
00095         m_residual = QCA::SecureArray();
00096 
00097         // Figure 2.2, step 1.
00098         QCA::Cipher aesObj(QString("aes128"),
00099                            QCA::Cipher::ECB, QCA::Cipher::DefaultPadding,
00100                            QCA::Encode, key);
00101         QCA::SecureArray L = aesObj.process(const_Zero);
00102 
00103         // Figure 2.2, step 2
00104         if (0 == (L[0] & 0x80))
00105             m_k1 = leftShift(L);
00106         else
00107             m_k1 = xorArray(leftShift(L), const_Rb);
00108 
00109         // Figure 2.2, step 3
00110         if (0 == (m_k1[0] & 0x80))
00111             m_k2 = leftShift(m_k1);
00112         else
00113             m_k2 = xorArray(leftShift(m_k1), const_Rb);
00114     }
00115 
00116     QCA::Provider::Context *clone() const
00117     {
00118         return new AESCMACContext(*this);
00119     }
00120 
00121     void clear()
00122     {
00123         setup(m_key);
00124     }
00125 
00126     QCA::KeyLength keyLength() const
00127     {
00128         return QCA::KeyLength(16, 16, 1);
00129     }
00130 
00131     // This is a bit different to the way the I-D does it,
00132     // to allow for multiple update() calls.
00133     void update(const QCA::MemoryRegion &a)
00134     {
00135         QCA::SecureArray bytesToProcess = m_residual + a;
00136         int blockNum;
00137         // note that we don't want to do the last full block here, because
00138         // it needs special treatment in final().
00139         for (blockNum = 0; blockNum < ((bytesToProcess.size()-1)/16); ++blockNum) {
00140             // copy a block of data
00141             QCA::SecureArray thisBlock(16);
00142             for (int yalv = 0; yalv < 16; ++yalv)
00143                 thisBlock[yalv] = bytesToProcess[blockNum*16 + yalv];
00144 
00145             m_Y = xorArray(m_X, thisBlock);
00146 
00147             QCA::Cipher aesObj(QString("aes128"),
00148                                QCA::Cipher::ECB, QCA::Cipher::DefaultPadding,
00149                                QCA::Encode, m_key);
00150             m_X = aesObj.process(m_Y);
00151         }
00152         // This can be between 1 and 16
00153         int numBytesLeft = bytesToProcess.size() - 16*blockNum;
00154         // we copy the left over part
00155         m_residual.resize(numBytesLeft);
00156         for(int yalv = 0; yalv < numBytesLeft; ++yalv)
00157             m_residual[yalv] = bytesToProcess[blockNum*16 + yalv];
00158     }
00159 
00160     void final( QCA::MemoryRegion *out)
00161     {
00162         QCA::SecureArray lastBlock;
00163         int numBytesLeft = m_residual.size();
00164 
00165         if ( numBytesLeft != 16 ) {
00166             // no full block, so we have to pad.
00167             m_residual.resize(16);
00168             m_residual[numBytesLeft] = (char)0x80;
00169             lastBlock = xorArray(m_residual, m_k2);
00170         } else {
00171             // this is a full block - no padding
00172             lastBlock = xorArray(m_residual, m_k1);
00173         }
00174         m_Y = xorArray(m_X, lastBlock);
00175         QCA::Cipher aesObj(QString("aes128"),
00176                            QCA::Cipher::ECB, QCA::Cipher::DefaultPadding,
00177                            QCA::Encode, m_key);
00178         *out = aesObj.process(m_Y);
00179 
00180     }
00181 
00182 protected:
00183     // first subkey
00184     QCA::SecureArray m_k1;
00185     // second subkey
00186     QCA::SecureArray m_k2;
00187     // main key
00188     QCA::SecureArray m_key;
00189 
00190     // state
00191     QCA::SecureArray m_X;
00192     QCA::SecureArray m_Y;
00193 
00194     // partial block that we can't do yet
00195     QCA::SecureArray m_residual;
00196 };
00197 
00198 class ClientSideProvider : public QCA::Provider
00199 {
00200 public:
00201         int qcaVersion() const
00202         {
00203                 return QCA_VERSION;
00204         }
00205 
00206         QString name() const
00207         {
00208                 return "exampleClientSideProvider";
00209         }
00210 
00211         QStringList features() const
00212         {
00213                 QStringList list;
00214                 list += "cmac(aes)";
00215                 // you can add more features in here, if you have some.
00216                 return list;
00217         }
00218 
00219         Provider::Context *createContext(const QString &type)
00220         {
00221             if(type == "cmac(aes)")
00222                 return new AESCMACContext(this);
00223             // else if (type == some other feature)
00224             //  return some other context.
00225             else
00226                 return 0;
00227         }
00228 };
00229 
00230 
00231 // AES CMAC is a Message Authentication Code based on a block cipher
00232 // instead of the more normal keyed hash.
00233 // See RFC 4493 "The AES-CMAC Algorithm"
00234 class AES_CMAC: public QCA::MessageAuthenticationCode
00235 {
00236 public:
00237     AES_CMAC(const QCA::SymmetricKey &key = QCA::SymmetricKey(),
00238              const QString &provider = QString()):
00239         QCA::MessageAuthenticationCode( "cmac(aes)", key, provider)
00240     {}
00241 };
00242 
00243 
00244 int main(int argc, char **argv)
00245 {
00246     QCoreApplication app(argc, argv);
00247 
00248     qDebug() << "This example shows AES CMAC";
00249 
00250     // the Initializer object sets things up, and
00251     // also does cleanup when it goes out of scope
00252     QCA::Initializer init;
00253 
00254     qDebug() << "Completed initialisation";
00255 
00256     if( ! QCA::isSupported("aes128-ecb") ) {
00257         qDebug() << "AES not supported!";
00258     }
00259 
00260     if ( QCA::insertProvider(new ClientSideProvider, 0) )
00261         qDebug() << "Inserted our provider";
00262     else
00263         qDebug() << "our provider could not be added";
00264 
00265     // We should check AES CMAC is supported before using it.
00266     if( ! QCA::isSupported("cmac(aes)") ) {
00267         qDebug() << "AES CMAC not supported!";
00268     } else {
00269         // create the required object
00270         AES_CMAC cmacObject;
00271 
00272         // create the key
00273         QCA::SymmetricKey key(QCA::hexToArray("2b7e151628aed2a6abf7158809cf4f3c"));
00274 
00275         // set the MAC to use the key
00276         cmacObject.setup(key);
00277 
00278         QCA::SecureArray message = QCA::hexToArray("6bc1bee22e409f96e93d7e117393172a"
00279                                                "ae2d8a571e03ac9c9eb76fac45af8e51"
00280                                                "30c81c46a35ce411e5fbc1191a0a52ef"
00281                                                "f69f2445df4f9b17ad2b417be66c3710");
00282         QCA::SecureArray message1(message);
00283         message1.resize(0);
00284         qDebug();
00285         qDebug() << "Message1: " << QCA::arrayToHex(message1.toByteArray());
00286         qDebug() << "Expecting:  bb1d6929e95937287fa37d129b756746";
00287         qDebug() << "AES-CMAC: " << QCA::arrayToHex(cmacObject.process(message1).toByteArray());
00288 
00289         cmacObject.clear();
00290         QCA::SecureArray message2(message);
00291         message2.resize(16);
00292         qDebug();
00293         qDebug() << "Message2: " << QCA::arrayToHex(message2.toByteArray());
00294         qDebug() << "Expecting:  070a16b46b4d4144f79bdd9dd04a287c";
00295         qDebug() << "AES-CMAC: " << QCA::arrayToHex(cmacObject.process(message2).toByteArray());
00296 
00297         cmacObject.clear();
00298         QCA::SecureArray message3(message);
00299         message3.resize(40);
00300         qDebug();
00301         qDebug() << "Message3: " << QCA::arrayToHex(message3.toByteArray());
00302         qDebug() << "Expecting:  dfa66747de9ae63030ca32611497c827";
00303         qDebug() << "AES-CMAC  " << QCA::arrayToHex(cmacObject.process(message3).toByteArray());
00304 
00305         cmacObject.clear();
00306         QCA::SecureArray message4(message);
00307         message4.resize(64);
00308         qDebug();
00309         qDebug() << "Message4: " << QCA::arrayToHex(message4.toByteArray());
00310         qDebug() << "Expecting:  51f0bebf7e3b9d92fc49741779363cfe";
00311         qDebug() << "AES-CMAC: " << QCA::arrayToHex(cmacObject.process(message4).toByteArray());
00312     }
00313 
00314     return 0;
00315 }
00316 

Generated on Fri Jul 6 12:14:03 2007 for Qt Cryptographic Architecture by  doxygen 1.4.6