File indexing completed on 2024-09-08 04:18:37
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"