File indexing completed on 2024-04-21 14:56:12
0001 /* This file is part of the KDE libraries 0002 Copyright (C) 2000,2001 Dawit Alemayehu <adawit@kde.org> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #undef QT_NO_CAST_FROM_ASCII 0021 0022 #include <unistd.h> 0023 0024 #include <iostream> 0025 #include <QCoreApplication> 0026 #include <QBuffer> 0027 #include <QFile> 0028 #include <QDateTime> 0029 0030 #include <kdebug.h> 0031 #include <klocalizedstring.h> 0032 #include <kcmdlineargs.h> 0033 0034 #include <kcodecs.h> 0035 #include <kmd5.h> 0036 0037 using namespace std; 0038 0039 #define TEST_BLOCK_LEN 1000 // Length of test blocks. 0040 #define TEST_BLOCK_COUNT 10000 // Number of test blocks. 0041 #define MAX_READ_BUF_SIZE 8192 0042 0043 enum Codec { 0044 Unspecified = 0, 0045 Base64Encode, 0046 Base64Decode, 0047 UUEncode, 0048 UUDecode, 0049 QPEncode, 0050 QPDecode 0051 }; 0052 0053 void MD5_timeTrial(); 0054 void MD5_testSuite(); 0055 void testCodec(const char *, Codec, bool); 0056 void MD5_verify(const char *, const char *, bool); 0057 void MD5_file(const char *, bool rawOutput = false); 0058 void MD5_string(const char *, const char *expected = nullptr, bool rawOutput = false); 0059 0060 long readContent(const QFile &f, long count, QByteArray &buf) 0061 { 0062 long result; 0063 int old_size; 0064 0065 old_size = buf.size(); 0066 buf.resize(old_size + count); 0067 0068 result = read(f.handle(), buf.data() + old_size, count); 0069 0070 if (result > 0 && result < count) { 0071 buf.resize(old_size + result); 0072 } else if (result == 0) { 0073 buf.resize(old_size); 0074 } else if (result == -1) { 0075 kError() << "Could not read the file!" << endl; 0076 } 0077 0078 return result; 0079 } 0080 0081 void testCodec(const char *msg, Codec type, bool isFile) 0082 { 0083 QByteArray output; 0084 0085 if (isFile) { 0086 int count; 0087 QByteArray data; 0088 0089 QFile f(QFile::encodeName(msg)); 0090 0091 if (!f.exists()) { 0092 kError() << "Could not find: " << qPrintable(f.fileName()) << endl; 0093 return; 0094 } 0095 0096 if (!f.open(QIODevice::ReadOnly)) { 0097 f.close(); 0098 kError() << "Could not open: " << qPrintable(f.fileName()) << endl; 0099 return; 0100 } 0101 0102 // Read contents of file... 0103 count = 0; 0104 0105 while ((count = readContent(f, MAX_READ_BUF_SIZE, data)) > 0) { 0106 ; 0107 } 0108 0109 // Error! Exit! 0110 if (count == -1) { 0111 kError() << "Error reading from: " << qPrintable(f.fileName()) << endl; 0112 f.close(); 0113 return; 0114 } 0115 0116 f.close(); 0117 0118 // Perform the requested encoding or decoding... 0119 switch (type) { 0120 case Base64Encode: 0121 KCodecs::base64Encode(data, output, true); 0122 break; 0123 case Base64Decode: 0124 KCodecs::base64Decode(data, output); 0125 break; 0126 case UUEncode: 0127 KCodecs::uuencode(data, output); 0128 break; 0129 case UUDecode: 0130 KCodecs::uudecode(data, output); 0131 break; 0132 case QPEncode: 0133 KCodecs::quotedPrintableEncode(data, output, true); 0134 break; 0135 case QPDecode: 0136 KCodecs::quotedPrintableDecode(data, output); 0137 break; 0138 default: 0139 break; 0140 } 0141 0142 cout << "Result: " << endl << output.data() << endl; 0143 } else { 0144 QByteArray result; 0145 0146 memcpy(output.data(), msg, strlen(msg)); 0147 0148 switch (type) { 0149 case Base64Encode: 0150 result = KCodecs::base64Encode(output); 0151 break; 0152 case Base64Decode: 0153 result = KCodecs::base64Decode(output); 0154 break; 0155 case UUEncode: 0156 result = KCodecs::uuencode(output); 0157 break; 0158 case UUDecode: 0159 result = KCodecs::uudecode(output); 0160 break; 0161 case QPEncode: 0162 result = KCodecs::quotedPrintableEncode(output); 0163 break; 0164 case QPDecode: 0165 result = KCodecs::quotedPrintableDecode(output); 0166 break; 0167 default: 0168 break; 0169 } 0170 cout << result.data() << endl; 0171 } 0172 } 0173 0174 void MD5_timeTrial() 0175 { 0176 KMD5 context; 0177 0178 QDateTime endTime; 0179 QDateTime startTime; 0180 0181 quint8 block[TEST_BLOCK_LEN]; 0182 quint32 i; 0183 0184 cout << "Timing test. Digesting " << TEST_BLOCK_COUNT << " blocks of " 0185 << TEST_BLOCK_LEN << "-byte..." << endl; 0186 0187 // Initialize block 0188 for (i = 0; i < TEST_BLOCK_LEN; ++i) { 0189 block[i] = (quint8)(i & 0xff); 0190 } 0191 0192 // Start timer 0193 startTime = QDateTime::currentDateTime(); 0194 0195 // Digest blocks 0196 for (i = 0; i < TEST_BLOCK_COUNT; ++i) { 0197 context.update(block, TEST_BLOCK_LEN); 0198 } 0199 0200 // Stop timer 0201 endTime = QDateTime::currentDateTime(); 0202 0203 long duration = startTime.secsTo(endTime); 0204 long speed; 0205 if (duration) { 0206 speed = (TEST_BLOCK_LEN * (TEST_BLOCK_COUNT / duration)); 0207 } else { 0208 speed = TEST_BLOCK_COUNT; 0209 } 0210 0211 cout << "Result: " << endl; 0212 cout << " Time = " << duration << " seconds" << endl; 0213 cout << " Speed = " << speed << " bytes/second" << endl; 0214 cout << " Digest = " << context.hexDigest().data() << endl; 0215 } 0216 0217 void MD5_testSuite() 0218 { 0219 cout << "MD5 preset test suite as defined in RFC 1321:" << endl; 0220 MD5_string("", "d41d8cd98f00b204e9800998ecf8427e"); 0221 MD5_string("a", "0cc175b9c0f1b6a831c399e269772661"); 0222 MD5_string("abc", "900150983cd24fb0d6963f7d28e17f72"); 0223 MD5_string("message digest", "f96b697d7cb7938d525a2f31aaf161d0"); 0224 MD5_string("abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b"); 0225 MD5_string("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 0226 "d174ab98d277d9f5a5611c2c9f419d9f"); 0227 MD5_string("12345678901234567890123456789012345678901234567890123456789012" 0228 "345678901234567890", "57edf4a22be3c955ac49da2e2107b67a"); 0229 } 0230 0231 void MD5_verify(const char *input, const char *digest, bool isFile) 0232 { 0233 bool result; 0234 KMD5 context; 0235 0236 if (!isFile) { 0237 context.update(QByteArray(input)); 0238 result = context.verify(digest); 0239 cout << "Input string: " << input << endl; 0240 } else { 0241 QFile f(input); 0242 0243 if (!f.open(QIODevice::ReadOnly)) { 0244 f.close(); 0245 kFatal() << "Cannot open file for reading!"; 0246 } 0247 0248 result = context.verify(digest); 0249 f.close(); 0250 0251 cout << "Input filename: " << input << endl; 0252 } 0253 0254 cout << "Calculated Digest = " << context.hexDigest().data() << endl; 0255 cout << "Supplied Digest = " << digest << endl; 0256 cout << "Matches: " << (result ? "TRUE" : "FALSE") << endl; 0257 } 0258 0259 void MD5_file(const char *filename, bool rawOutput) 0260 { 0261 QFile f(QFile::encodeName(filename)); 0262 0263 if (!f.open(QIODevice::ReadOnly)) { 0264 f.close(); 0265 kError() << "(" << filename << ") cannot be opened!" << endl; 0266 return; 0267 } 0268 0269 KMD5 context; 0270 context.update(f); 0271 0272 if (rawOutput) { 0273 cout << "MD5 (" << filename << ") = " << context.rawDigest() << endl; 0274 } else { 0275 cout << "MD5 (" << filename << ") = " << context.hexDigest().data() << endl; 0276 } 0277 0278 f.close(); 0279 } 0280 0281 void MD5_string(const char *input, const char *expected, bool rawOutput) 0282 { 0283 KMD5 context; 0284 context.update(QByteArray(input)); 0285 0286 cout << "Checking MD5 for: " << input << endl; 0287 0288 if (rawOutput) { 0289 cout << "Result: " << context.rawDigest() << endl; 0290 } else { 0291 cout << "Result: " << context.hexDigest().data() << endl; 0292 } 0293 0294 if (expected) { 0295 cout << "Expected: " << expected << endl; 0296 cout << "Status: " << context.verify(expected) << endl; 0297 } 0298 } 0299 0300 int main(int argc, char *argv[]) 0301 { 0302 KCmdLineOptions options; 0303 options.add("c <digest>", ki18n("compare <digest> with the calculated digest for a string or file.")); 0304 options.add("d", ki18n("decode the given string or file using base64")); 0305 options.add("e", ki18n("encode the given string or file using base64")); 0306 options.add("f", ki18n("the filename to be used as input"), "default"); 0307 options.add("p", ki18n("encode the given string or file using quoted-printable")); 0308 options.add("q", ki18n("decode the given string or file using quoted-printable")); 0309 options.add("r", ki18n("calculate the raw md5 for the given string or file")); 0310 options.add("s", ki18n("the string to be used as input")); 0311 options.add("t", ki18n("perform a timed message-digest test")); 0312 options.add("u", ki18n("uuencode the given string or file")); 0313 options.add("x", ki18n("uudecode the given string or file")); 0314 options.add("z", ki18n("run a preset message-digest test")); 0315 options.add("+command", ki18n("[input1, input2,...]")); 0316 0317 KCmdLineArgs::init(argc, argv, "kmdcodectest", nullptr, 0318 ki18n("KMDCodecTest"), "1.0", 0319 ki18n("Unit test for md5, base64 encode/decode " 0320 "and uuencode/decode facilities")); 0321 KCmdLineArgs::addCmdLineOptions(options); 0322 KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); 0323 int count = args->count(); 0324 0325 //QCoreApplication app; 0326 0327 if (!count) { 0328 if (args->isSet("t")) { 0329 MD5_timeTrial(); 0330 } else if (args->isSet("z")) { 0331 MD5_testSuite(); 0332 } else { 0333 args->usage(); 0334 } 0335 } else { 0336 bool isVerify = args->isSet("c"); 0337 bool isString = args->isSet("s"); 0338 bool isFile = args->isSet("f"); 0339 Codec type = Unspecified; 0340 if (args->isSet("d")) { 0341 type = Base64Decode; 0342 } else if (args->isSet("e")) { 0343 type = Base64Encode; 0344 } else if (args->isSet("u")) { 0345 type = UUEncode; 0346 } else if (args->isSet("x")) { 0347 type = UUDecode; 0348 } else if (args->isSet("p")) { 0349 type = QPEncode; 0350 } else if (args->isSet("q")) { 0351 type = QPDecode; 0352 } 0353 if (isVerify) { 0354 const char *opt = args->getOption("c").toLocal8Bit().data(); 0355 for (int i = 0; i < count; i++) { 0356 MD5_verify(args->arg(i).toLocal8Bit().constData(), opt, (isString || !isFile)); 0357 } 0358 } else { 0359 for (int i = 0; i < count; i++) { 0360 if (type != Unspecified) { 0361 testCodec(args->arg(i).toLocal8Bit().constData(), type, isFile); 0362 } else { 0363 if (isString) { 0364 MD5_string(args->arg(i).toLocal8Bit().constData(), nullptr, args->isSet("r")); 0365 } else { 0366 MD5_file(args->arg(i).toLocal8Bit().constData(), args->isSet("r")); 0367 } 0368 } 0369 } 0370 } 0371 } 0372 args->clear(); 0373 return (0); 0374 }