File indexing completed on 2024-09-08 04:18:39
0001 /* 0002 Copyright (C) 2007 Carlo Todeschini - Metarete s.r.l. <info@metarete.it> 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 /* 0023 Algorithm inspired by Vladimir Silva's "Secure Java apps on Linux using 0024 MD5 crypt" article 0025 (http://www-128.ibm.com/developerworks/linux/library/l-md5crypt/) 0026 */ 0027 0028 #include <QCoreApplication> 0029 #include <QtCrypto> 0030 #include <QtDebug> 0031 #include <cstdio> 0032 0033 #ifdef QT_STATICPLUGIN 0034 #include "import_plugins.h" 0035 #endif 0036 0037 QString to64(long v, int size) 0038 { 0039 // Character set of the encrypted password: A-Za-z0-9./ 0040 QString itoa64 = QStringLiteral("./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); 0041 QString result; 0042 0043 while (--size >= 0) { 0044 result.append(itoa64.at((int)(v & 0x3f))); 0045 v = v >> 6; 0046 } 0047 0048 return result; 0049 } 0050 0051 int byte2unsigned(int byteValue) 0052 { 0053 int integerToReturn; 0054 integerToReturn = (int)byteValue & 0xff; 0055 return integerToReturn; 0056 } 0057 0058 QString qca_md5crypt(const QCA::SecureArray &password, const QCA::SecureArray &salt) 0059 { 0060 QCA::SecureArray finalState, magic_string = "$1$"; 0061 0062 // The md5crypt algorithm uses two separate hashes 0063 QCA::Hash hash1(QStringLiteral("md5")); 0064 QCA::Hash hash2(QStringLiteral("md5")); 0065 0066 // MD5 Hash #1: pwd, magic string and salt 0067 hash1.update(password); 0068 hash1.update(magic_string); 0069 hash1.update(salt); 0070 0071 // MD5 Hash #2: password, salt, password 0072 hash2.update(password); 0073 hash2.update(salt); 0074 hash2.update(password); 0075 0076 finalState = hash2.final(); 0077 0078 // Two sets of transformations based on the length of the password 0079 for (int i = password.size(); i > 0; i -= 16) { 0080 // Update hash1 from offset value (i > 16 ? 16 : i) 0081 hash1.update(finalState.toByteArray().left(i > 16 ? 16 : i)); 0082 } 0083 0084 // Clear array bits 0085 finalState.fill(0); 0086 0087 for (int i = password.size(); i != 0; i = i >> 1) { 0088 if ((i & 1) != 0) { 0089 hash1.update(finalState.toByteArray().left(1)); 0090 } else { 0091 hash1.update(password.toByteArray().left(1)); 0092 } 0093 } 0094 0095 finalState = hash1.final(); 0096 0097 // Now build a 1000 entry dictionary... 0098 for (int i = 0; i < 1000; i++) { 0099 hash2.clear(); 0100 0101 if ((i & 1) != 0) { 0102 hash2.update(password); 0103 } else { 0104 hash2.update(finalState.toByteArray().left(16)); 0105 } 0106 0107 if ((i % 3) != 0) { 0108 hash2.update(salt); 0109 } 0110 0111 if ((i % 7) != 0) { 0112 hash2.update(password); 0113 } 0114 0115 if ((i & 1) != 0) { 0116 hash2.update(finalState.toByteArray().left(16)); 0117 } else { 0118 hash2.update(password); 0119 } 0120 0121 finalState = hash2.final(); 0122 } 0123 0124 // Create an output string 0125 // Salt is part of the encoded password ($1$<string>$) 0126 QString encodedString; 0127 0128 encodedString.append(QString::fromLatin1(magic_string.toByteArray())); 0129 encodedString.append(QString::fromLatin1(salt.toByteArray())); 0130 encodedString.append(QStringLiteral("$")); 0131 0132 long l; 0133 0134 l = (byte2unsigned(finalState.toByteArray().at(0)) << 16 | (byte2unsigned(finalState.toByteArray().at(6))) << 8 | 0135 byte2unsigned(finalState.toByteArray().at(12))); 0136 encodedString.append(to64(l, 4)); 0137 0138 l = (byte2unsigned(finalState.toByteArray().at(1)) << 16 | (byte2unsigned(finalState.toByteArray().at(7))) << 8 | 0139 byte2unsigned(finalState.toByteArray().at(13))); 0140 encodedString.append(to64(l, 4)); 0141 0142 l = (byte2unsigned(finalState.toByteArray().at(2)) << 16 | (byte2unsigned(finalState.toByteArray().at(8))) << 8 | 0143 byte2unsigned(finalState.toByteArray().at(14))); 0144 encodedString.append(to64(l, 4)); 0145 0146 l = (byte2unsigned(finalState.toByteArray().at(3)) << 16 | (byte2unsigned(finalState.toByteArray().at(9))) << 8 | 0147 byte2unsigned(finalState.toByteArray().at(15))); 0148 encodedString.append(to64(l, 4)); 0149 0150 l = (byte2unsigned(finalState.toByteArray().at(4)) << 16 | (byte2unsigned(finalState.toByteArray().at(10))) << 8 | 0151 byte2unsigned(finalState.toByteArray().at(5))); 0152 encodedString.append(to64(l, 4)); 0153 0154 l = byte2unsigned(finalState.toByteArray().at(11)); 0155 encodedString.append(to64(l, 2)); 0156 0157 return encodedString; 0158 } 0159 0160 int main(int argc, char **argv) 0161 { 0162 // the Initializer object sets things up, and 0163 // also does cleanup when it goes out of scope 0164 QCA::Initializer init; 0165 0166 QCoreApplication app(argc, argv); 0167 0168 QCA::SecureArray password, salt; 0169 0170 if (argc < 3) { 0171 printf("Usage: %s password salt (salt without $1$)\n", argv[0]); 0172 return 1; 0173 } 0174 0175 password.append(argv[1]); 0176 0177 salt.append(argv[2]); 0178 0179 // must always check that an algorithm is supported before using it 0180 if (!QCA::isSupported("md5")) 0181 printf("MD5 hash not supported!\n"); 0182 else { 0183 QString result = qca_md5crypt(password, salt); 0184 0185 printf("md5crypt [ %s , %s ] = '%s'\n", password.data(), salt.data(), qPrintable(result)); 0186 0187 // this is equivalent if you have GNU libc 2.0 0188 // printf( "GNU md5crypt [ %s , %s ] = '%s'\n", password.data(), salt.data(), crypt( password.data(), ( 0189 // "$1$"+salt ).data() ) ); 0190 } 0191 0192 return 0; 0193 }