md5crypt.cpp

The code below shows how to calculate an md5crypt based password. This code is compatible with the glibc code.

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 

Generated on Fri Jul 6 13:22:42 2007 for Qt Cryptographic Architecture by  doxygen 1.4.6