00001 /* 00002 Copyright (C) 2007 Carlo Todeschini - Metarete s.r.l. <info@metarete.it> 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 /* 00023 Algorithm inspired by Vladimir Silva's "Secure Java apps on Linux using 00024 MD5 crypt" article 00025 (http://www-128.ibm.com/developerworks/linux/library/l-md5crypt/) 00026 */ 00027 00028 #include <QtCrypto> 00029 #include <QCoreApplication> 00030 #include <QtDebug> 00031 #include <stdio.h> 00032 00033 QString to64 ( long v , int size ) 00034 { 00035 00036 // Character set of the encrypted password: A-Za-z0-9./ 00037 QString itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 00038 QString result; 00039 00040 while ( --size >= 0 ) 00041 { 00042 result.append ( itoa64.at ( ( int )( v & 0x3f ) ) ); 00043 v = v >> 6; 00044 } 00045 00046 return result; 00047 00048 } 00049 00050 00051 int byte2unsigned ( int byteValue ) 00052 { 00053 00054 int integerToReturn; 00055 integerToReturn = (int) byteValue & 0xff; 00056 return integerToReturn; 00057 00058 } 00059 00060 QString qca_md5crypt( const QCA::SecureArray &password, const QCA::SecureArray &salt ) 00061 { 00062 QCA::SecureArray finalState, magic_string = "$1$"; 00063 00064 // The md5crypt algorithm uses two separate hashes 00065 QCA::Hash hash1( "md5" ); 00066 QCA::Hash hash2( "md5" ); 00067 00068 // MD5 Hash #1: pwd, magic string and salt 00069 hash1.update ( password ); 00070 hash1.update ( magic_string ); 00071 hash1.update ( salt ); 00072 00073 // MD5 Hash #2: password, salt, password 00074 hash2.update ( password ); 00075 hash2.update ( salt ); 00076 hash2.update ( password ); 00077 00078 finalState = hash2.final(); 00079 00080 // Two sets of transformations based on the length of the password 00081 for ( int i = password.size() ; i > 0 ; i -= 16 ) 00082 { 00083 // Update hash1 from offset value (i > 16 ? 16 : i) 00084 hash1.update( finalState.toByteArray().left(i > 16 ? 16 : i)); 00085 } 00086 00087 // Clear array bits 00088 finalState.fill( 0 ); 00089 00090 for ( int i = password.size() ; i != 0 ; i = i >> 1 ) 00091 { 00092 if ( ( i & 1 ) != 0 ) 00093 { 00094 hash1.update( finalState.toByteArray().left ( 1 ) ); 00095 } 00096 else 00097 { 00098 hash1.update( password.toByteArray().left ( 1 ) ); 00099 } 00100 } 00101 00102 finalState = hash1.final(); 00103 00104 // Now build a 1000 entry dictionary... 00105 for ( int i = 0 ; i < 1000 ; i++ ) 00106 { 00107 00108 hash2.clear(); 00109 00110 if ((i & 1) != 0) 00111 { 00112 hash2.update ( password ); 00113 } 00114 else 00115 { 00116 hash2.update ( finalState.toByteArray().left( 16 )); 00117 } 00118 00119 if ((i % 3) != 0) 00120 { 00121 hash2.update ( salt ); 00122 } 00123 00124 if ((i % 7) != 0) 00125 { 00126 hash2.update ( password ); 00127 } 00128 00129 if ((i & 1) != 0) 00130 { 00131 hash2.update ( finalState.toByteArray().left( 16 ) ); 00132 } 00133 else 00134 { 00135 hash2.update ( password ); 00136 } 00137 00138 finalState = hash2.final(); 00139 } 00140 00141 // Create an output string 00142 // Salt is part of the encoded password ($1$<string>$) 00143 QString encodedString; 00144 00145 encodedString.append ( magic_string.toByteArray() ); 00146 encodedString.append ( salt.toByteArray() ); 00147 encodedString.append ( "$" ); 00148 00149 long l; 00150 00151 l = ( byte2unsigned (finalState.toByteArray().at(0) ) << 16 | 00152 ( byte2unsigned (finalState.toByteArray().at(6)) ) << 8 | 00153 byte2unsigned (finalState.toByteArray().at(12)) ); 00154 encodedString.append ( to64 (l, 4) ); 00155 00156 l = ( byte2unsigned (finalState.toByteArray().at(1)) << 16 | 00157 ( byte2unsigned (finalState.toByteArray().at(7))) << 8 | 00158 byte2unsigned (finalState.toByteArray().at(13)) ); 00159 encodedString.append ( to64 (l, 4) ); 00160 00161 l = ( byte2unsigned (finalState.toByteArray().at(2)) << 16 | 00162 ( byte2unsigned (finalState.toByteArray().at(8))) << 8 | 00163 byte2unsigned (finalState.toByteArray().at(14)) ); 00164 encodedString.append ( to64 (l, 4) ); 00165 00166 l = ( byte2unsigned (finalState.toByteArray().at(3)) << 16 | 00167 ( byte2unsigned (finalState.toByteArray().at(9))) << 8 | 00168 byte2unsigned (finalState.toByteArray().at(15)) ); 00169 encodedString.append ( to64 (l, 4) ); 00170 00171 l = ( byte2unsigned (finalState.toByteArray().at(4)) << 16 | 00172 ( byte2unsigned (finalState.toByteArray().at(10))) << 8 | 00173 byte2unsigned (finalState.toByteArray().at(5)) ); 00174 encodedString.append ( to64 (l, 4) ); 00175 00176 l = byte2unsigned (finalState.toByteArray().at(11)); 00177 encodedString.append ( to64 (l, 2) ); 00178 00179 return encodedString; 00180 } 00181 00182 int main(int argc, char **argv) 00183 { 00184 00185 // the Initializer object sets things up, and 00186 // also does cleanup when it goes out of scope 00187 QCA::Initializer init; 00188 00189 QCA::SecureArray password, salt; 00190 00191 QCoreApplication app ( argc, argv ); 00192 00193 if ( argc < 3 ) 00194 { 00195 printf ( "Usage: %s password salt (salt without $1$)\n" , argv[0] ); 00196 return 1; 00197 } 00198 00199 password.append( argv[1] ); 00200 00201 salt.append( argv[2] ); 00202 00203 // must always check that an algorithm is supported before using it 00204 if( !QCA::isSupported( "md5" ) ) 00205 printf ("MD5 hash not supported!\n"); 00206 else 00207 { 00208 QString result = qca_md5crypt( password, salt ); 00209 00210 printf ("md5crypt [ %s , %s ] = '%s'\n" , password.data(), salt.data() , qPrintable(result) ); 00211 00212 // this is equivalent if you have GNU libc 2.0 00213 // printf( "GNU md5crypt [ %s , %s ] = '%s'\n", password.data(), salt.data(), crypt( password.data(), ( "$1$"+salt ).data() ) ); 00214 } 00215 00216 return 0; 00217 } 00218 00219 00220 00221