00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
00041
00042 QCA::SecureArray leftShift(const QCA::SecureArray &array)
00043 {
00044
00045 QCA::SecureArray out(array.size());
00046
00047
00048 int overflow = 0;
00049
00050
00051 for (int i = array.size() -1; i >= 0; --i) {
00052
00053 out[i] = array[i] << 1;
00054
00055
00056 out[i] |= overflow;
00057
00058 overflow = (array[i] & 0x80) ? 1 : 0;
00059 }
00060 return out;
00061 }
00062
00063
00064
00065 QCA::SecureArray xorArray(const QCA::SecureArray &array1,
00066 const QCA::SecureArray &array2)
00067 {
00068 if (array1.size() != array2.size())
00069
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
00084
00085 if (key.size() == 0)
00086 return;
00087
00088 m_key = key;
00089
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
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
00104 if (0 == (L[0] & 0x80))
00105 m_k1 = leftShift(L);
00106 else
00107 m_k1 = xorArray(leftShift(L), const_Rb);
00108
00109
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
00132
00133 void update(const QCA::MemoryRegion &a)
00134 {
00135 QCA::SecureArray bytesToProcess = m_residual + a;
00136 int blockNum;
00137
00138
00139 for (blockNum = 0; blockNum < ((bytesToProcess.size()-1)/16); ++blockNum) {
00140
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
00153 int numBytesLeft = bytesToProcess.size() - 16*blockNum;
00154
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
00167 m_residual.resize(16);
00168 m_residual[numBytesLeft] = (char)0x80;
00169 lastBlock = xorArray(m_residual, m_k2);
00170 } else {
00171
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
00184 QCA::SecureArray m_k1;
00185
00186 QCA::SecureArray m_k2;
00187
00188 QCA::SecureArray m_key;
00189
00190
00191 QCA::SecureArray m_X;
00192 QCA::SecureArray m_Y;
00193
00194
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
00216 return list;
00217 }
00218
00219 Provider::Context *createContext(const QString &type)
00220 {
00221 if(type == "cmac(aes)")
00222 return new AESCMACContext(this);
00223
00224
00225 else
00226 return 0;
00227 }
00228 };
00229
00230
00231
00232
00233
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
00251
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
00266 if( ! QCA::isSupported("cmac(aes)") ) {
00267 qDebug() << "AES CMAC not supported!";
00268 } else {
00269
00270 AES_CMAC cmacObject;
00271
00272
00273 QCA::SymmetricKey key(QCA::hexToArray("2b7e151628aed2a6abf7158809cf4f3c"));
00274
00275
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