md5crypt.cpp
The code below shows how to calculate an md5crypt based password. This code is compatible with the glibc code.
#include <QtCrypto>
#include <QCoreApplication>
#include <QtDebug>
#include <stdio.h>
QString to64 ( long v , int size )
{
QString itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
QString result;
while ( --size >= 0 )
{
result.append ( itoa64.at ( ( int )( v & 0x3f ) ) );
v = v >> 6;
}
return result;
}
int byte2unsigned ( int byteValue )
{
int integerToReturn;
integerToReturn = (int) byteValue & 0xff;
return integerToReturn;
}
QString qca_md5crypt( const QCA::SecureArray &password, const QCA::SecureArray &salt )
{
QCA::SecureArray finalState, magic_string = "$1$";
QCA::Hash hash1( "md5" );
QCA::Hash hash2( "md5" );
hash1.update ( password );
hash1.update ( magic_string );
hash1.update ( salt );
hash2.update ( password );
hash2.update ( salt );
hash2.update ( password );
finalState = hash2.final();
for ( int i = password.size() ; i > 0 ; i -= 16 )
{
hash1.update( finalState.toByteArray().left(i > 16 ? 16 : i));
}
finalState.fill( 0 );
for ( int i = password.size() ; i != 0 ; i = i >> 1 )
{
if ( ( i & 1 ) != 0 )
{
hash1.update( finalState.toByteArray().left ( 1 ) );
}
else
{
hash1.update( password.toByteArray().left ( 1 ) );
}
}
finalState = hash1.final();
for ( int i = 0 ; i < 1000 ; i++ )
{
hash2.clear();
if ((i & 1) != 0)
{
hash2.update ( password );
}
else
{
hash2.update ( finalState.toByteArray().left( 16 ));
}
if ((i % 3) != 0)
{
hash2.update ( salt );
}
if ((i % 7) != 0)
{
hash2.update ( password );
}
if ((i & 1) != 0)
{
hash2.update ( finalState.toByteArray().left( 16 ) );
}
else
{
hash2.update ( password );
}
finalState = hash2.final();
}
QString encodedString;
encodedString.append ( magic_string.toByteArray() );
encodedString.append ( salt.toByteArray() );
encodedString.append ( "$" );
long l;
l = ( byte2unsigned (finalState.toByteArray().at(0) ) << 16 |
( byte2unsigned (finalState.toByteArray().at(6)) ) << 8 |
byte2unsigned (finalState.toByteArray().at(12)) );
encodedString.append ( to64 (l, 4) );
l = ( byte2unsigned (finalState.toByteArray().at(1)) << 16 |
( byte2unsigned (finalState.toByteArray().at(7))) << 8 |
byte2unsigned (finalState.toByteArray().at(13)) );
encodedString.append ( to64 (l, 4) );
l = ( byte2unsigned (finalState.toByteArray().at(2)) << 16 |
( byte2unsigned (finalState.toByteArray().at(8))) << 8 |
byte2unsigned (finalState.toByteArray().at(14)) );
encodedString.append ( to64 (l, 4) );
l = ( byte2unsigned (finalState.toByteArray().at(3)) << 16 |
( byte2unsigned (finalState.toByteArray().at(9))) << 8 |
byte2unsigned (finalState.toByteArray().at(15)) );
encodedString.append ( to64 (l, 4) );
l = ( byte2unsigned (finalState.toByteArray().at(4)) << 16 |
( byte2unsigned (finalState.toByteArray().at(10))) << 8 |
byte2unsigned (finalState.toByteArray().at(5)) );
encodedString.append ( to64 (l, 4) );
l = byte2unsigned (finalState.toByteArray().at(11));
encodedString.append ( to64 (l, 2) );
return encodedString;
}
int main(int argc, char **argv)
{
QCA::Initializer init;
QCoreApplication app ( argc, argv );
QCA::SecureArray password, salt;
if ( argc < 3 )
{
printf ( "Usage: %s password salt (salt without $1$)\n" , argv[0] );
return 1;
}
password.append( argv[1] );
salt.append( argv[2] );
if( !QCA::isSupported( "md5" ) )
printf ("MD5 hash not supported!\n");
else
{
QString result = qca_md5crypt( password, salt );
printf ("md5crypt [ %s , %s ] = '%s'\n" , password.data(), salt.data() , qPrintable(result) );
}
return 0;
}